summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/audio_backend.h
blob: 4d6d6a6dd8d40d4acc4bd48c3bd6cee08dad6268 (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
/*
    Copyright (C) 2013 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 __libardour_audiobackend_h__
#define __libardour_audiobackend_h__

#include <string>
#include <vector>

#include <stdint.h>
#include <stdlib.h>

#include <boost/function.hpp>

#include "ardour/types.h"

namespace ARDOUR {

class AudioEngine;

class AudioBackend {
  public:

    AudioBackend (AudioEngine& e) : engine (e){}
    virtual ~AudioBackend () {}

    /** Return the name of this backend.
     *
     * Should use a well-known, unique term. Expected examples
     * might include "JACK", "CoreAudio", "ASIO" etc.
     */
    virtual std::string name() const = 0;

    virtual void* private_handle() const = 0;

    /** return true if the underlying mechanism/API is still available
     * for us to utilize. return false if some or all of the AudioBackend
     * API can no longer be effectively used.
     */
    virtual bool connected() const = 0;

    /** return true if the callback from the underlying mechanism/API
     * (CoreAudio, JACK, ASIO etc.) occurs in a thread subject to realtime
     * constraints. Return false otherwise.
    */
    virtual bool is_realtime () const = 0;

    /* Discovering devices and parameters */

    /** Returns a collection of strings identifying devices known
     * to this backend. Any of these strings may be used to identify a
     * device in other calls to the backend, though any of them may become
     * invalid at any time.
     */
    virtual std::vector<std::string> enumerate_devices () const = 0;
    /** Returns a collection of float identifying sample rates that are
     * potentially usable with the hardware identified by @param device.
     * Any of these values may be supplied in other calls to this backend
     * as the desired sample rate to use with the name device, but the
     * requested sample rate may turn out to be unavailable, or become invalid
     * at any time.
     */
    virtual std::vector<float> available_sample_rates (const std::string& device) const = 0;
    /** Returns a collection of uint32 identifying buffer sizes that are
     * potentially usable with the hardware identified by @param device.
     * Any of these values may be supplied in other calls to this backend
     * as the desired buffer size to use with the name device, but the
     * requested buffer size may turn out to be unavailable, or become invalid
     * at any time.
     */
    virtual std::vector<uint32_t> available_buffer_sizes (const std::string& device) const = 0;

    /** Returns the maximum number of input channels that are potentially
     * usable with the hardware identified by @param device.  Any number from 1
     * to the value returned may be supplied in other calls to this backend as
     * the input channel count to use with the name device, but the requested
     * count may turn out to be unavailable, or become invalid at any time.
     */
    virtual uint32_t available_input_channel_count (const std::string& device) const = 0;

    /** Returns the maximum number of output channels that are potentially
     * usable with the hardware identified by @param device.  Any number from 1
     * to the value returned may be supplied in other calls to this backend as
     * the output channel count to use with the name device, but the requested
     * count may turn out to be unavailable, or become invalid at any time.
     */
    virtual uint32_t available_output_channel_count (const std::string& device) const = 0;

    /* Set the hardware parameters.
     * 
     * If called when the current state is stopped or paused,
     * the changes will not take effect until the state changes to running.
     *
     * If called while running, the state will change as fast as the
     * implementation allows.
     *
     * All set_*() methods return zero on success, non-zero otherwise.
     */

    /** Set the name of the device to be used
     */
    virtual int set_device_name (const std::string&) = 0;
    /** Set the sample rate to be used
     */
    virtual int set_sample_rate (float) = 0;
    /** Set the buffer size to be used.
     *
     * The device is assumed to use a double buffering scheme, so that one
     * buffer's worth of data can be processed by hardware while software works
     * on the other buffer. All known suitable audio APIs support this model
     * (though ALSA allows for alternate numbers of buffers, and CoreAudio
     * doesn't directly expose the concept).
     */
    virtual int set_buffer_size (uint32_t) = 0;
    /** Set the preferred underlying hardware sample format
     *
     * This does not change the sample format (32 bit float) read and
     * written to the device via the Port API.
     */
    virtual int set_sample_format (SampleFormat) = 0;
    /** Set the preferred underlying hardware data layout.
     * If @param yn is true, then the hardware will interleave
     * samples for successive channels; otherwise, the hardware will store
     * samples for a single channel contiguously.
     * 
     * Setting this does not change the fact that all data streams
     * to and from Ports are mono (essentially, non-interleaved)
     */
    virtual int set_interleaved (bool yn) = 0;
    /** Set the number of input channels that should be used
     */
    virtual int set_input_channels (uint32_t) = 0;
    /** Set the number of output channels that should be used
     */
    virtual int set_output_channels (uint32_t) = 0;
    /** Set the (additional) input latency that cannot be determined via 
     * the implementation's underlying code (e.g. latency from
     * external D-A/D-A converters. Units are samples.
     */
    virtual int set_systemic_input_latency (uint32_t) = 0;
    /** Set the (additional) output latency that cannot be determined via 
     * the implementation's underlying code (e.g. latency from
     * external D-A/D-A converters. Units are samples.
     */
    virtual int set_systemic_output_latency (uint32_t) = 0;

    virtual std::string  device_name () const = 0;
    virtual float        sample_rate () const = 0;
    virtual uint32_t     buffer_size () const = 0;
    virtual SampleFormat sample_format () const = 0;
    virtual bool         interleaved () const = 0;
    virtual uint32_t     input_channels () const = 0;
    virtual uint32_t     output_channels () const = 0;
    virtual uint32_t     systemic_input_latency () const = 0;
    virtual uint32_t     systemic_output_latency () const = 0;

    /* Basic state control */

    /** Start using the device named in the most recent call
     * to set_device(), with the parameters set by various
     * the most recent calls to set_sample_rate() etc. etc.
     * 
     * At some undetermined time after this function is successfully called,
     * the backend will start calling the ::process_callback() method of
     * the AudioEngine referenced by @param engine. These calls will
     * occur in a thread created by and/or under the control of the backend.
     *
     * Return zero if successful, negative values otherwise.
     */
    virtual int start () = 0;

    /** Stop using the device currently in use. 
     *
     * If the function is successfully called, no subsequent calls to the
     * process_callback() of @param engine will be made after the function
     * returns, until parameters are reset and start() are called again.
     * 
     * The backend is considered to be un-configured after a successful
     * return, and requires calls to set hardware parameters before it can be
     * start()-ed again. See pause() for a way to avoid this. stop() should
     * only be used when reconfiguration is required OR when there are no 
     * plans to use the backend in the future with a reconfiguration.
     *
     * Return zero if successful, 1 if the device is not in use, negative values on error
     */
    virtual int stop () = 0;

    /** Temporarily cease using the device named in the most recent call to set_parameters().
     *
     * If the function is successfully called, no subsequent calls to the
     * process_callback() of @param engine will be made after the function
     * returns, until start() is called again.
     * 
     * The backend will retain its existing parameter configuration after a successful
     * return, and does NOT require any calls to set hardware parameters before it can be
     * start()-ed again. 
     *
     * Return zero if successful, 1 if the device is not in use, negative values on error
     */
    virtual int pause () = 0;

    /** While remaining connected to the device, and without changing its
     * configuration, start (or stop) calling the process_callback() of @param engine
     * without waiting for the device. Once process_callback() has returned, it
     * will be called again immediately, thus allowing for faster-than-realtime
     * processing.
     *
     * All registered ports remain in existence and all connections remain
     * unaltered. However, any physical ports should NOT be used by the
     * process_callback() during freewheeling - the data behaviour is undefined.
     *
     * If @param start_stop is true, begin this behaviour; otherwise cease this
     * behaviour if it currently occuring, and return to calling
     * process_callback() of @param engine by waiting for the device.
     *
     * Return zero on success, non-zero otherwise.
     */
    virtual int freewheel (bool start_stop) = 0;

    /** return the fraction of the time represented by the current buffer
     * size that is being used for each buffer process cycle, as a value
     * from 0.0 to 1.0
     *
     * E.g. if the buffer size represents 5msec and current processing
     * takes 1msec, the returned value should be 0.2. 
     * 
     * Implementations can feel free to smooth the values returned over
     * time (e.g. high pass filtering, or its equivalent).
     */
    virtual float cpu_load() const  = 0;

    /* Transport Control (JACK is the only audio API that currently offers
       the concept of shared transport control)
    */
    
    /** Attempt to change the transport state to TransportRolling. 
     */
    virtual void transport_start () {}
    /** Attempt to change the transport state to TransportStopped. 
     */
    virtual void transport_stop () {}
    /** return the current transport state
     */
    virtual TransportState transport_state () const { return TransportStopped; }
    /** Attempt to locate the transport to @param pos
     */
    virtual void transport_locate (framepos_t /*pos*/) {}
    /** Return the current transport location, in samples measured
     * from the origin (defined by the transport time master)
     */
    virtual framepos_t transport_frame() const { return 0; }

    /** If @param yn is true, become the time master for any inter-application transport
     * timebase, otherwise cease to be the time master for the same.
     *
     * Return zero on success, non-zero otherwise
     * 
     * JACK is the only currently known audio API with the concept of a shared
     * transport timebase.
     */
    virtual int set_time_master (bool /*yn*/) { return 0; }

    virtual int        usecs_per_cycle () const { return 1000000 * (buffer_size() / sample_rate()); }
    virtual size_t     raw_buffer_size (DataType t);
    
    /* Process time */
    
    /** return the time according to the sample clock in use, measured in
     * samples since an arbitrary zero time in the past. The value should
     * increase monotonically and linearly, without interruption from any
     * source (including CPU frequency scaling).
     *
     * It is extremely likely that any implementation will use a DLL, since
     * this function can be called from any thread, at any time, and must be 
     * able to accurately determine the correct sample time.
     */
    virtual pframes_t sample_time () = 0;

    /** return the time according to the sample clock in use when the current 
     * buffer process cycle began. 
     * 
     * Can ONLY be called from within a process() callback tree (which
     * implies that it can only be called by a process thread)
     */
    virtual pframes_t sample_time_at_cycle_start () = 0;

    /** return the time since the current buffer process cycle started,
     * in samples, according to the sample clock in use.
     * 
     * Can ONLY be called from within a process() callback tree (which
     * implies that it can only be called by a process thread)
     */
    virtual pframes_t samples_since_cycle_start () = 0;

    /** return true if it possible to determine the offset in samples of the
     * first video frame that starts within the current buffer process cycle,
     * measured from the first sample of the cycle. If returning true,
     * set @param offset to that offset.
     *
     * Eg. if it can be determined that the first video frame within the cycle
     * starts 28 samples after the first sample of the cycle, then this method
     * should return true and set @param offset to 28.
     *
     * May be impossible to support outside of JACK, which has specific support
     * (in some cases, hardware support) for this feature.
     *
     * Can ONLY be called from within a process() callback tree (which implies
     * that it can only be called by a process thread)
     */
    virtual bool get_sync_offset (pframes_t& /*offset*/) const { return false; }

    /** Create a new thread suitable for running part of the buffer process
     * cycle (i.e. Realtime scheduling, memory allocation, etc. etc are all
     * correctly setup), with a stack size given in bytes by specified @param
     * stacksize. The thread will begin executing @param func, and will exit
     * when that function returns.
     */
    virtual int create_process_thread (boost::function<void()> func, pthread_t*, size_t stacksize) = 0;
    
  protected:
    AudioEngine&          engine;
};

}

#endif /* __libardour_audiobackend_h__ */