summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/engine_state_controller.h
blob: 7cf4e057dc24aa5c61557ee58dfc9ae21025fafb (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
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
/*
  Copyright (C) 2014 Waves Audio Ltd.

  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.

*/

#ifndef __gtk2_ardour__engine_state_controller__
#define __gtk2_ardour__engine_state_controller__

#include <vector>
#include <list>

#include "ardour/types.h"
#include "ardour/audio_backend.h"

namespace ARDOUR {

class AudioBackendInfo;

/**
 * @class EngineStateController
 * @brief EngineStateController class.
 *
 * Implements usecases for Audio devices and Audio/Midi ports.
 * Persistantly saves to the config device configuration settings and audio/midi port states
 */
class EngineStateController
{
                                        public:

	// public data types:

	/**
	 * @struct PortState
	 * Structure which represents AudioPort state
	 */
	struct PortState {
		std::string name; ///< Audio Port name
		bool active;      ///< Audio Port state

		PortState ()
			: name("")
			, active(false)
		{
		}

		PortState (const std::string& name)
			: name(name)
			, active(false)
		{
		}

		bool operator==(const PortState& rhs) {return rhs.name == name; }

	};

	/// @typedef Type for the list of all available audio ports
	typedef std::list<PortState> PortStateList;

	/**
	 * @struct MidiPortState
	 * Structure which represents MidiPort state.
	 */
	struct MidiPortState
	{
		std::string name;     ///< Midi Port name
		bool active;          ///< Midi Port state
		bool available;       ///< Midi Port availability - if it is physicaly available or not
		bool scene_connected; ///< Is midi port used for scene MIDI marker in/out
		bool mtc_in;          ///< Is midi port used as MTC in

		MidiPortState(const std::string& name)
			: name(name)
			, active(false)
			, available(false)
			, scene_connected(false)
			, mtc_in(false)
		{}

		bool operator==(const MidiPortState& rhs)
		{
			return name == rhs.name;
		}
	};

	/// @typedef Type for the list of MidiPorts ever registered in the system
	typedef std::list<MidiPortState> MidiPortStateList;


	//Interfaces

	/** Get an instance of EngineStateController singleton.
	 * @return EngineStateController instance pointer
	 */
	static EngineStateController* instance ();

	/** Associate session with EngineStateController instance.
	 */
	void set_session (Session* session);

	/** Remove link to the associated session.
	 */
	void remove_session ();

	//////////////////////////////////////////////////////////////////////////////////////////////////////////
	// General backend/device information methods

	/** Provides names of all available backends.
	 *
	 * @param[out] available_backends - vector of available backends
	 */
	void available_backends (std::vector<const AudioBackendInfo*>& available_backends);

	/** Provides the name of currently used backend.
	 *
	 * @return the name of currently used backend
	 */
	const std::string& get_current_backend_name() const;

	/** Provides the name of currently used device.
	 *
	 * @return the name of currently used device
	 */
	const std::string& get_current_device_name () const;

	/** Provides names for all available devices.
	 *
	 * @param[out] device_vector - vector of available devices
	 */
	void enumerate_devices (std::vector<ARDOUR::AudioBackend::DeviceStatus>& device_vector) const;

	/** Get sample rate used by current device.
	 *
	 * @return current sample rate
	 */
	ARDOUR::framecnt_t get_current_sample_rate () const;

	/** Get default sample rate for current backend.
	 *
	 * @return default sample rate for current backend
	 */
	ARDOUR::framecnt_t get_default_sample_rate () const;

	/** Get sample rates which are supported by current device and current backend.
	 *
	 * @param[out] sample_rates - vector of supported sample rates
	 */
	void available_sample_rates_for_current_device (std::vector<float>& sample_rates) const;

	/** Get buffer size used by current device.
	 *
	 * @return current buffer size
	 */
	ARDOUR::pframes_t get_current_buffer_size () const;

	/** Get default buffer size for current backend.
	 *
	 * @return default buffer size for current backend
	 */
	ARDOUR::pframes_t get_default_buffer_size () const;

	/** Get buffer sizes which are supported by current device and current backend.
	 *
	 * @param[out] buffer_sizes - vector of supported buffer_sizes
	 */
	void available_buffer_sizes_for_current_device (std::vector<ARDOUR::pframes_t>& buffer_sizes) const;

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// device state control methods

	/** Get the number of all enabled Audio inputs.
	 *
	 * @return number of all enabled Audio inputs
	 */
	uint32_t            get_available_inputs_count() const;
	/** Get the number of all enabled Audio outputs.
	 *
	 * @return number of all enabled Audio outputs
	 */
	uint32_t            get_available_outputs_count () const;

	/** Get vector of all enabled physical Audio input port names.
	 *
	 * @param[out] port_names - vector of all enabled Audio input names
	 */
	void                get_physical_audio_inputs (std::vector<std::string>& port_names);
	/** Get vector of all enabled physical Audio input port names.
	 *
	 * @param[out] port_names - vector of all enabled Audio input names
	 */
	void                get_physical_audio_outputs (std::vector<std::string>& port_names);

	/** Get vector of all enabled physical MIDI input port names.
	 *
	 * @param[out] port_names - vector of all enabled MIDI input names
	 */
	void                get_physical_midi_inputs (std::vector<std::string>& port_names);
	/** Get vector of all enabled physical MIDI output port names.
	 *
	 * @param[out] port_names - vector of all enabled MIDI output names
	 */
	void                get_physical_midi_outputs (std::vector<std::string>& port_names);

	/** Sets new state to all Audio inputs.
	 *
	 * @param[in] state - new state
	 */
	void                set_state_to_all_inputs(bool state);
	/** Sets new state to all Audio outputs.
	 * @note Does nothing in Stereo Out mode
	 * @param[in] state - new state
	 */
	void                set_state_to_all_outputs(bool state);

	/** Get vector of states for all physical Audio input ports.
	 *
	 * @param[out] channel_states - vector of input port states
	 */
	void                get_physical_audio_input_states(std::vector<PortState>& channel_states);
	/** Get vector of states for all physical Audio output ports.
	 *
	 * @param[out] channel_states - vector of output port states
	 */
	void                get_physical_audio_output_states(std::vector<PortState>& channel_states);

	/** Set state of the specified Audio input port.
	 *
	 * @param[in] port_name - input name
	 * @param[in] state - new state
	 */
	void                set_physical_audio_input_state(const std::string& port_name, bool state);
	/** Set state of the specified Audio output port.
	 *
	 * @param[in] port_name - output name
	 * @param[in] state - new state
	 */
	void                set_physical_audio_output_state(const std::string& port_name, bool state);

	/** Get state of the specified Audio input port.
	 *
	 * @param[in] port_name - input name
	 * @return input state
	 */
	bool                get_physical_audio_input_state(const std::string& port_name);
	/** Get state of the specified Audi output port.
	 *
	 * @param[in] port_name - output name
	 * @return output state
	 */
	bool                get_physical_audio_output_state(const std::string& port_name);


	/** Get vector of all enabled MIDI input port names.
	 *
	 * @param[out] channel_states - vector of enabled inputs
	 */
	void                get_physical_midi_input_states (std::vector<MidiPortState>& channel_states);
	/** Get vector of all enabled MIDI output port names.
	 *
	 * @param[out] channel_states - vector of enabled outputs
	 */
	void                get_physical_midi_output_states (std::vector<MidiPortState>& channel_states);

	/** Get name of mtc source port
	 *
	 * return name of mtc source port
	 */
	std::string          get_mtc_source_port ();

	/** Set ltc source port
	 *
	 * @param[in] port - name of ltc source port
	 */
	void                set_ltc_source_port (const std::string& port);
	/** Get name of ltc source port
	 *
	 * return name of ltc source port
	 */
	std::string          get_ltc_source_port ();

	/** Set ltc output port
	 *
	 * @param[in] port - name of ltc output port
	 */
	void                set_ltc_output_port (const std::string&);
	/** Get name of ltc output port
	 *
	 * return name of ltc output port
	 */
	std::string         get_ltc_output_port ();

	/** Set state of the specified MIDI input port.
	 *
	 * @param[in] port_name - input name
	 * @param[in] state - new state
	 */
	void                set_physical_midi_input_state(const std::string& port_name, bool state);
	/** Set state of the specified MIDI output port.
	 *
	 * @param[in] port_name - output name
	 * @param[in] state - new state
	 */
	void                set_physical_midi_output_state(const std::string& port_name, bool state);
	/** Get state of the specified MIDI input port.
	 *
	 * @param[in] port_name - input name
	 * @param[out] scene_connected - is port used as Scene In or not
	 * @return input state
	 */
	bool                get_physical_midi_input_state(const std::string& port_name, bool& scene_connected);
	/** Get state of the specified MIDI output port.
	 *
	 * @param[in] port_name - output name
	 * @param[out] scene_connected - is port used as Scene Out or not
	 * @return output state
	 */
	bool                get_physical_midi_output_state(const std::string& port_name, bool& scene_connected);

	/** Set state of Scene In connection for the specified MIDI input port.
	 *
	 * @param[in] port_name - input name
	 * @param[in] state - new state
	 */
	void                set_physical_midi_scene_in_connection_state(const std::string& port_name, bool state);
	/** Set state of Scene Out connection for the specified MIDI output port.
	 *
	 * @param[in] port_name - input name
	 * @param[in] state - new state
	 */
	void                set_physical_midi_scenen_out_connection_state(const std::string&, bool);

	/** Disocnnect all MIDI input ports from Scene In.
	 */
	void                set_all_midi_scene_inputs_disconnected();
	/** Disocnnect all MIDI output ports from Scene Out.
	 */
	void                set_all_midi_scene_outputs_disconnected();

	/** Set MIDI TimeCode input port
	 * @note There is a sense to choose MIDI TimeCode input only because
	 * our MIDI TimeCode is propagated to all midi output ports.
	 */
	void                set_mtc_source_port (const std::string&);

	/** Check if AudioEngine setup is required
	 * @return true if setup is required, otherwise - false
	 */
	bool                is_setup_required() const {return ARDOUR::AudioEngine::instance()->setup_required (); }

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Methods set parameters inside the controller
	// the state of engine won't change untill we make a "push" of this state to the backend
	// NOTE: Use push_state_to_backend() method to update backend with the most recent controller state

	/** Set new sample rate for current device in EngineStateController database
	 * @note Use push_state_to_backend() method to update backend/device state with the most recent controller state
	 * @param sample_rate - new sample rate
	 */
	bool        set_new_sample_rate_in_controller(framecnt_t sample_rate);
	/** Set new buffer size for current device in EngineStateController database
	 * @note Use push_state_to_backend() method to update backend/device state with the most recent controller state
	 * @param buffer_size - new buffer size
	 */
	bool        set_new_buffer_size_in_controller(pframes_t buffer_size);

	/** @brief push current controller state to backend.
	 * Propagate and set all current EngineStateController parameters to the backend
	 * @note Engine will be restarted if it's running when this method is called.
	 * @note If an attempt ot set parameters is unsuccessful current device will be switched to "None".
	 * @param start - start the Engine if it was not running when this function was called.
	 * @return true on success, otherwise - false
	 */
	bool        push_current_state_to_backend(bool start);
	/** Switch to new backend
	 * @note The change will be propagated emmidiatelly as if push_current_state_to_backend () was called.
	 * @param backend_name - new backend name.
	 * @return true on success, otherwise - false
	 */
	bool        set_new_backend_as_current(const std::string& backend_name);
	/** Switch to new device
	 * @note The change will be propagated emmidiatelly as if push_current_state_to_backend () was called.
	 * @param device_name - new device name.
	 * @return true on success, otherwise - false
	 */
	bool        set_new_device_as_current(const std::string& device_name);


	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Methods to save/serialize setting states

	/** Serialize Audio/Midi settings (entire EngineStateController database) to XML
	 * @return XML note with serialized states
	 */
	XMLNode&    serialize_audio_midi_settings();
	/** Save Audio/Midi settings (entire EngineStateController database) to config persistently
	 */
	void        save_audio_midi_settings();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	//UPDATE SIGNALS
	/** This signal is emitted if the sample rate changes */
	PBD::Signal0<void> SampleRateChanged;
	/** This signal is emitted if the buffer size changes */
	PBD::Signal0<void> BufferSizeChanged;
	/** This signal is emitted if the device list changes */
	PBD::Signal1<void, bool> DeviceListChanged;
	/** This signal is emitted if the device cannot operate properly */
	PBD::Signal0<void> DeviceError;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	//ENGINE STATE SIGNALS
	/** This signal is emitted when the engine is started */
	PBD::Signal0<void> EngineRunning;
	/** This signal is emitted when the engine is stopped */
	PBD::Signal0<void> EngineStopped;
	/** This signal is emitted if Engine processing is terminated */
	PBD::Signal0<void> EngineHalted;

	/** This signal is emitted if the AUDIO input channel configuration changes */
	PBD::Signal0<void> InputConfigChanged;
	/** This signal is emitted if the AUDIO output channel configuration changes */
	PBD::Signal0<void> OutputConfigChanged;
	/** This signal is emitted if the AUDIO output connection mode changes
	 * @note By output connection mode "Stereo Out" or "Multi Out" is meant
	 */
	PBD::Signal0<void> OutputConnectionModeChanged;

	/** This signals is emitted if the MIDI input channel configuration changes */
	PBD::Signal0<void> MIDIInputConfigChanged;
	/** This signals is emitted if the MIDI output channel configuration changes */
	PBD::Signal0<void> MIDIOutputConfigChanged;
	/** This signals is emitted if the MIDI Scene In connection changes */
	PBD::Signal2<void, const std::vector<std::string>&, bool> MIDISceneInputConnectionChanged;
	/** This signals is emitted if the MIDI Scene Out connection changes */
	PBD::Signal2<void, const std::vector<std::string>&, bool> MIDISceneOutputConnectionChanged;

	/** This signal is emitted if the MTC Input channel is changed */
	PBD::Signal1<void, const std::string&> MTCInputChanged;

	/** This signal is emitted if new Audio/MIDI ports are registered or unregistered */
	PBD::Signal0<void> PortRegistrationChanged;

                                        private:

	EngineStateController(); /// singleton
	~EngineStateController(); /// singleton
	EngineStateController(const EngineStateController& ); /// prohibited
	EngineStateController& operator=(const EngineStateController&); /// prohibited

	////////////////////////////////////////////////////////////////////////////////////////////
	// private data structures

	/** @struct Engine state
	 * @brief State structure.
	 * Contains information about single device/backend state
	 */
	struct State {
		std::string backend_name; ///< state backend name
		std::string device_name; ///< state device name
		ARDOUR::framecnt_t sample_rate; ///< sample rate used by the device in this state
		ARDOUR::pframes_t buffer_size; ///< buffer size used by the device in this state

		PortStateList input_channel_states; ///< states of device Audio inputs
		PortStateList multi_out_channel_states; ///< states of device Audio inputs in Multi Out mode
		PortStateList stereo_out_channel_states; ///< states of device Audio inputs in Stereo Out mode
		bool active; ///< was this state the most recent active one

		State()
			: sample_rate(0)
			, buffer_size(0)
			, input_channel_states (0)
			, multi_out_channel_states (0)
			, stereo_out_channel_states (0)
			, active (false)
		{
		}

		bool operator==(const State& rhs)
		{
			return (backend_name == rhs.backend_name) && (device_name == rhs.device_name);
		}

		/** Forms string name for the state
		 * @return name string
		 */
		std::string form_state_name() {
			return std::string("State:" + backend_name + ":" + device_name);
		}

		/** @struct StatepPredicate
		 * This predicate is used to identify a state during search in the list of states
		 */
		struct StatePredicate
		{
			StatePredicate(const std::string& backend_name, const std::string& device_name)
				: _backend_name (backend_name)
				, _device_name (device_name)
			{}

			bool operator()(boost::shared_ptr<ARDOUR::EngineStateController::State> rhs)
			{
				return (_backend_name == rhs->backend_name) && (_device_name == rhs->device_name);
			}

		                                        private:
			std::string _backend_name;
			std::string _device_name;
		};
	};

	/// @typedef Type for the state pointer
	typedef boost::shared_ptr<State> StatePtr;
	/// @typedef Type for the list of states
	typedef std::list<StatePtr> StateList;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// methods to manage setting states

	/** Deserializes and loads Engine and Audio port states from the config to EngineStateController
	 */
	void _deserialize_and_load_engine_states();
	/** Deserializes and loads MIDI port states from the config to EngineStateController
	 */
	void _deserialize_and_load_midi_port_states();
	/** Serializes Engine and Audio port states from EngineStateController to XML node
	 * @param[in,out] audio_midi_settings_node - node to serialize the satets to
	 */
	void _serialize_engine_states(XMLNode* audio_midi_settings_node);
	/** Serializes MIDI port states from EngineStateController to XML node
	 * @param[in,out] audio_midi_settings_node - node to serialize the satets to
	 */
	void _serialize_midi_port_states(XMLNode* audio_midi_settings_node);

	/** Provides initial state configuration.
	 * It loades the last active state if there is one and it is aplicable.
	 * Otherwise default state (None device with default sample rate and buffer size) is loaded.
	 */
	void _do_initial_engine_setup();

	/** Loades provided state.
	 * @note It's possible that provided state can't be loaded
	 * (device disconnected or reqested parameters are not supported anymore).
	 * @param state - state to apply
	 * @return true on success, otherwise - false
	 */
	bool _apply_state(const StatePtr& state);

	/** Gets available device channels from engine and updates internal controller state
	 */
	void _update_device_channels_state();

	/** Check "Stereo Out" mode channels state configuration and make it correspond Stereo Out mode requirements
	 */
	void _refresh_stereo_out_channel_states();

	////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// internal helper functions
	/** make sure that current device parameters are supported and fit session requirements
	 * @return true if current state is valid and all parameters are supported, otherwise - false
	 */
	bool _validate_current_device_state();

	/** change ltc source port in case of the input ports list change
	 */
	void _update_ltc_source_port ();
	/** change ltc source port in case of the output ports list change
	 */
	void _update_ltc_output_port ();

	/** check that port is still existed in the list of input ports
	    @param[in] port - port name
	    @return true if current port is existed, otherwise - false
	*/
	bool _audio_input_port_exists (const std::string& port);
	/** check that port is still existed in the list of output ports
	    @param[in] port - port name
	    @return true if current port is existed, otherwise - false
	*/
	bool _audio_output_port_exists (const std::string& port);



	////////////////////////////////////////
	// callbacks
	/** Invoked when Engine starts running
	 */
	void _on_engine_running();
	/** Invoked when Engine is halted
	 */
	void _on_engine_halted();
	/** Invoked when Engine processing is terminated
	 */
	void _on_engine_stopped();
	/** Invoked when Device error accured, it failed to start or didn't accept the change which should
	 */
	void _on_device_error();
	/** Invoked when current device changes sample rate
	 */
	void _on_sample_rate_change(ARDOUR::framecnt_t);
	/** Invoked when current device changes buffer size
	 */
	void _on_buffer_size_change(ARDOUR::pframes_t);
	/** Invoked when the list of available devices is changed
	 */
	void _on_device_list_change();
	/** Invoked when the config parameter is changed
	 */
	void _on_parameter_changed (const std::string&);
	/** Invoked when Audio/MIDI ports are registered or unregistered
	 */
	void _on_ports_registration_update ();
	/** Invoked when session loading process is complete
	 */
	void _on_session_loaded();
	////////////////////////////////////////

	////////////////////////////////////////
	// attributes
	StatePtr _current_state; ///< current state pointer
	// list of system states
	StateList _states; ///< list of all available states

	MidiPortStateList _midi_inputs; ///< midi input states
	MidiPortStateList _midi_outputs; ///< midi output states

	std::string _last_used_real_device; ///< last active non-default (real) device

	Session* _session; ///< current session

	// Engine connections stuff
	PBD::ScopedConnectionList update_connections; ///< connection container for update signals
	PBD::ScopedConnectionList session_connections; ///< connection container for session signals
	PBD::ScopedConnection running_connection; ///< connection container for EngineRunning signal
	PBD::ScopedConnection halt_connection; ///< connection container for EngineHalted signal
	PBD::ScopedConnection stopped_connection; ///< connection container for EngineStopped signal
};

} // namespace ARDOUR

#endif /* defined(__gtk2_ardour__engine_state_controller__) */