summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/audioengine.h
blob: 7f04aa05be43e1c938071cc7cfb7c33dbe767989 (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
/*
    Copyright (C) 2002-2004 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.

*/

#ifndef __ardour_audioengine_h__
#define __ardour_audioengine_h__

#ifdef WAF_BUILD
#include "libardour-config.h"
#endif

#include <iostream>
#include <list>
#include <set>
#include <cmath>
#include <exception>
#include <string>

#include <glibmm/threads.h>

#include "pbd/rcu.h"
#include "pbd/signals.h"
#include "pbd/stacktrace.h"

#include <jack/weakjack.h>
#include <jack/jack.h>
#include <jack/transport.h>
#include <jack/thread.h>

#include "ardour/ardour.h"

#include "ardour/data_type.h"
#include "ardour/session_handle.h"
#include "ardour/types.h"
#include "ardour/chan_count.h"

#ifdef HAVE_JACK_SESSION
#include <jack/session.h>
#endif

namespace ARDOUR {

class InternalPort;
class MidiPort;
class Port;
class Session;
class ProcessThread;

class AudioEngine : public SessionHandlePtr
{
public:
	typedef std::map<std::string,boost::shared_ptr<Port> > Ports;

	AudioEngine (std::string client_name, std::string session_uuid);
	virtual ~AudioEngine ();

        static int discover_backends();
        std::vector<std::string> available_backends() const;

	ProcessThread* main_thread() const { return _main_thread; }

	std::string client_name() const { return jack_client_name; }

	int stop (bool forever = false);
	int start ();
        int pause ();
        int freewheel (bool);
    
	bool running() const { return _running; }

	Glib::Threads::Mutex& process_lock() { return _process_lock; }

	framecnt_t frame_rate () const;
	pframes_t frames_per_cycle () const;

	size_t raw_buffer_size(DataType t);

	int usecs_per_cycle () const { return _usecs_per_cycle; }

	bool get_sync_offset (pframes_t & offset) const;

	pframes_t frames_since_cycle_start () {
  	        jack_client_t* _priv_jack = _jack;
		if (!_running || !_priv_jack) {
			return 0;
		}
		return jack_frames_since_cycle_start (_priv_jack);
	}

	pframes_t frame_time () {
  	        jack_client_t* _priv_jack = _jack;
		if (!_running || !_priv_jack) {
			return 0;
		}
		return jack_frame_time (_priv_jack);
	}

	pframes_t frame_time_at_cycle_start () {
  	        jack_client_t* _priv_jack = _jack;
		if (!_running || !_priv_jack) {
			return 0;
		}
		return jack_last_frame_time (_priv_jack);
	}

	int request_buffer_size (pframes_t);

	framecnt_t processed_frames() const { return _processed_frames; }

	float get_cpu_load() {
  	        jack_client_t* _priv_jack = _jack;
		if (!_running || !_priv_jack) {
			return 0;
		}
		return jack_cpu_load (_priv_jack);
	}

	void set_session (Session *);
	void remove_session (); // not a replacement for SessionHandle::session_going_away()

	class NoBackendAvailable : public std::exception {
	public:
		virtual const char *what() const throw() { return "could not connect to engine backend"; }
	};

	void split_cycle (pframes_t offset);

	int  reset_timebase ();

        void update_latencies ();

	/* start/stop freewheeling */

	int freewheel (bool onoff);
	bool freewheeling() const { return _freewheeling; }

	/* this signal is sent for every process() cycle while freewheeling.
_	   the regular process() call to session->process() is not made.
	*/

	PBD::Signal1<int, pframes_t> Freewheel;

	PBD::Signal0<void> Xrun;

	/* this signal is if JACK notifies us of a graph order event */

	PBD::Signal0<void> GraphReordered;

#ifdef HAVE_JACK_SESSION
	PBD::Signal1<void,jack_session_event_t *> JackSessionEvent;
#endif


	/* this signal is emitted if the sample rate changes */

	PBD::Signal1<void, framecnt_t> SampleRateChanged;

	/* this signal is sent if JACK ever disconnects us */

	PBD::Signal1<void,const char*> Halted;

	/* these two are emitted when the engine itself is
	   started and stopped
	*/

	PBD::Signal0<void> Running;
	PBD::Signal0<void> Stopped;

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

	/** Emitted if a JACK 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;

	std::string make_port_name_relative (std::string) const;
	std::string make_port_name_non_relative (std::string) const;
	bool port_is_mine (const std::string&) const;

	static AudioEngine* instance() { return _instance; }
	static void destroy();
	void died ();

	int create_process_thread (boost::function<void()>, pthread_t*, size_t stacksize);

private:
	static AudioEngine*       _instance;

	Glib::Threads::Mutex      _process_lock;
        Glib::Threads::Cond        session_removed;
	bool                       session_remove_pending;
        frameoffset_t              session_removal_countdown;
        gain_t                     session_removal_gain;
        gain_t                     session_removal_gain_step;
	bool                      _running;
	bool                      _has_run;
	mutable framecnt_t        _buffer_size;
	std::map<DataType,size_t> _raw_buffer_sizes;
	mutable framecnt_t        _frame_rate;
	/// number of frames between each check for changes in monitor input
	framecnt_t                 monitor_check_interval;
	/// time of the last monitor check in frames
	framecnt_t                 last_monitor_check;
	/// the number of frames processed since start() was called
	framecnt_t                _processed_frames;
	bool                      _freewheeling;
	bool                      _pre_freewheel_mmc_enabled;
	int                       _usecs_per_cycle;
	bool                       port_remove_in_progress;
        Glib::Threads::Thread*     m_meter_thread;
	ProcessThread*            _main_thread;


	SerializedRCUManager<Ports> ports;

	boost::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input);

	int    process_callback (pframes_t nframes);
	void*  process_thread ();
	void   remove_all_ports ();

	void port_registration_failure (const std::string& portname);

	void meter_thread ();
	void start_metering_thread ();
	void stop_metering_thread ();

	static gint      m_meter_exit;

        void parameter_changed (const std::string&);
        PBD::ScopedConnection config_connection;
};

} // namespace ARDOUR

#endif /* __ardour_audioengine_h__ */