~ubuntu-branches/ubuntu/maverick/ultrastar-ng/maverick

« back to all changes in this revision

Viewing changes to audio/alsa/alsa.hpp

  • Committer: Bazaar Package Importer
  • Author(s): Miriam Ruiz, Miriam Ruiz, Mario Bonino, Jon Dowland, Ansgar Burchardt
  • Date: 2008-06-07 16:43:18 UTC
  • mfrom: (1.1.2 upstream)
  • mto: This revision was merged to the branch mainline in revision 6.
  • Revision ID: james.westby@ubuntu.com-20080607164318-spq0cnpt8mjhg1pj
[ Miriam Ruiz ]
* New Upstream Release (Closes: #453132)
* Removed unneeded patches
* Added packages to build deps:
  + libtool
  + portaudio19-dev | portaudio-dev
  + libboost-dev, libboost-thread-dev, libboost-serialization-dev
  + libboost-program-options-dev, libboost-regex-dev
* Moved shared objects to private directory: /usr/lib/ultraster-ng
* Added rpath to binaries to search for shared objects in the private dir
* Uses ultrastar-ng-gstreamer as default, instead of ultrastar-ng-xine,
  since there are significantly less issues with GStreamer.
* Added patch to fix upstream desktop file
* Added -Wl,-as-needed to LDFLAGS
* Replaced fftw3-dev by libfftw3-dev in build dependencies.
* Standards-Version upgraded to 3.7.3

[ Mario Bonino ]
* Fixed data/Makefile.am to install .desktop file and icon

[ Jon Dowland ]
* add Homepage: control field to source stanza
* fix a bashism in debian/rules (Closes: #478634)

[ Ansgar Burchardt ]
* debian/control: Change XS-Vcs-* to Vcs-*
* Remove Homepage semi-field from description

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifndef ALSA_HPP_INCLUDED
 
2
#define ALSA_HPP_INCLUDED
 
3
 
 
4
/**
 
5
 
 
6
@file alsa.hpp
 
7
@brief An experimental low-level C++ API to ALSA.
 
8
@version 0.4
 
9
@author Lasse Kärkkäinen <tronic>
 
10
@license GNU LGPL 2.1 or later
 
11
 
 
12
This is a header-only C++ wrapper for the ALSA library. This means that you do
 
13
not need to add any new binary files to your build and you will only need to
 
14
link with -lasound, as if you were using the C API directly. GCC will probably
 
15
optimize all of the wrapper overhead away in any case, leaving you with a safer
 
16
and easier API to ALSA, but leaving your binaries just as if you had used C.
 
17
 
 
18
The library is designed to be very closely related to the C API, so that you
 
19
can still see what is going on under the hood, and also so that porting existing
 
20
applications to it is trivial. The interoperatibility between C and C++ APIs is
 
21
is a major design goal. What this means is that you can freely mix C and C++ API
 
22
calls with no problems.
 
23
 
 
24
 
 
25
Usage example:
 
26
 
 
27
alsa::pcm alsa_pcm;  // Create a PCM object (defaults to playback and mode = 0)
 
28
 
 
29
The above creates an equivalent for the snd_pcm_t*, which is what you need to
 
30
play or record anything. Make sure that the alsa_pcm object stays alive as long
 
31
as you need it (and preferrably not longer) by putting it inside a suitable
 
32
class or even inside the main() function. The object cannot be copied, but you
 
33
can pass references to it to other objects or functions.
 
34
 
 
35
The alsa_pcm also automatically converts into snd_pcm_t* as required, so you can
 
36
use it as an argument for the C API functions.
 
37
 
 
38
Next you'll need to configure it:
 
39
 
 
40
unsigned int rate = 44100;
 
41
unsigned int period;
 
42
 
 
43
alsa::hw_config(alsa_pcm)  // Create a new config space
 
44
  .set(SND_PCM_ACCESS_RW_INTERLEAVED)
 
45
  .set(SND_PCM_FORMAT_S16_LE)
 
46
  .rate_near(rate)
 
47
  .channels(1)
 
48
  .period_size_first(period)  // Get the smallest available period size
 
49
  .commit();  // Apply the config to the PCM
 
50
 
 
51
alsa::hw_config(pcm) constructs a new config space, using the current settings
 
52
from the PCM, if available, or the "any" space, if not set yet. The any space
 
53
contains all available hardware configurations and you have to narrow it down
 
54
to exactly one option by setting some parameters. Trying to narrow it too much
 
55
(by asking an amount of channels that is not available, for example) causes a
 
56
failure.
 
57
 
 
58
In case of failure, an alsa::error is thrown. When this happens, the commit part
 
59
never gets executed and thus the result is not stored to alsa_pcm and the
 
60
failed operation will have no effect (even to the temporary hw_config object,
 
61
which gets destroyed when the exception flies). However, all the operations
 
62
already performed successfully remain in effect.
 
63
 
 
64
The rate_near functions behaves like the C API *_near functions
 
65
do: they take the preferred value as an argument and then they modify the
 
66
argument, returning the actual rate. For example, if your sound card only
 
67
supports 48000 Hz, rate will be set to that on that call, even if some later
 
68
part, such as setting the number of channels, fails.
 
69
 
 
70
In the example above, a temporary object of type alsa::hw_config was used, but
 
71
you can also create a variable of it, should you need to test something in
 
72
between, or if you want to call the C API functions directly (hw_config
 
73
converts automatically into hw_params, which converts into snd_hw_params_t*).
 
74
 
 
75
For this, you may use a block like this:
 
76
 
 
77
{
 
78
    alsa::hw_config hw(alsa_pcm);
 
79
    hw.set(SND_ACCESS_(SND_PCM_ACCESS_MMAP_INTERLEAVED);
 
80
    hw.set(SND_PCM_FORMAT_FLOAT_BE);
 
81
    if (!snd_pcm_hw_params_is_full_duplex(hw)) hw.channels(2);
 
82
    hw.commit();
 
83
}
 
84
 
 
85
(anyone got a better example?)
 
86
 
 
87
 
 
88
Software configuration works in the same way, using alsa::sw_config, just the
 
89
parameters to be adjusted are different.
 
90
 
 
91
When constructed, both sw_config and hw_config try to load config from the given
 
92
PCM. If that fails, sw_config throws, but hw_config still tries loading the any
 
93
space. Alternatively, you may supply a snd_pcm_hw/sw_params_t const* as a second
 
94
argument for the constructor to get a copy of the contents of that that instead.
 
95
 
 
96
The contents may be loaded (overwrites the old contents) with these functions:
 
97
  .any()            Get the "any" configuration (hw_config only)
 
98
  .current()        Get the currently active configuration from PCM
 
99
Once finished with the changes, you should call:
 
100
  .commit()         Store current config space to the PCM
 
101
 
 
102
For enum values SND_PCM_*, you may use the following functions:
 
103
  .get(var)         Get the current setting into the given variable
 
104
  .set(val)         Set the value requested (also supports masks)
 
105
  .enum_test(val)   The same as .set, except that it does not set anything
 
106
  .enum_first(var)  Set the first available option, store the selection in var
 
107
  .enum_last(var)   Set the last available option, store the selection in var
 
108
 
 
109
The parameter to manipulate is chosen based on the argument type. The enum_*
 
110
functions and masks are only available for hardware parameters, not for
 
111
sw_param.
 
112
 
 
113
For integer values (times, sizes, counts), these functions are available:
 
114
  .get_X(var)       Get the current setting into the given variable
 
115
  .X(val)           Set the value requested
 
116
For ranges, the following can also be used:
 
117
  .get_X_min(var)   Get the smallest available value into var
 
118
  .get_X_max(var)   Get the largest available value into var
 
119
  .X_min(var)       Remove all values smaller than var and store the new
 
120
                    smallest value into var.
 
121
  .X_max(var)       Remove all values larger than var, store new max in var.
 
122
  .X_minmax(v1, v2) Limit to [v1, v2], store new range in v1, v2.
 
123
  .X_near(var)      Set the closest available value and store it in var
 
124
  .X_first(var)     Set the first available option, store the selection in var
 
125
  .X_last(var)      Set the last available option, store the selection in var
 
126
 
 
127
For booleans, these functions are available:
 
128
  .get_X(var)    Get the current setting (var must be unsigned int or bool)
 
129
  .set_X(val)    Set the value (val can be anything that converts into bool)
 
130
  
 
131
Replace X with the name of the parameter that you want to set. Consult the ALSA
 
132
C library reference for available options. All functions that modify their
 
133
arguments require the same type as is used in the C API (often unsigned int or
 
134
snd_pcm_uframes_t). The only exception is with bool types, where both bool and
 
135
unsigned int are accepted.
 
136
 
 
137
For those ranged parameters that support the dir argument (see ALSA docs), the
 
138
default value is always 0 when writing and NULL (none) when reading. You may
 
139
supply the preferred dir value or variable as the second argument and then the
 
140
value will be used or the result will be stored in the variable supplied.
 
141
 
 
142
For example, the following calls are equivalent:
 
143
snd_pcm_hw_params_set_format(pcm, hw, SND_PCM_FORMAT_FLOAT_LE)
 
144
  <=> hw.set(SND_PCM_FORMAT_FLOAT_LE)
 
145
snd_pcm_hw_params_set_rate_resample(pcm, hw, 1) <=> hw.rate_resample(true)
 
146
snd_pcm_hw_params_set_channels_near(pcm, hw, &num) <=> hw.channels_near(num)
 
147
snd_pcm_hw_params_get_rate(hw, &rate, NULL) <=> hw.get_rate(rate)
 
148
snd_pcm_hw_params_get_rate(hw, &rate, &dir) <=> hw.get_rate(rate, dir)
 
149
 
 
150
 
 
151
... except for the fact that the C++ versions also check the return values and
 
152
throw alsa::error if anything goes wrong. alsa::error inherits from
 
153
std::runtime_error and thus eventually from std::exception, so you can catch
 
154
pretty much everything by catching that somewhere in your code:
 
155
 
 
156
try {
 
157
        // do everything here
 
158
} catch (std::exception& e) {
 
159
        std::cerr << "FATAL ERROR: " << e.what() << std::endl;
 
160
}
 
161
 
 
162
However, recent versions of glibc seem to be handling uncaught exceptions quite
 
163
nicely, so even without a try-catch you may get a nice printout in your console:
 
164
 
 
165
terminate called after throwing an instance of 'alsa::error'
 
166
  what():  ALSA snd_pcm_hw_params_set_channels failed: Invalid argument
 
167
Aborted
 
168
 
 
169
If you need to know the error code, you may call e.code() after catching
 
170
alsa::error& e.
 
171
 
 
172
 
 
173
When you call the C API functions directly, the ALSA_CHECKED macro may prove to
 
174
be useful. It is used internally by the library for testing errors and throwing
 
175
exceptions when calling the C functions. It will throw alsa::error with a
 
176
description of the error if the function returns a negative value.
 
177
 
 
178
The macro is well-behaving, as it only calls an internal helper function,
 
179
evaluating the arguments given exactly once.
 
180
 
 
181
Usage: ALSA_CHECKED(snd_pcm_whatever, (arg1, arg2, arg2));
 
182
 
 
183
Note: a comma between function name and arguments.
 
184
 
 
185
The return value can also still be used (will return only >= 0):
 
186
 
 
187
 
 
188
For MMAP transfers, another RAII wrapper, alsa::mmap, is provided.
 
189
 
 
190
Usage:
 
191
 
 
192
// First we need to call avail_update (storing the return value is optional)
 
193
snd_pcm_uframes_t count = ALSA_CHECKED(snd_pcm_avail_update, (pcm));
 
194
alsa::mmap mmap(pcm, 256) // Begin MMAP transfer, request 256 frames
 
195
 
 
196
// Process the audio (mmap.frames frames of it, accessible via mmap.areas,
 
197
// starting at offset mmap.offset) and then let mmap go out of scope, which will
 
198
// end the transfer. If you didn't process all available frames, set the number
 
199
// of frames processed to mmap.frames before the object goes out of scope.
 
200
 
 
201
As usual, the constructor will throw alsa::error in case of error.
 
202
 
 
203
 
 
204
In case you really want to get low-level, alsa::hw_params and alsa::sw_params
 
205
are offered. These only contain the corresponding snd_pcm_*_params_t, but they
 
206
allocate and free memory automatically and they can also properly copy the
 
207
struct contents when they get copied. Be aware that the structure contents are
 
208
not initialized during construction, so you have to initialize it yourself (just
 
209
like with the C API). They are used internally by hw_config and sw_config and
 
210
normally it should be better to use these instead of dealing directly with the
 
211
params.
 
212
 
 
213
**/
 
214
 
 
215
#include <alsa/asoundlib.h>
 
216
#include <stdexcept>
 
217
#include <string>
 
218
 
 
219
/**
 
220
* A macro that executes func with the given args and tests for errors.
 
221
* Examples of use:
 
222
*   ALSA_CHECKED(snd_pcm_recover, (pcm, e.code(), 0));
 
223
*   snd_pcm_uframes_t count = ALSA_CHECKED(snd_pcm_avail_update, (pcm));
 
224
* @param func the function name
 
225
* @param args arguments in parenthesis
 
226
* @return the return value of the function
 
227
* @throws alsa::error if the return value is smaller than zero.
 
228
**/
 
229
#define ALSA_CHECKED(func, args) alsa::internal::check(func args, #func)
 
230
 
 
231
namespace alsa {
 
232
        /** @short Exception class **/
 
233
        class error: public std::runtime_error {
 
234
                int err;
 
235
          public:
 
236
                error(std::string const& function, int err): std::runtime_error("ALSA " + function + " failed: " + std::string(snd_strerror(err))), err(err) {}
 
237
                int code() const { return err; }
 
238
        };
 
239
 
 
240
        namespace internal {
 
241
                /** For internal use only: a function used by the macro ALSA_CHECKED **/
 
242
                template<typename T> T check(T ret, char const* funcname) {
 
243
                        if (ret < 0) throw error(funcname, ret);
 
244
                        return ret;
 
245
                }
 
246
                /**
 
247
                * @short FOR INTERNAL USE ONLY. A utility class similar to
 
248
                * boost::noncopyable, duplicated here in order to avoid
 
249
                * a dependency on the Boost library.
 
250
                **/
 
251
                class noncopyable {
 
252
                  protected:
 
253
                        noncopyable() {}
 
254
                        ~noncopyable() {}
 
255
                  private:
 
256
                        noncopyable(noncopyable const&);
 
257
                        noncopyable const& operator=(noncopyable const&);
 
258
                };
 
259
        }
 
260
 
 
261
        /**
 
262
        * @short A minimal RAII wrapper for ALSA PCM.
 
263
        * Automatically converts into snd_pcm_t* as needed, so the ALSA C API
 
264
        * can be used directly with this.
 
265
        **/
 
266
        class pcm: internal::noncopyable {
 
267
                snd_pcm_t* handle;
 
268
          public:
 
269
                pcm(char const* device = "default", snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK, int mode = 0) {
 
270
                        ALSA_CHECKED(snd_pcm_open, (&handle, device, stream, mode));
 
271
                }
 
272
                ~pcm() { snd_pcm_close(handle); }
 
273
                operator snd_pcm_t*() { return handle; }
 
274
                operator snd_pcm_t const*() const { return handle; }
 
275
        };
 
276
 
 
277
        // RAII wrapper for snd_pcm_hw/sw_params_t types.
 
278
        
 
279
#define ALSA_HPP_PARAMWRAPPER(type) \
 
280
        class type##_params {\
 
281
                snd_pcm_##type##_params_t* handle;\
 
282
                void init() { ALSA_CHECKED(snd_pcm_##type##_params_malloc, (&handle)); }\
 
283
          public:\
 
284
                type##_params() { init(); }\
 
285
                ~type##_params() { snd_pcm_##type##_params_free(handle); }\
 
286
                type##_params(type##_params const& orig) { init(); *this = orig; }\
 
287
                type##_params(snd_pcm_##type##_params_t const* orig) { init(); *this = orig; }\
 
288
                type##_params& operator=(snd_pcm_##type##_params_t const* params) {\
 
289
                        if (handle != params) snd_pcm_##type##_params_copy(handle, params);\
 
290
                        return *this;\
 
291
                }\
 
292
                operator snd_pcm_##type##_params_t*() { return handle; }\
 
293
                operator snd_pcm_##type##_params_t const*() const { return handle; }\
 
294
        };
 
295
 
 
296
        ALSA_HPP_PARAMWRAPPER(hw)
 
297
        ALSA_HPP_PARAMWRAPPER(sw)
 
298
#undef ALSA_HPP_PARAMWRAPPER
 
299
 
 
300
// Various helper macros used for generating code for hw_config and sw_config
 
301
 
 
302
#define ALSA_HPP_FUNC(name, suffix) ALSA_HPP_TEMPLATE(& name(), suffix, (pcm, params))
 
303
 
 
304
#define ALSA_HPP_VARGET(name, type) \
 
305
  ALSA_HPP_TEMPLATE(& get_##name(type& val), _get_##name, (params, &val))\
 
306
  ALSA_HPP_TEMPLATE(const& get_##name(type& val) const, _get_##name, (params, &val))
 
307
 
 
308
#define ALSA_HPP_VAR(name, type) ALSA_HPP_VARGET(name, type)\
 
309
  ALSA_HPP_TEMPLATE(& name(type val), _set_##name, (pcm, params, val))
 
310
 
 
311
#define ALSA_HPP_ENUMVARMINIMAL(name) \
 
312
  ALSA_HPP_TEMPLATE(& get(snd_pcm_##name##_t& name), _get_##name, (params, &name))\
 
313
  ALSA_HPP_TEMPLATE(const& get(snd_pcm_##name##_t& name) const, _get_##name, (params, &name))\
 
314
  ALSA_HPP_TEMPLATE(& set(snd_pcm_##name##_t name), _set_##name, (pcm, params, name))
 
315
 
 
316
#define ALSA_HPP_ENUMVAR(name) ALSA_HPP_ENUMVARMINIMAL(name)\
 
317
  ALSA_HPP_TEMPLATE(& enum_test(snd_pcm_##name##_t name), _test_##name, (pcm, params, name))\
 
318
  ALSA_HPP_TEMPLATE(& enum_first(snd_pcm_##name##_t& name), _set_##name##_first, (pcm, params, &name))\
 
319
  ALSA_HPP_TEMPLATE(& enum_last(snd_pcm_##name##_t& name), _set_##name##_last, (pcm, params, &name))\
 
320
  ALSA_HPP_TEMPLATE(& set(snd_pcm_##name##_mask_t* mask), _set_##name##_mask, (pcm, params, mask))
 
321
  
 
322
#define ALSA_HPP_BOOLVAR(name) \
 
323
  ALSA_HPP_CLASS& get_##name(bool& val) { unsigned int tmp; get_##name(tmp); val = tmp; return *this; }\
 
324
  /*ALSA_HPP_CLASS const& get_##name(bool& val) const { unsigned int tmp; get_##name(tmp); val = tmp; return *this; }*/\
 
325
  ALSA_HPP_TEMPLATE(& get_##name(unsigned int& val), _get_##name, (pcm, params, &val))\
 
326
  /*ALSA_HPP_TEMPLATE(const& get_##name(unsigned int& val) const, _get_##name, (pcm, params, &val))*/\
 
327
  ALSA_HPP_TEMPLATE(& name(bool val = true), _set_##name, (pcm, params, val))
 
328
 
 
329
#define ALSA_HPP_RANGEVAR(name, type) ALSA_HPP_VAR(name, type)\
 
330
  ALSA_HPP_TEMPLATE(& get_##name##_min(type& min), _get_##name##_min, (params, &min))\
 
331
  ALSA_HPP_TEMPLATE(const& get_##name##_min(type& min) const, _get_##name##_min, (params, &min))\
 
332
  ALSA_HPP_TEMPLATE(& get_##name##_max(type& max), _get_##name##_max, (params, &max))\
 
333
  ALSA_HPP_TEMPLATE(const& get_##name##_max(type& max) const, _get_##name##_max, (params, &max))\
 
334
  ALSA_HPP_TEMPLATE(& name##_min(type& min), _set_##name##_min, (pcm, params, &min))\
 
335
  ALSA_HPP_TEMPLATE(& name##_max(type& max), _set_##name##_max, (pcm, params, &max))\
 
336
  ALSA_HPP_TEMPLATE(& name##_minmax(type& min, type& max), _set_##name##_minmax, (pcm, params, &min, &max))\
 
337
  ALSA_HPP_TEMPLATE(& name##_near(type& val), _set_##name##_near, (pcm, params, &val))\
 
338
  ALSA_HPP_TEMPLATE(& name##_first(type& val), _set_##name##_first, (pcm, params, &val))\
 
339
  ALSA_HPP_TEMPLATE(& name##_last(type& val), _set_##name##_last, (pcm, params, &val))
 
340
 
 
341
#define ALSA_HPP_RANGEVARDIR(name, type) \
 
342
  ALSA_HPP_TEMPLATE(& get_##name(type& val), _get_##name, (params, &val, NULL))\
 
343
  ALSA_HPP_TEMPLATE(const& get_##name(type& val) const, _get_##name, (params, &val, NULL))\
 
344
  ALSA_HPP_TEMPLATE(& get_##name(type& val, int& dir), _get_##name, (params, &val, &dir))\
 
345
  ALSA_HPP_TEMPLATE(const& get_##name(type& val, int& dir) const, _get_##name, (params, &val, &dir))\
 
346
  ALSA_HPP_TEMPLATE(& get_##name##_min(type& min), _get_##name##_min, (params, &min, NULL))\
 
347
  ALSA_HPP_TEMPLATE(const& get_##name##_min(type& min) const, _get_##name##_min, (params, &min, NULL))\
 
348
  ALSA_HPP_TEMPLATE(& get_##name##_min(type& min, int& dir), _get_##name##_min, (params, &min, &dir))\
 
349
  ALSA_HPP_TEMPLATE(const& get_##name##_min(type& min, int& dir) const, _get_##name##_min, (params, &min, &dir))\
 
350
  ALSA_HPP_TEMPLATE(& get_##name##_max(type& max), _get_##name##_max, (params, &max, NULL))\
 
351
  ALSA_HPP_TEMPLATE(const& get_##name##_max(type& max) const, _get_##name##_max, (params, &max, NULL))\
 
352
  ALSA_HPP_TEMPLATE(& get_##name##_max(type& max, int& dir), _get_##name##_max, (params, &max, &dir))\
 
353
  ALSA_HPP_TEMPLATE(const& get_##name##_max(type& max, int& dir) const, _get_##name##_max, (params, &max, &dir))\
 
354
  ALSA_HPP_TEMPLATE(& name(type val, int dir = 0), _set_##name, (pcm, params, val, dir))\
 
355
  ALSA_HPP_TEMPLATE(& name##_min(type& min), _set_##name##_min, (pcm, params, &min, NULL))\
 
356
  ALSA_HPP_TEMPLATE(& name##_min(type& min, int& dir), _set_##name##_min, (pcm, params, &min, &dir))\
 
357
  ALSA_HPP_TEMPLATE(& name##_max(type& max), _set_##name##_max, (pcm, params, &max, NULL))\
 
358
  ALSA_HPP_TEMPLATE(& name##_max(type& max, int& dir), _set_##name##_max, (pcm, params, &max, &dir))\
 
359
  ALSA_HPP_TEMPLATE(& name##_minmax(type& min, type& max), _set_##name##_minmax, (pcm, params, &min, NULL, &max, NULL))\
 
360
  ALSA_HPP_TEMPLATE(& name##_minmax(type& min, int& mindir, type& max, int& maxdir), _set_##name##_minmax, (pcm, params, &min, &mindir, &max, &maxdir))\
 
361
  ALSA_HPP_TEMPLATE(& name##_near(type& val), _set_##name##_near, (pcm, params, &val, NULL))\
 
362
  ALSA_HPP_TEMPLATE(& name##_near(type& val, int& dir), _set_##name##_near, (pcm, params, &val, &dir))\
 
363
  ALSA_HPP_TEMPLATE(& name##_first(type& val), _set_##name##_first, (pcm, params, &val, NULL))\
 
364
  ALSA_HPP_TEMPLATE(& name##_first(type& val, int& dir), _set_##name##_first, (pcm, params, &val, &dir))\
 
365
  ALSA_HPP_TEMPLATE(& name##_last(type& val), _set_##name##_last, (pcm, params, &val, NULL))\
 
366
  ALSA_HPP_TEMPLATE(& name##_last(type& val, int& dir), _set_##name##_last, (pcm, params, &val, &dir))
 
367
 
 
368
        /** @short A helper object for modifying hw_params of a PCM. **/
 
369
        class hw_config: internal::noncopyable {
 
370
                snd_pcm_t* pcm;
 
371
                hw_params params;
 
372
          public:
 
373
                /**
 
374
                * Construct a new config object, initialized with the current settings
 
375
                * of the PCM or with the "any" configuration space, if there are none.
 
376
                **/
 
377
                hw_config(snd_pcm_t* pcm): pcm(pcm) {
 
378
                        try { current(); } catch (std::runtime_error&) { any(); }
 
379
                }
 
380
                /** Construct a new config object, initialized with a copy from given parameters **/
 
381
                hw_config(snd_pcm_t* pcm, snd_pcm_hw_params_t const* params): pcm(pcm), params(params) {}
 
382
                operator hw_params&() { return params; }
 
383
                operator hw_params const&() const { return params; }
 
384
#define ALSA_HPP_CLASS hw_config
 
385
#define ALSA_HPP_TEMPLATE(proto, suffix, params) ALSA_HPP_CLASS proto { ALSA_CHECKED(snd_pcm_hw_params##suffix, params); return *this; }
 
386
                // Load / store functions
 
387
                ALSA_HPP_FUNC(commit,)
 
388
                ALSA_HPP_FUNC(any, _any)
 
389
                ALSA_HPP_FUNC(current, _current)
 
390
                // Enum functions
 
391
                ALSA_HPP_ENUMVAR(access)
 
392
                ALSA_HPP_ENUMVAR(format)
 
393
                ALSA_HPP_ENUMVAR(subformat)
 
394
                // Bool functions
 
395
                ALSA_HPP_BOOLVAR(rate_resample)
 
396
                ALSA_HPP_BOOLVAR(export_buffer)
 
397
                // Range functions
 
398
                ALSA_HPP_RANGEVAR(channels, unsigned int)
 
399
                ALSA_HPP_RANGEVAR(buffer_size, snd_pcm_uframes_t)
 
400
                // Range functions with direction argument
 
401
                ALSA_HPP_RANGEVARDIR(rate, unsigned int)
 
402
                ALSA_HPP_RANGEVARDIR(period_time, unsigned int)
 
403
                ALSA_HPP_RANGEVARDIR(period_size, snd_pcm_uframes_t)
 
404
                ALSA_HPP_RANGEVARDIR(periods, unsigned int)
 
405
                ALSA_HPP_RANGEVARDIR(buffer_time, unsigned int)
 
406
                ALSA_HPP_RANGEVARDIR(tick_time, unsigned int)
 
407
#undef ALSA_HPP_TEMPLATE
 
408
#undef ALSA_HPP_CLASS
 
409
        };
 
410
 
 
411
        class sw_config: internal::noncopyable {
 
412
                snd_pcm_t* pcm;
 
413
                sw_params params;
 
414
          public:
 
415
                sw_config(snd_pcm_t* pcm): pcm(pcm) { current(); }
 
416
                /** Construct a new config object, initialized with a copy from given parameters **/
 
417
                sw_config(snd_pcm_t* pcm, snd_pcm_sw_params_t const* params): pcm(pcm), params(params) {}
 
418
                operator sw_params&() { return params; }
 
419
                operator sw_params const&() const { return params; }
 
420
#define ALSA_HPP_CLASS sw_config
 
421
#define ALSA_HPP_TEMPLATE(proto, suffix, params) ALSA_HPP_CLASS proto { ALSA_CHECKED(snd_pcm_sw_params##suffix, params); return *this; }
 
422
                // Load / store functions
 
423
                ALSA_HPP_FUNC(commit,)
 
424
                ALSA_HPP_FUNC(current, _current)
 
425
                // Enum functions
 
426
                typedef snd_pcm_tstamp_t snd_pcm_tstamp_mode_t; // Workaround for inconsistent naming in asound
 
427
                ALSA_HPP_ENUMVARMINIMAL(tstamp_mode)
 
428
                // Simple variable functions
 
429
                ALSA_HPP_VAR(sleep_min, unsigned int)
 
430
                ALSA_HPP_VAR(avail_min, snd_pcm_uframes_t)
 
431
                ALSA_HPP_VAR(xfer_align, snd_pcm_uframes_t)
 
432
                ALSA_HPP_VAR(start_threshold, snd_pcm_uframes_t)
 
433
                ALSA_HPP_VAR(stop_threshold, snd_pcm_uframes_t)
 
434
                ALSA_HPP_VAR(silence_threshold, snd_pcm_uframes_t)
 
435
                ALSA_HPP_VAR(silence_size, snd_pcm_uframes_t)
 
436
                // Get-only variable
 
437
                ALSA_HPP_VARGET(boundary, snd_pcm_uframes_t)
 
438
#undef ALSA_HPP_TEMPLATE
 
439
#undef ALSA_HPP_CLASS
 
440
        };
 
441
 
 
442
#undef ALSA_HPP_FUNC
 
443
#undef ALSA_HPP_VAR
 
444
#undef ALSA_HPP_VARGET
 
445
#undef ALSA_HPP_ENUMVAR
 
446
#undef ALSA_HPP_ENUMVARMINIMAL
 
447
#undef ALSA_HPP_BOOLVAR
 
448
#undef ALSA_HPP_RANGEVAR
 
449
#undef ALSA_HPP_RANGEVARDIR
 
450
 
 
451
        /** @short A RAII wrapper for snd_pcm_mmap_begin/end block. **/
 
452
        class mmap {
 
453
                snd_pcm_t* pcm;
 
454
          public:
 
455
                snd_pcm_channel_area_t const* areas;
 
456
                snd_pcm_uframes_t const offset; // Const for external API
 
457
                snd_pcm_uframes_t frames;
 
458
                /**
 
459
                * Initiate MMAP transfer. Returns a buffer via .areas member variable.
 
460
                * snd_pcm_avail_update must be called directly before constructing the
 
461
                * alsa::mmap object, otherwise snd_pcm_mmap_begin may return a wrong
 
462
                * count of available frames.
 
463
                * @param pcm PCM handle
 
464
                * @param fr number of frames to request (check .frames for actual count)
 
465
                **/
 
466
                mmap(snd_pcm_t* pcm, snd_pcm_uframes_t fr): pcm(pcm), areas(), offset(), frames(fr) {
 
467
                        ALSA_CHECKED(snd_pcm_mmap_begin, (pcm, &areas, const_cast<snd_pcm_uframes_t*>(&offset), &frames));
 
468
                }
 
469
                /**
 
470
                * End MMAP transfer. If not all frames were used, the count of frames
 
471
                * used be set in .frames member variable before alsa::mmap destruction.
 
472
                **/
 
473
                ~mmap() {
 
474
                        // We just assume that this works (can't do anything sensible if it fails).
 
475
                        snd_pcm_mmap_commit(pcm, offset, frames);
 
476
                }
 
477
        };
 
478
 
 
479
}
 
480
 
 
481
#endif
 
482