porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h
Go to the documentation of this file.
1 /*
2 Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
3 miniaudio - v0.10.0 - 2020-03-07
4 
5 David Reid - davidreidsoftware@gmail.com
6 
7 Website: https://miniaud.io
8 GitHub: https://github.com/dr-soft/miniaudio
9 */
10 
11 /*
12 RELEASE NOTES - VERSION 0.10
13 ============================
14 Version 0.10 includes major API changes and refactoring, mostly concerned with the data conversion system. Data conversion is performed internally to convert
15 audio data between the format requested when initializing the `ma_device` object and the format of the internal device used by the backend. The same applies
16 to the `ma_decoder` object. The previous design has several design flaws and missing features which necessitated a complete redesign.
17 
18 
19 Changes to Data Conversion
20 --------------------------
21 The previous data conversion system used callbacks to deliver input data for conversion. This design works well in some specific situations, but in other
22 situations it has some major readability and maintenance issues. The decision was made to replace this with a more iterative approach where you just pass in a
23 pointer to the input data directly rather than dealing with a callback.
24 
25 The following are the data conversion APIs that have been removed and their replacements:
26 
27  - ma_format_converter -> ma_convert_pcm_frames_format()
28  - ma_channel_router -> ma_channel_converter
29  - ma_src -> ma_resampler
30  - ma_pcm_converter -> ma_data_converter
31 
32 The previous conversion APIs accepted a callback in their configs. There are no longer any callbacks to deal with. Instead you just pass the data into the
33 `*_process_pcm_frames()` function as a pointer to a buffer.
34 
35 The simplest aspect of data conversion is sample format conversion. To convert between two formats, just call `ma_convert_pcm_frames_format()`. Channel
36 conversion is also simple which you can do with `ma_channel_router` via `ma_channel_router_process_pcm_frames()`.
37 
38 Resampling is more complicated because the number of output frames that are processed is different to the number of input frames that are consumed. When you
39 call `ma_resampler_process_pcm_frames()` you need to pass in the number of input frames available for processing and the number of output frames you want to
40 output. Upon returning they will receive the number of input frames that were consumed and the number of output frames that were generated.
41 
42 The `ma_data_converter` API is a wrapper around format, channel and sample rate conversion and handles all of the data conversion you'll need which probably
43 makes it the best option if you need to do data conversion.
44 
45 In addition to changes to the API design, a few other changes have been made to the data conversion pipeline:
46 
47  - The sinc resampler has been removed. This was completely broken and never actually worked properly.
48  - The linear resampler now uses low-pass filtering to remove aliasing. The quality of the low-pass filter can be controlled via the resampler config with the
49  `lpfOrder` option, which has a maximum value of MA_MAX_FILTER_ORDER.
50  - Data conversion now supports s16 natively which runs through a fixed point pipeline. Previously everything needed to be converted to floating point before
51  processing, whereas now both s16 and f32 are natively supported. Other formats still require conversion to either s16 or f32 prior to processing, however
52  `ma_data_converter` will handle this for you.
53 
54 
55 Custom Memory Allocators
56 ------------------------
57 miniaudio has always supported macro level customization for memory allocation via MA_MALLOC, MA_REALLOC and MA_FREE, however some scenarios require more
58 flexibility by allowing a user data pointer to be passed to the custom allocation routines. Support for this has been added to version 0.10 via the
59 `ma_allocation_callbacks` structure. Anything making use of heap allocations has been updated to accept this new structure.
60 
61 The `ma_context_config` structure has been updated with a new member called `allocationCallbacks`. Leaving this set to it's defaults returned by
62 `ma_context_config_init()` will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. Likewise, The `ma_decoder_config` structure has been updated in the same
63 way, and leaving everything as-is after `ma_decoder_config_init()` will cause it to use the same defaults.
64 
65 The following APIs have been updated to take a pointer to a `ma_allocation_callbacks` object. Setting this parameter to NULL will cause it to use defaults.
66 Otherwise they will use the relevant callback in the structure.
67 
68  - ma_malloc()
69  - ma_realloc()
70  - ma_free()
71  - ma_aligned_malloc()
72  - ma_aligned_free()
73  - ma_rb_init() / ma_rb_init_ex()
74  - ma_pcm_rb_init() / ma_pcm_rb_init_ex()
75 
76 Note that you can continue to use MA_MALLOC, MA_REALLOC and MA_FREE as per normal. These will continue to be used by default if you do not specify custom
77 allocation callbacks.
78 
79 
80 Buffer and Period Configuration Changes
81 ---------------------------------------
82 The way in which the size of the internal buffer and periods are specified in the device configuration have changed. In previous versions, the config variables
83 `bufferSizeInFrames` and `bufferSizeInMilliseconds` defined the size of the entire buffer, with the size of a period being the size of this variable divided by
84 the period count. This became confusing because people would expect the value of `bufferSizeInFrames` or `bufferSizeInMilliseconds` to independantly determine
85 latency, when in fact it was that value divided by the period count that determined it. These variables have been removed and replaced with new ones called
86 `periodSizeInFrames` and `periodSizeInMilliseconds`.
87 
88 These new configuration variables work in the same way as their predecessors in that if one is set to 0, the other will be used, but the main difference is
89 that you now set these to you desired latency rather than the size of the entire buffer. The benefit of this is that it's much easier and less confusing to
90 configure latency.
91 
92 The following unused APIs have been removed:
93 
94  ma_get_default_buffer_size_in_milliseconds()
95  ma_get_default_buffer_size_in_frames()
96 
97 The following macros have been removed:
98 
99  MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY
100  MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE
101 
102 
103 Other API Changes
104 -----------------
105 Other less major API changes have also been made in version 0.10.
106 
107 `ma_device_set_stop_callback()` has been removed. If you require a stop callback, you must now set it via the device config just like the data callback.
108 
109 The `ma_sine_wave` API has been replaced with a more general API called `ma_waveform`. This supports generation of different types of waveforms, including
110 sine, square, triangle and sawtooth. Use `ma_waveform_init()` in place of `ma_sine_wave_init()` to initialize the waveform object. This takes a configuration
111 object called `ma_waveform_config` which defines the properties of the waveform. Use `ma_waveform_config_init()` to initialize a `ma_waveform_config` object.
112 Use `ma_waveform_read_pcm_frames()` in place of `ma_sine_wave_read_f32()` and `ma_sine_wave_read_f32_ex()`.
113 
114 `ma_convert_frames()` and `ma_convert_frames_ex()` have been changed. Both of these functions now take a new parameter called `frameCountOut` which specifies
115 the size of the output buffer in PCM frames. This has been added for safety. In addition to this, the parameters for `ma_convert_frames_ex()` have changed to
116 take a pointer to a `ma_data_converter_config` object to specify the input and output formats to convert between. This was done to make it more flexible, to
117 prevent the parameter list getting too long, and to prevent API breakage whenever a new conversion property is added.
118 
119 `ma_calculate_frame_count_after_src()` has been renamed to `ma_calculate_frame_count_after_resampling()` for consistency with the new `ma_resampler` API.
120 
121 
122 Filters
123 -------
124 The following filters have been added:
125 
126  |-------------|-------------------------------------------------------------------|
127  | API | Description |
128  |-------------|-------------------------------------------------------------------|
129  | ma_biquad | Biquad filter (transposed direct form 2) |
130  | ma_lpf1 | First order low-pass filter |
131  | ma_lpf2 | Second order low-pass filter |
132  | ma_lpf | High order low-pass filter (Butterworth) |
133  | ma_hpf1 | First order high-pass filter |
134  | ma_hpf2 | Second order high-pass filter |
135  | ma_hpf | High order high-pass filter (Butterworth) |
136  | ma_bpf2 | Second order band-pass filter |
137  | ma_bpf | High order band-pass filter |
138  | ma_peak2 | Second order peaking filter |
139  | ma_notch2 | Second order notching filter |
140  | ma_loshelf2 | Second order low shelf filter |
141  | ma_hishelf2 | Second order high shelf filter |
142  |-------------|-------------------------------------------------------------------|
143 
144 These filters all support 32-bit floating point and 16-bit signed integer formats natively. Other formats need to be converted beforehand.
145 
146 
147 Sine, Square, Triangle and Sawtooth Waveforms
148 ---------------------------------------------
149 Previously miniaudio supported only sine wave generation. This has now been generalized to support sine, square, triangle and sawtooth waveforms. The old
150 `ma_sine_wave` API has been removed and replaced with the `ma_waveform` API. Use `ma_waveform_config_init()` to initialize a config object, and then pass it
151 into `ma_waveform_init()`. Then use `ma_waveform_read_pcm_frames()` to read PCM data.
152 
153 
154 Noise Generation
155 ----------------
156 A noise generation API has been added. This is used via the `ma_noise` API. Currently white, pink and Brownian noise is supported. The `ma_noise` API is
157 similar to the waveform API. Use `ma_noise_config_init()` to initialize a config object, and then pass it into `ma_noise_init()` to initialize a `ma_noise`
158 object. Then use `ma_noise_read_pcm_frames()` to read PCM data.
159 
160 
161 Miscellaneous Changes
162 ---------------------
163 Internal functions have all been made static where possible. If you get warnings about unused functions, please submit a bug report.
164 
165 The `ma_device` structure is no longer defined as being aligned to MA_SIMD_ALIGNMENT. This resulted in a possible crash when allocating a `ma_device` object on
166 the heap, but not aligning it to MA_SIMD_ALIGNMENT. This crash would happen due to the compiler seeing the alignment specified on the structure and assuming it
167 was always aligned as such and thinking it was safe to emit alignment-dependant SIMD instructions. Since miniaudio's philosophy is for things to just work,
168 this has been removed from all structures.
169 
170 Results codes have been overhauled. Unnecessary result codes have been removed, and some have been renumbered for organisation purposes. If you are are binding
171 maintainer you will need to update your result codes. Support has also been added for retrieving a human readable description of a given result code via the
172 `ma_result_description()` API.
173 */
174 
175 
176 /*
177 Introduction
178 ============
179 miniaudio is a single file library for audio playback and capture. To use it, do the following in one .c file:
180 
181  ```c
182  #define MINIAUDIO_IMPLEMENTATION
183  #include "miniaudio.h
184  ```
185 
186 You can #include miniaudio.h in other parts of the program just like any other header.
187 
188 miniaudio uses the concept of a "device" as the abstraction for physical devices. The idea is that you choose a physical device to emit or capture audio from,
189 and then move data to/from the device when miniaudio tells you to. Data is delivered to and from devices asynchronously via a callback which you specify when
190 initializing the device.
191 
192 When initializing the device you first need to configure it. The device configuration allows you to specify things like the format of the data delivered via
193 the callback, the size of the internal buffer and the ID of the device you want to emit or capture audio from.
194 
195 Once you have the device configuration set up you can initialize the device. When initializing a device you need to allocate memory for the device object
196 beforehand. This gives the application complete control over how the memory is allocated. In the example below we initialize a playback device on the stack,
197 but you could allocate it on the heap if that suits your situation better.
198 
199  ```c
200  void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
201  {
202  // In playback mode copy data to pOutput. In capture mode read data from pInput. In full-duplex mode, both pOutput and pInput will be valid and you can
203  // move data from pInput into pOutput. Never process more than frameCount frames.
204  }
205 
206  ...
207 
208  ma_device_config config = ma_device_config_init(ma_device_type_playback);
209  config.playback.format = MY_FORMAT;
210  config.playback.channels = MY_CHANNEL_COUNT;
211  config.sampleRate = MY_SAMPLE_RATE;
212  config.dataCallback = data_callback;
213  config.pUserData = pMyCustomData; // Can be accessed from the device object (device.pUserData).
214 
215  ma_device device;
216  if (ma_device_init(NULL, &config, &device) != MA_SUCCESS) {
217  ... An error occurred ...
218  }
219 
220  ma_device_start(&device); // The device is sleeping by default so you'll need to start it manually.
221 
222  ...
223 
224  ma_device_uninit(&device); // This will stop the device so no need to do that manually.
225  ```
226 
227 In the example above, `data_callback()` is where audio data is written and read from the device. The idea is in playback mode you cause sound to be emitted
228 from the speakers by writing audio data to the output buffer (`pOutput` in the example). In capture mode you read data from the input buffer (`pInput`) to
229 extract sound captured by the microphone. The `frameCount` parameter tells you how many frames can be written to the output buffer and read from the input
230 buffer. A "frame" is one sample for each channel. For example, in a stereo stream (2 channels), one frame is 2 samples: one for the left, one for the right.
231 The channel count is defined by the device config. The size in bytes of an individual sample is defined by the sample format which is also specified in the
232 device config. Multi-channel audio data is always interleaved, which means the samples for each frame are stored next to each other in memory. For example, in
233 a stereo stream the first pair of samples will be the left and right samples for the first frame, the second pair of samples will be the left and right samples
234 for the second frame, etc.
235 
236 The configuration of the device is defined by the `ma_device_config` structure. The config object is always initialized with `ma_device_config_init()`. It's
237 important to always initialize the config with this function as it initializes it with logical defaults and ensures your program doesn't break when new members
238 are added to the `ma_device_config` structure. The example above uses a fairly simple and standard device configuration. The call to `ma_device_config_init()`
239 takes a single parameter, which is whether or not the device is a playback, capture, duplex or loopback device (loopback devices are not supported on all
240 backends). The `config.playback.format` member sets the sample format which can be one of the following (all formats are native-endian):
241 
242  |---------------|----------------------------------------|---------------------------|
243  | Symbol | Description | Range |
244  |---------------|----------------------------------------|---------------------------|
245  | ma_format_f32 | 32-bit floating point | [-1, 1] |
246  | ma_format_s16 | 16-bit signed integer | [-32768, 32767] |
247  | ma_format_s24 | 24-bit signed integer (tightly packed) | [-8388608, 8388607] |
248  | ma_format_s32 | 32-bit signed integer | [-2147483648, 2147483647] |
249  | ma_format_u8 | 8-bit unsigned integer | [0, 255] |
250  |---------------|----------------------------------------|---------------------------|
251 
252 The `config.playback.channels` member sets the number of channels to use with the device. The channel count cannot exceed MA_MAX_CHANNELS. The
253 `config.sampleRate` member sets the sample rate (which must be the same for both playback and capture in full-duplex configurations). This is usually set to
254 44100 or 48000, but can be set to anything. It's recommended to keep this between 8000 and 384000, however.
255 
256 Note that leaving the format, channel count and/or sample rate at their default values will result in the internal device's native configuration being used
257 which is useful if you want to avoid the overhead of miniaudio's automatic data conversion.
258 
259 In addition to the sample format, channel count and sample rate, the data callback and user data pointer are also set via the config. The user data pointer is
260 not passed into the callback as a parameter, but is instead set to the `pUserData` member of `ma_device` which you can access directly since all miniaudio
261 structures are transparent.
262 
263 Initializing the device is done with `ma_device_init()`. This will return a result code telling you what went wrong, if anything. On success it will return
264 `MA_SUCCESS`. After initialization is complete the device will be in a stopped state. To start it, use `ma_device_start()`. Uninitializing the device will stop
265 it, which is what the example above does, but you can also stop the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again.
266 Note that it's important to never stop or start the device from inside the callback. This will result in a deadlock. Instead you set a variable or signal an
267 event indicating that the device needs to stop and handle it in a different thread. The following APIs must never be called inside the callback:
268 
269  ma_device_init()
270  ma_device_init_ex()
271  ma_device_uninit()
272  ma_device_start()
273  ma_device_stop()
274 
275 You must never try uninitializing and reinitializing a device inside the callback. You must also never try to stop and start it from inside the callback. There
276 are a few other things you shouldn't do in the callback depending on your requirements, however this isn't so much a thread-safety thing, but rather a real-
277 time processing thing which is beyond the scope of this introduction.
278 
279 The example above demonstrates the initialization of a playback device, but it works exactly the same for capture. All you need to do is change the device type
280 from `ma_device_type_playback` to `ma_device_type_capture` when setting up the config, like so:
281 
282  ```c
283  ma_device_config config = ma_device_config_init(ma_device_type_capture);
284  config.capture.format = MY_FORMAT;
285  config.capture.channels = MY_CHANNEL_COUNT;
286  ```
287 
288 In the data callback you just read from the input buffer (`pInput` in the example above) and leave the output buffer alone (it will be set to NULL when the
289 device type is set to `ma_device_type_capture`).
290 
291 These are the available device types and how you should handle the buffers in the callback:
292 
293  |-------------------------|--------------------------------------------------------|
294  | Device Type | Callback Behavior |
295  |-------------------------|--------------------------------------------------------|
296  | ma_device_type_playback | Write to output buffer, leave input buffer untouched. |
297  | ma_device_type_capture | Read from input buffer, leave output buffer untouched. |
298  | ma_device_type_duplex | Read from input buffer, write to output buffer. |
299  | ma_device_type_loopback | Read from input buffer, leave output buffer untouched. |
300  |-------------------------|--------------------------------------------------------|
301 
302 You will notice in the example above that the sample format and channel count is specified separately for playback and capture. This is to support different
303 data formats between the playback and capture devices in a full-duplex system. An example may be that you want to capture audio data as a monaural stream (one
304 channel), but output sound to a stereo speaker system. Note that if you use different formats between playback and capture in a full-duplex configuration you
305 will need to convert the data yourself. There are functions available to help you do this which will be explained later.
306 
307 The example above did not specify a physical device to connect to which means it will use the operating system's default device. If you have multiple physical
308 devices connected and you want to use a specific one you will need to specify the device ID in the configuration, like so:
309 
310  ```
311  config.playback.pDeviceID = pMyPlaybackDeviceID; // Only if requesting a playback or duplex device.
312  config.capture.pDeviceID = pMyCaptureDeviceID; // Only if requesting a capture, duplex or loopback device.
313  ```
314 
315 To retrieve the device ID you will need to perform device enumeration, however this requires the use of a new concept call the "context". Conceptually speaking
316 the context sits above the device. There is one context to many devices. The purpose of the context is to represent the backend at a more global level and to
317 perform operations outside the scope of an individual device. Mainly it is used for performing run-time linking against backend libraries, initializing
318 backends and enumerating devices. The example below shows how to enumerate devices.
319 
320  ```c
321  ma_context context;
322  if (ma_context_init(NULL, 0, NULL, &context) != MA_SUCCESS) {
323  // Error.
324  }
325 
326  ma_device_info* pPlaybackDeviceInfos;
327  ma_uint32 playbackDeviceCount;
328  ma_device_info* pCaptureDeviceInfos;
329  ma_uint32 captureDeviceCount;
330  if (ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, &pCaptureDeviceInfos, &captureDeviceCount) != MA_SUCCESS) {
331  // Error.
332  }
333 
334  // Loop over the each device info and do something with it. Here we just print the name with their index. You may want to give the user the
335  // opportunity to choose which device they'd prefer.
336  for (ma_uint32 iDevice = 0; iDevice < playbackDeviceCount; iDevice += 1) {
337  printf("%d - %s\n", iDevice, pPlaybackDeviceInfos[iDevice].name);
338  }
339 
340  ma_device_config config = ma_device_config_init(ma_device_type_playback);
341  config.playback.pDeviceID = &pPlaybackDeviceInfos[chosenPlaybackDeviceIndex].id;
342  config.playback.format = MY_FORMAT;
343  config.playback.channels = MY_CHANNEL_COUNT;
344  config.sampleRate = MY_SAMPLE_RATE;
345  config.dataCallback = data_callback;
346  config.pUserData = pMyCustomData;
347 
348  ma_device device;
349  if (ma_device_init(&context, &config, &device) != MA_SUCCESS) {
350  // Error
351  }
352 
353  ...
354 
355  ma_device_uninit(&device);
356  ma_context_uninit(&context);
357  ```
358 
359 The first thing we do in this example is initialize a `ma_context` object with `ma_context_init()`. The first parameter is a pointer to a list of `ma_backend`
360 values which are used to override the default backend priorities. When this is NULL, as in this example, miniaudio's default priorities are used. The second
361 parameter is the number of backends listed in the array pointed to by the first paramter. The third parameter is a pointer to a `ma_context_config` object
362 which can be NULL, in which case defaults are used. The context configuration is used for setting the logging callback, custom memory allocation callbacks,
363 user-defined data and some backend-specific configurations.
364 
365 Once the context has been initialized you can enumerate devices. In the example above we use the simpler `ma_context_get_devices()`, however you can also use a
366 callback for handling devices by using `ma_context_enumerate_devices()`. When using `ma_context_get_devices()` you provide a pointer to a pointer that will,
367 upon output, be set to a pointer to a buffer containing a list of `ma_device_info` structures. You also provide a pointer to an unsigned integer that will
368 receive the number of items in the returned buffer. Do not free the returned buffers as their memory is managed internally by miniaudio.
369 
370 The `ma_device_info` structure contains an `id` member which is the ID you pass to the device config. It also contains the name of the device which is useful
371 for presenting a list of devices to the user via the UI.
372 
373 When creating your own context you will want to pass it to `ma_device_init()` when initializing the device. Passing in NULL, like we do in the first example,
374 will result in miniaudio creating the context for you, which you don't want to do since you've already created a context. Note that internally the context is
375 only tracked by it's pointer which means you must not change the location of the `ma_context` object. If this is an issue, consider using `malloc()` to
376 allocate memory for the context.
377 
378 
379 
380 Building
381 ========
382 miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details.
383 
384 
385 Windows
386 -------
387 The Windows build should compile clean on all popular compilers without the need to configure any include paths nor link to any libraries.
388 
389 macOS and iOS
390 -------------
391 The macOS build should compile clean without the need to download any dependencies or link to any libraries or frameworks. The iOS build needs to be compiled
392 as Objective-C (sorry) and will need to link the relevant frameworks but should Just Work with Xcode. Compiling through the command line requires linking to
393 -lpthread and -lm.
394 
395 Linux
396 -----
397 The Linux build only requires linking to -ldl, -lpthread and -lm. You do not need any development packages.
398 
399 BSD
400 ---
401 The BSD build only requires linking to -lpthread and -lm. NetBSD uses audio(4), OpenBSD uses sndio and FreeBSD uses OSS.
402 
403 Android
404 -------
405 AAudio is the highest priority backend on Android. This should work out out of the box without needing any kind of compiler configuration. Support for AAudio
406 starts with Android 8 which means older versions will fall back to OpenSL|ES which requires API level 16+.
407 
408 Emscripten
409 ----------
410 The Emscripten build emits Web Audio JavaScript directly and should Just Work without any configuration. You cannot use -std=c* compiler flags, nor -ansi.
411 
412 
413 Build Options
414 -------------
415 #define these options before including miniaudio.h.
416 
417 #define MA_NO_WASAPI
418  Disables the WASAPI backend.
419 
420 #define MA_NO_DSOUND
421  Disables the DirectSound backend.
422 
423 #define MA_NO_WINMM
424  Disables the WinMM backend.
425 
426 #define MA_NO_ALSA
427  Disables the ALSA backend.
428 
429 #define MA_NO_PULSEAUDIO
430  Disables the PulseAudio backend.
431 
432 #define MA_NO_JACK
433  Disables the JACK backend.
434 
435 #define MA_NO_COREAUDIO
436  Disables the Core Audio backend.
437 
438 #define MA_NO_SNDIO
439  Disables the sndio backend.
440 
441 #define MA_NO_AUDIO4
442  Disables the audio(4) backend.
443 
444 #define MA_NO_OSS
445  Disables the OSS backend.
446 
447 #define MA_NO_AAUDIO
448  Disables the AAudio backend.
449 
450 #define MA_NO_OPENSL
451  Disables the OpenSL|ES backend.
452 
453 #define MA_NO_WEBAUDIO
454  Disables the Web Audio backend.
455 
456 #define MA_NO_NULL
457  Disables the null backend.
458 
459 #define MA_NO_DECODING
460  Disables the decoding APIs.
461 
462 #define MA_NO_DEVICE_IO
463  Disables playback and recording. This will disable ma_context and ma_device APIs. This is useful if you only want to use miniaudio's data conversion and/or
464  decoding APIs.
465 
466 #define MA_NO_STDIO
467  Disables file IO APIs.
468 
469 #define MA_NO_SSE2
470  Disables SSE2 optimizations.
471 
472 #define MA_NO_AVX2
473  Disables AVX2 optimizations.
474 
475 #define MA_NO_AVX512
476  Disables AVX-512 optimizations.
477 
478 #define MA_NO_NEON
479  Disables NEON optimizations.
480 
481 #define MA_LOG_LEVEL <Level>
482  Sets the logging level. Set level to one of the following:
483  MA_LOG_LEVEL_VERBOSE
484  MA_LOG_LEVEL_INFO
485  MA_LOG_LEVEL_WARNING
486  MA_LOG_LEVEL_ERROR
487 
488 #define MA_DEBUG_OUTPUT
489  Enable printf() debug output.
490 
491 #define MA_COINIT_VALUE
492  Windows only. The value to pass to internal calls to CoInitializeEx(). Defaults to COINIT_MULTITHREADED.
493 
494 
495 
496 Definitions
497 ===========
498 This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity in the use of terms throughout the audio space, so this
499 section is intended to clarify how miniaudio uses each term.
500 
501 Sample
502 ------
503 A sample is a single unit of audio data. If the sample format is f32, then one sample is one 32-bit floating point number.
504 
505 Frame / PCM Frame
506 -----------------
507 A frame is a groups of samples equal to the number of channels. For a stereo stream a frame is 2 samples, a mono frame is 1 sample, a 5.1 surround sound frame
508 is 6 samples, etc. The terms "frame" and "PCM frame" are the same thing in miniaudio. Note that this is different to a compressed frame. If ever miniaudio
509 needs to refer to a compressed frame, such as a FLAC frame, it will always clarify what it's referring to with something like "FLAC frame" or whatnot.
510 
511 Channel
512 -------
513 A stream of monaural audio that is emitted from an individual speaker in a speaker system, or received from an individual microphone in a microphone system. A
514 stereo stream has two channels (a left channel, and a right channel), a 5.1 surround sound system has 6 channels, etc. Some audio systems refer to a channel as
515 a complex audio stream that's mixed with other channels to produce the final mix - this is completely different to miniaudio's use of the term "channel" and
516 should not be confused.
517 
518 Sample Rate
519 -----------
520 The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It's the number of PCM frames that are processed per second.
521 
522 Formats
523 -------
524 Throughout miniaudio you will see references to different sample formats:
525 
526  |---------------|----------------------------------------|---------------------------|
527  | Symbol | Description | Range |
528  |---------------|----------------------------------------|---------------------------|
529  | ma_format_f32 | 32-bit floating point | [-1, 1] |
530  | ma_format_s16 | 16-bit signed integer | [-32768, 32767] |
531  | ma_format_s24 | 24-bit signed integer (tightly packed) | [-8388608, 8388607] |
532  | ma_format_s32 | 32-bit signed integer | [-2147483648, 2147483647] |
533  | ma_format_u8 | 8-bit unsigned integer | [0, 255] |
534  |---------------|----------------------------------------|---------------------------|
535 
536 All formats are native-endian.
537 
538 
539 
540 Decoding
541 ========
542 The `ma_decoder` API is used for reading audio files. To enable a decoder you must #include the header of the relevant backend library before the
543 implementation of miniaudio. You can find copies of these in the "extras" folder in the miniaudio repository (https://github.com/dr-soft/miniaudio).
544 
545 The table below are the supported decoding backends:
546 
547  |--------|-----------------|
548  | Type | Backend Library |
549  |--------|-----------------|
550  | WAV | dr_wav.h |
551  | FLAC | dr_flac.h |
552  | MP3 | dr_mp3.h |
553  | Vorbis | stb_vorbis.c |
554  |--------|-----------------|
555 
556 The code below is an example of how to enable decoding backends:
557 
558  ```c
559  #include "dr_flac.h" // Enables FLAC decoding.
560  #include "dr_mp3.h" // Enables MP3 decoding.
561  #include "dr_wav.h" // Enables WAV decoding.
562 
563  #define MINIAUDIO_IMPLEMENTATION
564  #include "miniaudio.h"
565  ```
566 
567 A decoder can be initialized from a file with `ma_decoder_init_file()`, a block of memory with `ma_decoder_init_memory()`, or from data delivered via callbacks
568 with `ma_decoder_init()`. Here is an example for loading a decoder from a file:
569 
570  ```c
571  ma_decoder decoder;
572  ma_result result = ma_decoder_init_file("MySong.mp3", NULL, &decoder);
573  if (result != MA_SUCCESS) {
574  return false; // An error occurred.
575  }
576 
577  ...
578 
579  ma_decoder_uninit(&decoder);
580  ```
581 
582 When initializing a decoder, you can optionally pass in a pointer to a ma_decoder_config object (the NULL argument in the example above) which allows you to
583 configure the output format, channel count, sample rate and channel map:
584 
585  ```c
586  ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 2, 48000);
587  ```
588 
589 When passing in NULL for decoder config in `ma_decoder_init*()`, the output format will be the same as that defined by the decoding backend.
590 
591 Data is read from the decoder as PCM frames:
592 
593  ```c
594  ma_uint64 framesRead = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead);
595  ```
596 
597 You can also seek to a specific frame like so:
598 
599  ```c
600  ma_result result = ma_decoder_seek_to_pcm_frame(pDecoder, targetFrame);
601  if (result != MA_SUCCESS) {
602  return false; // An error occurred.
603  }
604  ```
605 
606 When loading a decoder, miniaudio uses a trial and error technique to find the appropriate decoding backend. This can be unnecessarily inefficient if the type
607 is already known. In this case you can use the `_wav`, `_mp3`, etc. varients of the aforementioned initialization APIs:
608 
609  ```c
610  ma_decoder_init_wav()
611  ma_decoder_init_mp3()
612  ma_decoder_init_memory_wav()
613  ma_decoder_init_memory_mp3()
614  ma_decoder_init_file_wav()
615  ma_decoder_init_file_mp3()
616  etc.
617  ```
618 
619 The `ma_decoder_init_file()` API will try using the file extension to determine which decoding backend to prefer.
620 
621 
622 
623 Encoding
624 ========
625 The `ma_encoding` API is used for writing audio files. To enable an encoder you must #include the header of the relevant backend library before the
626 implementation of miniaudio. You can find copies of these in the "extras" folder in the miniaudio repository (https://github.com/dr-soft/miniaudio).
627 
628 The table below are the supported encoding backends:
629 
630  |--------|-----------------|
631  | Type | Backend Library |
632  |--------|-----------------|
633  | WAV | dr_wav.h |
634  |--------|-----------------|
635 
636 The code below is an example of how to enable encoding backends:
637 
638  ```c
639  #include "dr_wav.h" // Enables WAV decoding.
640 
641  #define MINIAUDIO_IMPLEMENTATION
642  #include "miniaudio.h"
643  ```
644 
645 An encoder can be initialized to write to a file with `ma_encoder_init_file()` or from data delivered via callbacks with `ma_encoder_init()`. Below is an
646 example for initializing an encoder to output to a file.
647 
648  ```c
649  ma_encoder_config config = ma_encoder_config_init(ma_resource_format_wav, FORMAT, CHANNELS, SAMPLE_RATE);
650  ma_encoder encoder;
651  ma_result result = ma_encoder_init_file("my_file.wav", &config, &encoder);
652  if (result != MA_SUCCESS) {
653  // Error
654  }
655 
656  ...
657 
658  ma_encoder_uninit(&encoder);
659  ```
660 
661 When initializing an encoder you must specify a config which is initialized with `ma_encoder_config_init()`. Here you must specify the file type, the output
662 sample format, output channel count and output sample rate. The following file types are supported:
663 
664  |------------------------|-------------|
665  | Enum | Description |
666  |------------------------|-------------|
667  | ma_resource_format_wav | WAV |
668  |------------------------|-------------|
669 
670 If the format, channel count or sample rate is not supported by the output file type an error will be returned. The encoder will not perform data conversion so
671 you will need to convert it before outputting any audio data. To output audio data, use `ma_encoder_write_pcm_frames()`, like in the example below:
672 
673  ```c
674  framesWritten = ma_encoder_write_pcm_frames(&encoder, pPCMFramesToWrite, framesToWrite);
675  ```
676 
677 Encoders must be uninitialized with `ma_encoder_uninit()`.
678 
679 
680 
681 Sample Format Conversion
682 ========================
683 Conversion between sample formats is achieved with the `ma_pcm_*_to_*()`, `ma_pcm_convert()` and `ma_convert_pcm_frames_format()` APIs. Use `ma_pcm_*_to_*()`
684 to convert between two specific formats. Use `ma_pcm_convert()` to convert based on a `ma_format` variable. Use `ma_convert_pcm_frames_format()` to convert
685 PCM frames where you want to specify the frame count and channel count as a variable instead of the total sample count.
686 
687 Dithering
688 ---------
689 Dithering can be set using ditherMode parameter.
690 
691 The different dithering modes include the following, in order of efficiency:
692 
693  |-----------|--------------------------|
694  | Type | Enum Token |
695  |-----------|--------------------------|
696  | None | ma_dither_mode_none |
697  | Rectangle | ma_dither_mode_rectangle |
698  | Triangle | ma_dither_mode_triangle |
699  |-----------|--------------------------|
700 
701 Note that even if the dither mode is set to something other than `ma_dither_mode_none`, it will be ignored for conversions where dithering is not needed.
702 Dithering is available for the following conversions:
703 
704  s16 -> u8
705  s24 -> u8
706  s32 -> u8
707  f32 -> u8
708  s24 -> s16
709  s32 -> s16
710  f32 -> s16
711 
712 Note that it is not an error to pass something other than ma_dither_mode_none for conversions where dither is not used. It will just be ignored.
713 
714 
715 
716 Channel Conversion
717 ==================
718 Channel conversion is used for channel rearrangement and conversion from one channel count to another. The `ma_channel_converter` API is used for channel
719 conversion. Below is an example of initializing a simple channel converter which converts from mono to stereo.
720 
721  ```c
722  ma_channel_converter_config config = ma_channel_converter_config_init(ma_format, 1, NULL, 2, NULL, ma_channel_mix_mode_default, NULL);
723  result = ma_channel_converter_init(&config, &converter);
724  if (result != MA_SUCCESS) {
725  // Error.
726  }
727  ```
728 
729 To perform the conversion simply call `ma_channel_converter_process_pcm_frames()` like so:
730 
731  ```c
732  ma_result result = ma_channel_converter_process_pcm_frames(&converter, pFramesOut, pFramesIn, frameCount);
733  if (result != MA_SUCCESS) {
734  // Error.
735  }
736  ```
737 
738 It is up to the caller to ensure the output buffer is large enough to accomodate the new PCM frames.
739 
740 The only formats supported are `ma_format_s16` and `ma_format_f32`. If you need another format you need to convert your data manually which you can do with
741 `ma_pcm_convert()`, etc.
742 
743 Input and output PCM frames are always interleaved. Deinterleaved layouts are not supported.
744 
745 
746 Channel Mapping
747 ---------------
748 In addition to converting from one channel count to another, like the example above, The channel converter can also be used to rearrange channels. When
749 initializing the channel converter, you can optionally pass in channel maps for both the input and output frames. If the channel counts are the same, and each
750 channel map contains the same channel positions with the exception that they're in a different order, a simple shuffling of the channels will be performed. If,
751 however, there is not a 1:1 mapping of channel positions, or the channel counts differ, the input channels will be mixed based on a mixing mode which is
752 specified when initializing the `ma_channel_converter_config` object.
753 
754 When converting from mono to multi-channel, the mono channel is simply copied to each output channel. When going the other way around, the audio of each output
755 channel is simply averaged and copied to the mono channel.
756 
757 In more complicated cases blending is used. The `ma_channel_mix_mode_simple` mode will drop excess channels and silence extra channels. For example, converting
758 from 4 to 2 channels, the 3rd and 4th channels will be dropped, whereas converting from 2 to 4 channels will put silence into the 3rd and 4th channels.
759 
760 The `ma_channel_mix_mode_rectangle` mode uses spacial locality based on a rectangle to compute a simple distribution between input and output. Imagine sitting
761 in the middle of a room, with speakers on the walls representing channel positions. The MA_CHANNEL_FRONT_LEFT position can be thought of as being in the corner
762 of the front and left walls.
763 
764 Finally, the `ma_channel_mix_mode_custom_weights` mode can be used to use custom user-defined weights. Custom weights can be passed in as the last parameter of
765 `ma_channel_converter_config_init()`.
766 
767 Predefined channel maps can be retrieved with `ma_get_standard_channel_map()`. This takes a `ma_standard_channel_map` enum as it's first parameter, which can
768 be one of the following:
769 
770  |-----------------------------------|-----------------------------------------------------------|
771  | Name | Description |
772  |-----------------------------------|-----------------------------------------------------------|
773  | ma_standard_channel_map_default | Default channel map used by miniaudio. See below. |
774  | ma_standard_channel_map_microsoft | Channel map used by Microsoft's bitfield channel maps. |
775  | ma_standard_channel_map_alsa | Default ALSA channel map. |
776  | ma_standard_channel_map_rfc3551 | RFC 3551. Based on AIFF. |
777  | ma_standard_channel_map_flac | FLAC channel map. |
778  | ma_standard_channel_map_vorbis | Vorbis channel map. |
779  | ma_standard_channel_map_sound4 | FreeBSD's sound(4). |
780  | ma_standard_channel_map_sndio | sndio channel map. www.sndio.org/tips.html |
781  | ma_standard_channel_map_webaudio | https://webaudio.github.io/web-audio-api/#ChannelOrdering |
782  |-----------------------------------|-----------------------------------------------------------|
783 
784 Below are the channel maps used by default in miniaudio (ma_standard_channel_map_default):
785 
786  |---------------|------------------------------|
787  | Channel Count | Mapping |
788  |---------------|------------------------------|
789  | 1 (Mono) | 0: MA_CHANNEL_MONO |
790  |---------------|------------------------------|
791  | 2 (Stereo) | 0: MA_CHANNEL_FRONT_LEFT |
792  | | 1: MA_CHANNEL_FRONT_RIGHT |
793  |---------------|------------------------------|
794  | 3 | 0: MA_CHANNEL_FRONT_LEFT |
795  | | 1: MA_CHANNEL_FRONT_RIGHT |
796  | | 2: MA_CHANNEL_FRONT_CENTER |
797  |---------------|------------------------------|
798  | 4 (Surround) | 0: MA_CHANNEL_FRONT_LEFT |
799  | | 1: MA_CHANNEL_FRONT_RIGHT |
800  | | 2: MA_CHANNEL_FRONT_CENTER |
801  | | 3: MA_CHANNEL_BACK_CENTER |
802  |---------------|------------------------------|
803  | 5 | 0: MA_CHANNEL_FRONT_LEFT |
804  | | 1: MA_CHANNEL_FRONT_RIGHT |
805  | | 2: MA_CHANNEL_FRONT_CENTER |
806  | | 3: MA_CHANNEL_BACK_LEFT |
807  | | 4: MA_CHANNEL_BACK_RIGHT |
808  |---------------|------------------------------|
809  | 6 (5.1) | 0: MA_CHANNEL_FRONT_LEFT |
810  | | 1: MA_CHANNEL_FRONT_RIGHT |
811  | | 2: MA_CHANNEL_FRONT_CENTER |
812  | | 3: MA_CHANNEL_LFE |
813  | | 4: MA_CHANNEL_SIDE_LEFT |
814  | | 5: MA_CHANNEL_SIDE_RIGHT |
815  |---------------|------------------------------|
816  | 7 | 0: MA_CHANNEL_FRONT_LEFT |
817  | | 1: MA_CHANNEL_FRONT_RIGHT |
818  | | 2: MA_CHANNEL_FRONT_CENTER |
819  | | 3: MA_CHANNEL_LFE |
820  | | 4: MA_CHANNEL_BACK_CENTER |
821  | | 4: MA_CHANNEL_SIDE_LEFT |
822  | | 5: MA_CHANNEL_SIDE_RIGHT |
823  |---------------|------------------------------|
824  | 8 (7.1) | 0: MA_CHANNEL_FRONT_LEFT |
825  | | 1: MA_CHANNEL_FRONT_RIGHT |
826  | | 2: MA_CHANNEL_FRONT_CENTER |
827  | | 3: MA_CHANNEL_LFE |
828  | | 4: MA_CHANNEL_BACK_LEFT |
829  | | 5: MA_CHANNEL_BACK_RIGHT |
830  | | 6: MA_CHANNEL_SIDE_LEFT |
831  | | 7: MA_CHANNEL_SIDE_RIGHT |
832  |---------------|------------------------------|
833  | Other | All channels set to 0. This |
834  | | is equivalent to the same |
835  | | mapping as the device. |
836  |---------------|------------------------------|
837 
838 
839 
840 Resampling
841 ==========
842 Resampling is achieved with the `ma_resampler` object. To create a resampler object, do something like the following:
843 
844  ```c
845  ma_resampler_config config = ma_resampler_config_init(ma_format_s16, channels, sampleRateIn, sampleRateOut, ma_resample_algorithm_linear);
846  ma_resampler resampler;
847  ma_result result = ma_resampler_init(&config, &resampler);
848  if (result != MA_SUCCESS) {
849  // An error occurred...
850  }
851  ```
852 
853 Do the following to uninitialize the resampler:
854 
855  ```c
856  ma_resampler_uninit(&resampler);
857  ```
858 
859 The following example shows how data can be processed
860 
861  ```c
862  ma_uint64 frameCountIn = 1000;
863  ma_uint64 frameCountOut = 2000;
864  ma_result result = ma_resampler_process_pcm_frames(&resampler, pFramesIn, &frameCountIn, pFramesOut, &frameCountOut);
865  if (result != MA_SUCCESS) {
866  // An error occurred...
867  }
868 
869  // At this point, frameCountIn contains the number of input frames that were consumed and frameCountOut contains the number of output frames written.
870  ```
871 
872 To initialize the resampler you first need to set up a config (`ma_resampler_config`) with `ma_resampler_config_init()`. You need to specify the sample format
873 you want to use, the number of channels, the input and output sample rate, and the algorithm.
874 
875 The sample format can be either `ma_format_s16` or `ma_format_f32`. If you need a different format you will need to perform pre- and post-conversions yourself
876 where necessary. Note that the format is the same for both input and output. The format cannot be changed after initialization.
877 
878 The resampler supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization.
879 
880 The sample rates can be anything other than zero, and are always specified in hertz. They should be set to something like 44100, etc. The sample rate is the
881 only configuration property that can be changed after initialization.
882 
883 The miniaudio resampler supports multiple algorithms:
884 
885  |-----------|------------------------------|
886  | Algorithm | Enum Token |
887  |-----------|------------------------------|
888  | Linear | ma_resample_algorithm_linear |
889  | Speex | ma_resample_algorithm_speex |
890  |-----------|------------------------------|
891 
892 Because Speex is not public domain it is strictly opt-in and the code is stored in separate files. if you opt-in to the Speex backend you will need to consider
893 it's license, the text of which can be found in it's source files in "extras/speex_resampler". Details on how to opt-in to the Speex resampler is explained in
894 the Speex Resampler section below.
895 
896 The algorithm cannot be changed after initialization.
897 
898 Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process
899 frames, use `ma_resampler_process_pcm_frames()`. On input, this function takes the number of output frames you can fit in the output buffer and the number of
900 input frames contained in the input buffer. On output these variables contain the number of output frames that were written to the output buffer and the
901 number of input frames that were consumed in the process. You can pass in NULL for the input buffer in which case it will be treated as an infinitely large
902 buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek.
903 
904 The sample rate can be changed dynamically on the fly. You can change this with explicit sample rates with `ma_resampler_set_rate()` and also with a decimal
905 ratio with `ma_resampler_set_rate_ratio()`. The ratio is in/out.
906 
907 Sometimes it's useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with
908 `ma_resampler_get_required_input_frame_count()`. Likewise, it's sometimes useful to know exactly how many frames would be output given a certain number of
909 input frames. You can do this with `ma_resampler_get_expected_output_frame_count()`.
910 
911 Due to the nature of how resampling works, the resampler introduces some latency. This can be retrieved in terms of both the input rate and the output rate
912 with `ma_resampler_get_input_latency()` and `ma_resampler_get_output_latency()`.
913 
914 
915 Resampling Algorithms
916 ---------------------
917 The choice of resampling algorithm depends on your situation and requirements. The linear resampler is the most efficient and has the least amount of latency,
918 but at the expense of poorer quality. The Speex resampler is higher quality, but slower with more latency. It also performs several heap allocations internally
919 for memory management.
920 
921 
922 Linear Resampling
923 -----------------
924 The linear resampler is the fastest, but comes at the expense of poorer quality. There is, however, some control over the quality of the linear resampler which
925 may make it a suitable option depending on your requirements.
926 
927 The linear resampler performs low-pass filtering before or after downsampling or upsampling, depending on the sample rates you're converting between. When
928 decreasing the sample rate, the low-pass filter will be applied before downsampling. When increasing the rate it will be performed after upsampling. By default
929 a fourth order low-pass filter will be applied. This can be configured via the `lpfOrder` configuration variable. Setting this to 0 will disable filtering.
930 
931 The low-pass filter has a cutoff frequency which defaults to half the sample rate of the lowest of the input and output sample rates (Nyquist Frequency). This
932 can be controlled with the `lpfNyquistFactor` config variable. This defaults to 1, and should be in the range of 0..1, although a value of 0 does not make
933 sense and should be avoided. A value of 1 will use the Nyquist Frequency as the cutoff. A value of 0.5 will use half the Nyquist Frequency as the cutoff, etc.
934 Values less than 1 will result in more washed out sound due to more of the higher frequencies being removed. This config variable has no impact on performance
935 and is a purely perceptual configuration.
936 
937 The API for the linear resampler is the same as the main resampler API, only it's called `ma_linear_resampler`.
938 
939 
940 Speex Resampling
941 ----------------
942 The Speex resampler is made up of third party code which is released under the BSD license. Because it is licensed differently to miniaudio, which is public
943 domain, it is strictly opt-in and all of it's code is stored in separate files. If you opt-in to the Speex resampler you must consider the license text in it's
944 source files. To opt-in, you must first #include the following file before the implementation of miniaudio.h:
945 
946  #include "extras/speex_resampler/ma_speex_resampler.h"
947 
948 Both the header and implementation is contained within the same file. The implementation can be included in your program like so:
949 
950  #define MINIAUDIO_SPEEX_RESAMPLER_IMPLEMENTATION
951  #include "extras/speex_resampler/ma_speex_resampler.h"
952 
953 Note that even if you opt-in to the Speex backend, miniaudio won't use it unless you explicitly ask for it in the respective config of the object you are
954 initializing. If you try to use the Speex resampler without opting in, initialization of the `ma_resampler` object will fail with `MA_NO_BACKEND`.
955 
956 The only configuration option to consider with the Speex resampler is the `speex.quality` config variable. This is a value between 0 and 10, with 0 being
957 the fastest with the poorest quality and 10 being the slowest with the highest quality. The default value is 3.
958 
959 
960 
961 General Data Conversion
962 =======================
963 The `ma_data_converter` API can be used to wrap sample format conversion, channel conversion and resampling into one operation. This is what miniaudio uses
964 internally to convert between the format requested when the device was initialized and the format of the backend's native device. The API for general data
965 conversion is very similar to the resampling API. Create a `ma_data_converter` object like this:
966 
967  ```c
968  ma_data_converter_config config = ma_data_converter_config_init(inputFormat, outputFormat, inputChannels, outputChannels, inputSampleRate, outputSampleRate);
969  ma_data_converter converter;
970  ma_result result = ma_data_converter_init(&config, &converter);
971  if (result != MA_SUCCESS) {
972  // An error occurred...
973  }
974  ```
975 
976 In the example above we use `ma_data_converter_config_init()` to initialize the config, however there's many more properties that can be configured, such as
977 channel maps and resampling quality. Something like the following may be more suitable depending on your requirements:
978 
979  ```c
980  ma_data_converter_config config = ma_data_converter_config_init_default();
981  config.formatIn = inputFormat;
982  config.formatOut = outputFormat;
983  config.channelsIn = inputChannels;
984  config.channelsOut = outputChannels;
985  config.sampleRateIn = inputSampleRate;
986  config.sampleRateOut = outputSampleRate;
987  ma_get_standard_channel_map(ma_standard_channel_map_flac, config.channelCountIn, config.channelMapIn);
988  config.resampling.linear.lpfOrder = MA_MAX_FILTER_ORDER;
989  ```
990 
991 Do the following to uninitialize the data converter:
992 
993  ```c
994  ma_data_converter_uninit(&converter);
995  ```
996 
997 The following example shows how data can be processed
998 
999  ```c
1000  ma_uint64 frameCountIn = 1000;
1001  ma_uint64 frameCountOut = 2000;
1002  ma_result result = ma_data_converter_process_pcm_frames(&converter, pFramesIn, &frameCountIn, pFramesOut, &frameCountOut);
1003  if (result != MA_SUCCESS) {
1004  // An error occurred...
1005  }
1006 
1007  // At this point, frameCountIn contains the number of input frames that were consumed and frameCountOut contains the number of output frames written.
1008  ```
1009 
1010 The data converter supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization.
1011 
1012 Sample rates can be anything other than zero, and are always specified in hertz. They should be set to something like 44100, etc. The sample rate is the only
1013 configuration property that can be changed after initialization, but only if the `resampling.allowDynamicSampleRate` member of `ma_data_converter_config` is
1014 set to MA_TRUE. To change the sample rate, use `ma_data_converter_set_rate()` or `ma_data_converter_set_rate_ratio()`. The ratio must be in/out. The resampling
1015 algorithm cannot be changed after initialization.
1016 
1017 Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process
1018 frames, use `ma_data_converter_process_pcm_frames()`. On input, this function takes the number of output frames you can fit in the output buffer and the number
1019 of input frames contained in the input buffer. On output these variables contain the number of output frames that were written to the output buffer and the
1020 number of input frames that were consumed in the process. You can pass in NULL for the input buffer in which case it will be treated as an infinitely large
1021 buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek.
1022 
1023 Sometimes it's useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with
1024 `ma_data_converter_get_required_input_frame_count()`. Likewise, it's sometimes useful to know exactly how many frames would be output given a certain number of
1025 input frames. You can do this with `ma_data_converter_get_expected_output_frame_count()`.
1026 
1027 Due to the nature of how resampling works, the data converter introduces some latency if resampling is required. This can be retrieved in terms of both the
1028 input rate and the output rate with `ma_data_converter_get_input_latency()` and `ma_data_converter_get_output_latency()`.
1029 
1030 
1031 
1032 Filtering
1033 =========
1034 
1035 Biquad Filtering
1036 ----------------
1037 Biquad filtering is achieved with the `ma_biquad` API. Example:
1038 
1039  ```c
1040  ma_biquad_config config = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2);
1041  ma_result result = ma_biquad_init(&config, &biquad);
1042  if (result != MA_SUCCESS) {
1043  // Error.
1044  }
1045 
1046  ...
1047 
1048  ma_biquad_process_pcm_frames(&biquad, pFramesOut, pFramesIn, frameCount);
1049  ```
1050 
1051 Biquad filtering is implemented using transposed direct form 2. The numerator coefficients are b0, b1 and b2, and the denominator coefficients are a0, a1 and
1052 a2. The a0 coefficient is required and coefficients must not be pre-normalized.
1053 
1054 Supported formats are `ma_format_s16` and `ma_format_f32`. If you need to use a different format you need to convert it yourself beforehand. When using
1055 `ma_format_s16` the biquad filter will use fixed point arithmetic. When using `ma_format_f32`, floating point arithmetic will be used.
1056 
1057 Input and output frames are always interleaved.
1058 
1059 Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so:
1060 
1061  ```c
1062  ma_biquad_process_pcm_frames(&biquad, pMyData, pMyData, frameCount);
1063  ```
1064 
1065 If you need to change the values of the coefficients, but maintain the values in the registers you can do so with `ma_biquad_reinit()`. This is useful if you
1066 need to change the properties of the filter while keeping the values of registers valid to avoid glitching. Do not use `ma_biquad_init()` for this as it will
1067 do a full initialization which involves clearing the registers to 0. Note that changing the format or channel count after initialization is invalid and will
1068 result in an error.
1069 
1070 
1071 Low-Pass Filtering
1072 ------------------
1073 Low-pass filtering is achieved with the following APIs:
1074 
1075  |---------|------------------------------------------|
1076  | API | Description |
1077  |---------|------------------------------------------|
1078  | ma_lpf1 | First order low-pass filter |
1079  | ma_lpf2 | Second order low-pass filter |
1080  | ma_lpf | High order low-pass filter (Butterworth) |
1081  |---------|------------------------------------------|
1082 
1083 Low-pass filter example:
1084 
1085  ```c
1086  ma_lpf_config config = ma_lpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order);
1087  ma_result result = ma_lpf_init(&config, &lpf);
1088  if (result != MA_SUCCESS) {
1089  // Error.
1090  }
1091 
1092  ...
1093 
1094  ma_lpf_process_pcm_frames(&lpf, pFramesOut, pFramesIn, frameCount);
1095  ```
1096 
1097 Supported formats are `ma_format_s16` and` ma_format_f32`. If you need to use a different format you need to convert it yourself beforehand. Input and output
1098 frames are always interleaved.
1099 
1100 Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so:
1101 
1102  ```c
1103  ma_lpf_process_pcm_frames(&lpf, pMyData, pMyData, frameCount);
1104  ```
1105 
1106 The maximum filter order is limited to MA_MAX_FILTER_ORDER which is set to 8. If you need more, you can chain first and second order filters together.
1107 
1108  ```c
1109  for (iFilter = 0; iFilter < filterCount; iFilter += 1) {
1110  ma_lpf2_process_pcm_frames(&lpf2[iFilter], pMyData, pMyData, frameCount);
1111  }
1112  ```
1113 
1114 If you need to change the configuration of the filter, but need to maintain the state of internal registers you can do so with `ma_lpf_reinit()`. This may be
1115 useful if you need to change the sample rate and/or cutoff frequency dynamically while maintaing smooth transitions. Note that changing the format or channel
1116 count after initialization is invalid and will result in an error.
1117 
1118 The `ma_lpf` object supports a configurable order, but if you only need a first order filter you may want to consider using `ma_lpf1`. Likewise, if you only
1119 need a second order filter you can use `ma_lpf2`. The advantage of this is that they're lighter weight and a bit more efficient.
1120 
1121 If an even filter order is specified, a series of second order filters will be processed in a chain. If an odd filter order is specified, a first order filter
1122 will be applied, followed by a series of second order filters in a chain.
1123 
1124 
1125 High-Pass Filtering
1126 -------------------
1127 High-pass filtering is achieved with the following APIs:
1128 
1129  |---------|-------------------------------------------|
1130  | API | Description |
1131  |---------|-------------------------------------------|
1132  | ma_hpf1 | First order high-pass filter |
1133  | ma_hpf2 | Second order high-pass filter |
1134  | ma_hpf | High order high-pass filter (Butterworth) |
1135  |---------|-------------------------------------------|
1136 
1137 High-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_hpf1`, `ma_hpf2` and `ma_hpf`. See example code for low-pass filters
1138 for example usage.
1139 
1140 
1141 Band-Pass Filtering
1142 -------------------
1143 Band-pass filtering is achieved with the following APIs:
1144 
1145  |---------|-------------------------------|
1146  | API | Description |
1147  |---------|-------------------------------|
1148  | ma_bpf2 | Second order band-pass filter |
1149  | ma_bpf | High order band-pass filter |
1150  |---------|-------------------------------|
1151 
1152 Band-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_bpf2` and `ma_hpf`. See example code for low-pass filters for example
1153 usage. Note that the order for band-pass filters must be an even number which means there is no first order band-pass filter, unlike low-pass and high-pass
1154 filters.
1155 
1156 
1157 Notch Filtering
1158 ---------------
1159 Notch filtering is achieved with the following APIs:
1160 
1161  |-----------|------------------------------------------|
1162  | API | Description |
1163  |-----------|------------------------------------------|
1164  | ma_notch2 | Second order notching filter |
1165  |-----------|------------------------------------------|
1166 
1167 
1168 Peaking EQ Filtering
1169 --------------------
1170 Peaking filtering is achieved with the following APIs:
1171 
1172  |----------|------------------------------------------|
1173  | API | Description |
1174  |----------|------------------------------------------|
1175  | ma_peak2 | Second order peaking filter |
1176  |----------|------------------------------------------|
1177 
1178 
1179 Low Shelf Filtering
1180 -------------------
1181 Low shelf filtering is achieved with the following APIs:
1182 
1183  |-------------|------------------------------------------|
1184  | API | Description |
1185  |-------------|------------------------------------------|
1186  | ma_loshelf2 | Second order low shelf filter |
1187  |-------------|------------------------------------------|
1188 
1189 Where a high-pass filter is used to eliminate lower frequencies, a low shelf filter can be used to just turn them down rather than eliminate them entirely.
1190 
1191 
1192 High Shelf Filtering
1193 --------------------
1194 High shelf filtering is achieved with the following APIs:
1195 
1196  |-------------|------------------------------------------|
1197  | API | Description |
1198  |-------------|------------------------------------------|
1199  | ma_hishelf2 | Second order high shelf filter |
1200  |-------------|------------------------------------------|
1201 
1202 The high shelf filter has the same API as the low shelf filter, only you would use `ma_hishelf` instead of `ma_loshelf`. Where a low shelf filter is used to
1203 adjust the volume of low frequencies, the high shelf filter does the same thing for high frequencies.
1204 
1205 
1206 
1207 
1208 Waveform and Noise Generation
1209 =============================
1210 
1211 Waveforms
1212 ---------
1213 miniaudio supports generation of sine, square, triangle and sawtooth waveforms. This is achieved with the `ma_waveform` API. Example:
1214 
1215  ```c
1216  ma_waveform_config config = ma_waveform_config_init(FORMAT, CHANNELS, SAMPLE_RATE, ma_waveform_type_sine, amplitude, frequency);
1217 
1218  ma_waveform waveform;
1219  ma_result result = ma_waveform_init(&config, &waveform);
1220  if (result != MA_SUCCESS) {
1221  // Error.
1222  }
1223 
1224  ...
1225 
1226  ma_waveform_read_pcm_frames(&waveform, pOutput, frameCount);
1227  ```
1228 
1229 The amplitude, frequency and sample rate can be changed dynamically with `ma_waveform_set_amplitude()`, `ma_waveform_set_frequency()` and
1230 `ma_waveform_set_sample_rate()` respectively.
1231 
1232 You can reverse the waveform by setting the amplitude to a negative value. You can use this to control whether or not a sawtooth has a positive or negative
1233 ramp, for example.
1234 
1235 Below are the supported waveform types:
1236 
1237  |---------------------------|
1238  | Enum Name |
1239  |---------------------------|
1240  | ma_waveform_type_sine |
1241  | ma_waveform_type_square |
1242  | ma_waveform_type_triangle |
1243  | ma_waveform_type_sawtooth |
1244  |---------------------------|
1245 
1246 
1247 
1248 Noise
1249 -----
1250 miniaudio supports generation of white, pink and brownian noise via the `ma_noise` API. Example:
1251 
1252  ```c
1253  ma_noise_config config = ma_noise_config_init(FORMAT, CHANNELS, ma_noise_type_white, SEED, amplitude);
1254 
1255  ma_noise noise;
1256  ma_result result = ma_noise_init(&config, &noise);
1257  if (result != MA_SUCCESS) {
1258  // Error.
1259  }
1260 
1261  ...
1262 
1263  ma_noise_read_pcm_frames(&noise, pOutput, frameCount);
1264  ```
1265 
1266 The noise API uses simple LCG random number generation. It supports a custom seed which is useful for things like automated testing requiring reproducibility.
1267 Setting the seed to zero will default to MA_DEFAULT_LCG_SEED.
1268 
1269 By default, the noise API will use different values for different channels. So, for example, the left side in a stereo stream will be different to the right
1270 side. To instead have each channel use the same random value, set the `duplicateChannels` member of the noise config to true, like so:
1271 
1272  ```c
1273  config.duplicateChannels = MA_TRUE;
1274  ```
1275 
1276 Below are the supported noise types.
1277 
1278  |------------------------|
1279  | Enum Name |
1280  |------------------------|
1281  | ma_noise_type_white |
1282  | ma_noise_type_pink |
1283  | ma_noise_type_brownian |
1284  |------------------------|
1285 
1286 
1287 
1288 Ring Buffers
1289 ============
1290 miniaudio supports lock free (single producer, single consumer) ring buffers which are exposed via the `ma_rb` and `ma_pcm_rb` APIs. The `ma_rb` API operates
1291 on bytes, whereas the `ma_pcm_rb` operates on PCM frames. They are otherwise identical as `ma_pcm_rb` is just a wrapper around `ma_rb`.
1292 
1293 Unlike most other APIs in miniaudio, ring buffers support both interleaved and deinterleaved streams. The caller can also allocate their own backing memory for
1294 the ring buffer to use internally for added flexibility. Otherwise the ring buffer will manage it's internal memory for you.
1295 
1296 The examples below use the PCM frame variant of the ring buffer since that's most likely the one you will want to use. To initialize a ring buffer, do
1297 something like the following:
1298 
1299  ```c
1300  ma_pcm_rb rb;
1301  ma_result result = ma_pcm_rb_init(FORMAT, CHANNELS, BUFFER_SIZE_IN_FRAMES, NULL, NULL, &rb);
1302  if (result != MA_SUCCESS) {
1303  // Error
1304  }
1305  ```
1306 
1307 The `ma_pcm_rb_init()` function takes the sample format and channel count as parameters because it's the PCM varient of the ring buffer API. For the regular
1308 ring buffer that operates on bytes you would call `ma_rb_init()` which leaves these out and just takes the size of the buffer in bytes instead of frames. The
1309 fourth parameter is an optional pre-allocated buffer and the fifth parameter is a pointer to a `ma_allocation_callbacks` structure for custom memory allocation
1310 routines. Passing in NULL for this results in MA_MALLOC() and MA_FREE() being used.
1311 
1312 Use `ma_pcm_rb_init_ex()` if you need a deinterleaved buffer. The data for each sub-buffer is offset from each other based on the stride. To manage your sub-
1313 buffers you can use `ma_pcm_rb_get_subbuffer_stride()`, `ma_pcm_rb_get_subbuffer_offset()` and `ma_pcm_rb_get_subbuffer_ptr()`.
1314 
1315 Use 'ma_pcm_rb_acquire_read()` and `ma_pcm_rb_acquire_write()` to retrieve a pointer to a section of the ring buffer. You specify the number of frames you
1316 need, and on output it will set to what was actually acquired. If the read or write pointer is positioned such that the number of frames requested will require
1317 a loop, it will be clamped to the end of the buffer. Therefore, the number of frames you're given may be less than the number you requested.
1318 
1319 After calling `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()`, you do your work on the buffer and then "commit" it with `ma_pcm_rb_commit_read()` or
1320 `ma_pcm_rb_commit_write()`. This is where the read/write pointers are updated. When you commit you need to pass in the buffer that was returned by the earlier
1321 call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and
1322 `ma_pcm_rb_commit_write()` is what's used to increment the pointers.
1323 
1324 If you want to correct for drift between the write pointer and the read pointer you can use a combination of `ma_pcm_rb_pointer_distance()`,
1325 `ma_pcm_rb_seek_read()` and `ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only move the read pointer forward via
1326 the consumer thread, and the write pointer forward by the producer thread. If there is too much space between the pointers, move the read pointer forward. If
1327 there is too little space between the pointers, move the write pointer forward.
1328 
1329 You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb` API. This is exactly the sample, only you will use the `ma_rb`
1330 functions instead of `ma_pcm_rb` and instead of frame counts you'll pass around byte counts.
1331 
1332 The maximum size of the buffer in bytes is 0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1) due to the most significant bit being used to encode a flag and the internally
1333 managed buffers always being aligned to MA_SIMD_ALIGNMENT.
1334 
1335 Note that the ring buffer is only thread safe when used by a single consumer thread and single producer thread.
1336 
1337 
1338 
1339 Backends
1340 ========
1341 The following backends are supported by miniaudio.
1342 
1343  |-------------|-----------------------|--------------------------------------------------------|
1344  | Name | Enum Name | Supported Operating Systems |
1345  |-------------|-----------------------|--------------------------------------------------------|
1346  | WASAPI | ma_backend_wasapi | Windows Vista+ |
1347  | DirectSound | ma_backend_dsound | Windows XP+ |
1348  | WinMM | ma_backend_winmm | Windows XP+ (may work on older versions, but untested) |
1349  | Core Audio | ma_backend_coreaudio | macOS, iOS |
1350  | ALSA | ma_backend_alsa | Linux |
1351  | PulseAudio | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android) |
1352  | JACK | ma_backend_jack | Cross Platform (disabled on BSD and Android) |
1353  | sndio | ma_backend_sndio | OpenBSD |
1354  | audio(4) | ma_backend_audio4 | NetBSD, OpenBSD |
1355  | OSS | ma_backend_oss | FreeBSD |
1356  | AAudio | ma_backend_aaudio | Android 8+ |
1357  | OpenSL|ES | ma_backend_opensl | Android (API level 16+) |
1358  | Web Audio | ma_backend_webaudio | Web (via Emscripten) |
1359  | Null | ma_backend_null | Cross Platform (not used on Web) |
1360  |-------------|-----------------------|--------------------------------------------------------|
1361 
1362 Some backends have some nuance details you may want to be aware of.
1363 
1364 WASAPI
1365 ------
1366 - Low-latency shared mode will be disabled when using an application-defined sample rate which is different to the device's native sample rate. To work around
1367  this, set wasapi.noAutoConvertSRC to true in the device config. This is due to IAudioClient3_InitializeSharedAudioStream() failing when the
1368  AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM flag is specified. Setting wasapi.noAutoConvertSRC will result in miniaudio's lower quality internal resampler being used
1369  instead which will in turn enable the use of low-latency shared mode.
1370 
1371 PulseAudio
1372 ----------
1373 - If you experience bad glitching/noise on Arch Linux, consider this fix from the Arch wiki:
1374  https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling
1375  Alternatively, consider using a different backend such as ALSA.
1376 
1377 Android
1378 -------
1379 - To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest:
1380  <uses-permission android:name="android.permission.RECORD_AUDIO" />
1381 - With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a limitation with OpenSL|ES.
1382 - With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration API (devices are enumerated through Java). You can however
1383  perform your own device enumeration through Java and then set the ID in the ma_device_id structure (ma_device_id.aaudio) and pass it to ma_device_init().
1384 - The backend API will perform resampling where possible. The reason for this as opposed to using miniaudio's built-in resampler is to take advantage of any
1385  potential device-specific optimizations the driver may implement.
1386 
1387 UWP
1388 ---
1389 - UWP only supports default playback and capture devices.
1390 - UWP requires the Microphone capability to be enabled in the application's manifest (Package.appxmanifest):
1391  <Package ...>
1392  ...
1393  <Capabilities>
1394  <DeviceCapability Name="microphone" />
1395  </Capabilities>
1396  </Package>
1397 
1398 Web Audio / Emscripten
1399 ----------------------
1400 - You cannot use -std=c* compiler flags, nor -ansi. This only applies to the Emscripten build.
1401 - The first time a context is initialized it will create a global object called "miniaudio" whose primary purpose is to act as a factory for device objects.
1402 - Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as they've been deprecated.
1403 - Google has implemented a policy in their browsers that prevent automatic media output without first receiving some kind of user input. The following web page
1404  has additional details: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting the device may fail if you try to start playback
1405  without first handling some kind of user input.
1406 
1407 
1408 
1409 Miscellaneous Notes
1410 ===================
1411 - Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for WASAPI and Core Audio, however other backends such as
1412  PulseAudio may naturally support it, though not all have been tested.
1413 - The contents of the output buffer passed into the data callback will always be pre-initialized to zero unless the noPreZeroedOutputBuffer config variable in
1414  ma_device_config is set to true, in which case it'll be undefined which will require you to write something to the entire buffer.
1415 - By default miniaudio will automatically clip samples. This only applies when the playback sample format is configured as ma_format_f32. If you are doing
1416  clipping yourself, you can disable this overhead by setting noClip to true in the device config.
1417 - The sndio backend is currently only enabled on OpenBSD builds.
1418 - The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can use it.
1419 - Note that GCC and Clang requires "-msse2", "-mavx2", etc. for SIMD optimizations.
1420 */
1421 
1422 #ifndef miniaudio_h
1423 #define miniaudio_h
1424 
1425 #ifdef __cplusplus
1426 extern "C" {
1427 #endif
1428 
1429 #if defined(_MSC_VER) && !defined(__clang__)
1430  #pragma warning(push)
1431  #pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */
1432  #pragma warning(disable:4324) /* structure was padded due to alignment specifier */
1433 #else
1434  #pragma GCC diagnostic push
1435  #pragma GCC diagnostic ignored "-Wpedantic" /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
1436  #if defined(__clang__)
1437  #pragma GCC diagnostic ignored "-Wc11-extensions" /* anonymous unions are a C11 extension */
1438  #endif
1439 #endif
1440 
1441 /* Platform/backend detection. */
1442 #ifdef _WIN32
1443  #define MA_WIN32
1444  #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
1445  #define MA_WIN32_UWP
1446  #else
1447  #define MA_WIN32_DESKTOP
1448  #endif
1449 #else
1450  #define MA_POSIX
1451  #include <pthread.h> /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */
1452  #include <semaphore.h>
1453 
1454  #ifdef __unix__
1455  #define MA_UNIX
1456  #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
1457  #define MA_BSD
1458  #endif
1459  #endif
1460  #ifdef __linux__
1461  #define MA_LINUX
1462  #endif
1463  #ifdef __APPLE__
1464  #define MA_APPLE
1465  #endif
1466  #ifdef __ANDROID__
1467  #define MA_ANDROID
1468  #endif
1469  #ifdef __EMSCRIPTEN__
1470  #define MA_EMSCRIPTEN
1471  #endif
1472 #endif
1473 
1474 #include <stddef.h> /* For size_t. */
1475 
1476 /* Sized types. Prefer built-in types. Fall back to stdint. */
1477 #ifdef _MSC_VER
1478  #if defined(__clang__)
1479  #pragma GCC diagnostic push
1480  #pragma GCC diagnostic ignored "-Wlanguage-extension-token"
1481  #pragma GCC diagnostic ignored "-Wlong-long"
1482  #pragma GCC diagnostic ignored "-Wc++11-long-long"
1483  #endif
1484  typedef signed __int8 ma_int8;
1485  typedef unsigned __int8 ma_uint8;
1486  typedef signed __int16 ma_int16;
1487  typedef unsigned __int16 ma_uint16;
1488  typedef signed __int32 ma_int32;
1489  typedef unsigned __int32 ma_uint32;
1490  typedef signed __int64 ma_int64;
1491  typedef unsigned __int64 ma_uint64;
1492  #if defined(__clang__)
1493  #pragma GCC diagnostic pop
1494  #endif
1495 #else
1496  #define MA_HAS_STDINT
1497  #include <stdint.h>
1498  typedef int8_t ma_int8;
1499  typedef uint8_t ma_uint8;
1500  typedef int16_t ma_int16;
1501  typedef uint16_t ma_uint16;
1502  typedef int32_t ma_int32;
1503  typedef uint32_t ma_uint32;
1504  typedef int64_t ma_int64;
1505  typedef uint64_t ma_uint64;
1506 #endif
1507 
1508 #ifdef MA_HAS_STDINT
1509  typedef uintptr_t ma_uintptr;
1510 #else
1511  #if defined(_WIN32)
1512  #if defined(_WIN64)
1513  typedef ma_uint64 ma_uintptr;
1514  #else
1515  typedef ma_uint32 ma_uintptr;
1516  #endif
1517  #elif defined(__GNUC__)
1518  #if defined(__LP64__)
1519  typedef ma_uint64 ma_uintptr;
1520  #else
1521  typedef ma_uint32 ma_uintptr;
1522  #endif
1523  #else
1524  typedef ma_uint64 ma_uintptr; /* Fallback. */
1525  #endif
1526 #endif
1527 
1530 #define MA_TRUE 1
1531 #define MA_FALSE 0
1532 
1533 typedef void* ma_handle;
1534 typedef void* ma_ptr;
1535 typedef void (* ma_proc)(void);
1536 
1537 #if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED)
1538 typedef ma_uint16 wchar_t;
1539 #endif
1540 
1541 /* Define NULL for some compilers. */
1542 #ifndef NULL
1543 #define NULL 0
1544 #endif
1545 
1546 #if defined(SIZE_MAX)
1547  #define MA_SIZE_MAX SIZE_MAX
1548 #else
1549  #define MA_SIZE_MAX 0xFFFFFFFF /* When SIZE_MAX is not defined by the standard library just default to the maximum 32-bit unsigned integer. */
1550 #endif
1551 
1552 
1553 #ifdef _MSC_VER
1554  #define MA_INLINE __forceinline
1555 #elif defined(__GNUC__)
1556  /*
1557  I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
1558  the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
1559  case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
1560  command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
1561  I am using "__inline__" only when we're compiling in strict ANSI mode.
1562  */
1563  #if defined(__STRICT_ANSI__)
1564  #define MA_INLINE __inline__ __attribute__((always_inline))
1565  #else
1566  #define MA_INLINE inline __attribute__((always_inline))
1567  #endif
1568 #else
1569  #define MA_INLINE
1570 #endif
1571 
1572 #if defined(_MSC_VER)
1573  #if _MSC_VER >= 1400
1574  #define MA_ALIGN(alignment) __declspec(align(alignment))
1575  #endif
1576 #elif !defined(__DMC__)
1577  #define MA_ALIGN(alignment) __attribute__((aligned(alignment)))
1578 #endif
1579 #ifndef MA_ALIGN
1580  #define MA_ALIGN(alignment)
1581 #endif
1582 
1583 /* SIMD alignment in bytes. Currently set to 64 bytes in preparation for future AVX-512 optimizations. */
1584 #define MA_SIMD_ALIGNMENT 64
1585 
1586 
1587 /* Logging levels */
1588 #define MA_LOG_LEVEL_VERBOSE 4
1589 #define MA_LOG_LEVEL_INFO 3
1590 #define MA_LOG_LEVEL_WARNING 2
1591 #define MA_LOG_LEVEL_ERROR 1
1592 
1593 #ifndef MA_LOG_LEVEL
1594 #define MA_LOG_LEVEL MA_LOG_LEVEL_ERROR
1595 #endif
1596 
1597 typedef struct ma_context ma_context;
1598 typedef struct ma_device ma_device;
1599 
1601 #define MA_CHANNEL_NONE 0
1602 #define MA_CHANNEL_MONO 1
1603 #define MA_CHANNEL_FRONT_LEFT 2
1604 #define MA_CHANNEL_FRONT_RIGHT 3
1605 #define MA_CHANNEL_FRONT_CENTER 4
1606 #define MA_CHANNEL_LFE 5
1607 #define MA_CHANNEL_BACK_LEFT 6
1608 #define MA_CHANNEL_BACK_RIGHT 7
1609 #define MA_CHANNEL_FRONT_LEFT_CENTER 8
1610 #define MA_CHANNEL_FRONT_RIGHT_CENTER 9
1611 #define MA_CHANNEL_BACK_CENTER 10
1612 #define MA_CHANNEL_SIDE_LEFT 11
1613 #define MA_CHANNEL_SIDE_RIGHT 12
1614 #define MA_CHANNEL_TOP_CENTER 13
1615 #define MA_CHANNEL_TOP_FRONT_LEFT 14
1616 #define MA_CHANNEL_TOP_FRONT_CENTER 15
1617 #define MA_CHANNEL_TOP_FRONT_RIGHT 16
1618 #define MA_CHANNEL_TOP_BACK_LEFT 17
1619 #define MA_CHANNEL_TOP_BACK_CENTER 18
1620 #define MA_CHANNEL_TOP_BACK_RIGHT 19
1621 #define MA_CHANNEL_AUX_0 20
1622 #define MA_CHANNEL_AUX_1 21
1623 #define MA_CHANNEL_AUX_2 22
1624 #define MA_CHANNEL_AUX_3 23
1625 #define MA_CHANNEL_AUX_4 24
1626 #define MA_CHANNEL_AUX_5 25
1627 #define MA_CHANNEL_AUX_6 26
1628 #define MA_CHANNEL_AUX_7 27
1629 #define MA_CHANNEL_AUX_8 28
1630 #define MA_CHANNEL_AUX_9 29
1631 #define MA_CHANNEL_AUX_10 30
1632 #define MA_CHANNEL_AUX_11 31
1633 #define MA_CHANNEL_AUX_12 32
1634 #define MA_CHANNEL_AUX_13 33
1635 #define MA_CHANNEL_AUX_14 34
1636 #define MA_CHANNEL_AUX_15 35
1637 #define MA_CHANNEL_AUX_16 36
1638 #define MA_CHANNEL_AUX_17 37
1639 #define MA_CHANNEL_AUX_18 38
1640 #define MA_CHANNEL_AUX_19 39
1641 #define MA_CHANNEL_AUX_20 40
1642 #define MA_CHANNEL_AUX_21 41
1643 #define MA_CHANNEL_AUX_22 42
1644 #define MA_CHANNEL_AUX_23 43
1645 #define MA_CHANNEL_AUX_24 44
1646 #define MA_CHANNEL_AUX_25 45
1647 #define MA_CHANNEL_AUX_26 46
1648 #define MA_CHANNEL_AUX_27 47
1649 #define MA_CHANNEL_AUX_28 48
1650 #define MA_CHANNEL_AUX_29 49
1651 #define MA_CHANNEL_AUX_30 50
1652 #define MA_CHANNEL_AUX_31 51
1653 #define MA_CHANNEL_LEFT MA_CHANNEL_FRONT_LEFT
1654 #define MA_CHANNEL_RIGHT MA_CHANNEL_FRONT_RIGHT
1655 #define MA_CHANNEL_POSITION_COUNT (MA_CHANNEL_AUX_31 + 1)
1656 
1657 
1658 typedef int ma_result;
1659 #define MA_SUCCESS 0
1660 #define MA_ERROR -1 /* A generic error. */
1661 #define MA_INVALID_ARGS -2
1662 #define MA_INVALID_OPERATION -3
1663 #define MA_OUT_OF_MEMORY -4
1664 #define MA_OUT_OF_RANGE -5
1665 #define MA_ACCESS_DENIED -6
1666 #define MA_DOES_NOT_EXIST -7
1667 #define MA_ALREADY_EXISTS -8
1668 #define MA_TOO_MANY_OPEN_FILES -9
1669 #define MA_INVALID_FILE -10
1670 #define MA_TOO_BIG -11
1671 #define MA_PATH_TOO_LONG -12
1672 #define MA_NAME_TOO_LONG -13
1673 #define MA_NOT_DIRECTORY -14
1674 #define MA_IS_DIRECTORY -15
1675 #define MA_DIRECTORY_NOT_EMPTY -16
1676 #define MA_END_OF_FILE -17
1677 #define MA_NO_SPACE -18
1678 #define MA_BUSY -19
1679 #define MA_IO_ERROR -20
1680 #define MA_INTERRUPT -21
1681 #define MA_UNAVAILABLE -22
1682 #define MA_ALREADY_IN_USE -23
1683 #define MA_BAD_ADDRESS -24
1684 #define MA_BAD_SEEK -25
1685 #define MA_BAD_PIPE -26
1686 #define MA_DEADLOCK -27
1687 #define MA_TOO_MANY_LINKS -28
1688 #define MA_NOT_IMPLEMENTED -29
1689 #define MA_NO_MESSAGE -30
1690 #define MA_BAD_MESSAGE -31
1691 #define MA_NO_DATA_AVAILABLE -32
1692 #define MA_INVALID_DATA -33
1693 #define MA_TIMEOUT -34
1694 #define MA_NO_NETWORK -35
1695 #define MA_NOT_UNIQUE -36
1696 #define MA_NOT_SOCKET -37
1697 #define MA_NO_ADDRESS -38
1698 #define MA_BAD_PROTOCOL -39
1699 #define MA_PROTOCOL_UNAVAILABLE -40
1700 #define MA_PROTOCOL_NOT_SUPPORTED -41
1701 #define MA_PROTOCOL_FAMILY_NOT_SUPPORTED -42
1702 #define MA_ADDRESS_FAMILY_NOT_SUPPORTED -43
1703 #define MA_SOCKET_NOT_SUPPORTED -44
1704 #define MA_CONNECTION_RESET -45
1705 #define MA_ALREADY_CONNECTED -46
1706 #define MA_NOT_CONNECTED -47
1707 #define MA_CONNECTION_REFUSED -48
1708 #define MA_NO_HOST -49
1709 #define MA_IN_PROGRESS -50
1710 #define MA_CANCELLED -51
1711 #define MA_MEMORY_ALREADY_MAPPED -52
1712 #define MA_AT_END -53
1713 
1714 /* General miniaudio-specific errors. */
1715 #define MA_FORMAT_NOT_SUPPORTED -100
1716 #define MA_DEVICE_TYPE_NOT_SUPPORTED -101
1717 #define MA_SHARE_MODE_NOT_SUPPORTED -102
1718 #define MA_NO_BACKEND -103
1719 #define MA_NO_DEVICE -104
1720 #define MA_API_NOT_FOUND -105
1721 #define MA_INVALID_DEVICE_CONFIG -106
1722 
1723 /* State errors. */
1724 #define MA_DEVICE_NOT_INITIALIZED -200
1725 #define MA_DEVICE_ALREADY_INITIALIZED -201
1726 #define MA_DEVICE_NOT_STARTED -202
1727 #define MA_DEVICE_NOT_STOPPED -203
1728 
1729 /* Operation errors. */
1730 #define MA_FAILED_TO_INIT_BACKEND -300
1731 #define MA_FAILED_TO_OPEN_BACKEND_DEVICE -301
1732 #define MA_FAILED_TO_START_BACKEND_DEVICE -302
1733 #define MA_FAILED_TO_STOP_BACKEND_DEVICE -303
1734 
1735 
1736 /* Standard sample rates. */
1737 #define MA_SAMPLE_RATE_8000 8000
1738 #define MA_SAMPLE_RATE_11025 11025
1739 #define MA_SAMPLE_RATE_16000 16000
1740 #define MA_SAMPLE_RATE_22050 22050
1741 #define MA_SAMPLE_RATE_24000 24000
1742 #define MA_SAMPLE_RATE_32000 32000
1743 #define MA_SAMPLE_RATE_44100 44100
1744 #define MA_SAMPLE_RATE_48000 48000
1745 #define MA_SAMPLE_RATE_88200 88200
1746 #define MA_SAMPLE_RATE_96000 96000
1747 #define MA_SAMPLE_RATE_176400 176400
1748 #define MA_SAMPLE_RATE_192000 192000
1749 #define MA_SAMPLE_RATE_352800 352800
1750 #define MA_SAMPLE_RATE_384000 384000
1751 
1752 #define MA_MIN_CHANNELS 1
1753 #define MA_MAX_CHANNELS 32
1754 #define MA_MIN_SAMPLE_RATE MA_SAMPLE_RATE_8000
1755 #define MA_MAX_SAMPLE_RATE MA_SAMPLE_RATE_384000
1756 
1757 #ifndef MA_MAX_FILTER_ORDER
1758 #define MA_MAX_FILTER_ORDER 8
1759 #endif
1760 
1761 typedef enum
1762 {
1765 
1766 typedef enum
1767 {
1771 
1772 typedef enum
1773 {
1777 } ma_dither_mode;
1778 
1779 typedef enum
1780 {
1781  /*
1782  I like to keep these explicitly defined because they're used as a key into a lookup table. When items are
1783  added to this, make sure there are no gaps and that they're added to the lookup table in ma_get_bytes_per_sample().
1784  */
1785  ma_format_unknown = 0, /* Mainly used for indicating an error, but also used as the default for the output format for decoders. */
1787  ma_format_s16 = 2, /* Seems to be the most widely supported format. */
1788  ma_format_s24 = 3, /* Tightly packed. 3 bytes per sample. */
1792 } ma_format;
1793 
1794 typedef enum
1795 {
1796  ma_channel_mix_mode_rectangular = 0, /* Simple averaging based on the plane(s) the channel is sitting on. */
1797  ma_channel_mix_mode_simple, /* Drop excess channels; zeroed out extra channels. */
1798  ma_channel_mix_mode_custom_weights, /* Use custom weights specified in ma_channel_router_config. */
1802 
1803 typedef enum
1804 {
1807  ma_standard_channel_map_rfc3551, /* Based off AIFF. */
1810  ma_standard_channel_map_sound4, /* FreeBSD's sound(4). */
1811  ma_standard_channel_map_sndio, /* www.sndio.org/tips.html */
1812  ma_standard_channel_map_webaudio = ma_standard_channel_map_flac, /* https://webaudio.github.io/web-audio-api/#ChannelOrdering. Only 1, 2, 4 and 6 channels are defined, but can fill in the gaps with logical assumptions. */
1815 
1816 typedef enum
1817 {
1821 
1822 
1823 typedef struct
1824 {
1825  void* pUserData;
1826  void* (* onMalloc)(size_t sz, void* pUserData);
1827  void* (* onRealloc)(void* p, size_t sz, void* pUserData);
1828  void (* onFree)(void* p, void* pUserData);
1830 
1831 
1832 /**************************************************************************************************************************************************************
1833 
1834 Biquad Filtering
1835 
1836 **************************************************************************************************************************************************************/
1837 typedef union
1838 {
1839  float f32;
1840  ma_int32 s32;
1842 
1843 typedef struct
1847  double b0;
1848  double b1;
1849  double b2;
1850  double a0;
1851  double a1;
1852  double a2;
1854 
1855 ma_biquad_config ma_biquad_config_init(ma_format format, ma_uint32 channels, double b0, double b1, double b2, double a0, double a1, double a2);
1856 
1857 typedef struct
1858 {
1868 } ma_biquad;
1869 
1870 ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ);
1872 ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
1874 
1875 
1876 /**************************************************************************************************************************************************************
1877 
1878 Low-Pass Filtering
1879 
1880 **************************************************************************************************************************************************************/
1881 typedef struct
1882 {
1883  ma_format format;
1886  double cutoffFrequency;
1887  double q;
1892 
1893 typedef struct
1894 {
1899 } ma_lpf1;
1900 
1901 ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, ma_lpf1* pLPF);
1902 ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF);
1903 ma_result ma_lpf1_process_pcm_frames(ma_lpf1* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
1905 
1906 typedef struct
1907 {
1908  ma_biquad bq; /* The second order low-pass filter is implemented as a biquad filter. */
1909 } ma_lpf2;
1910 
1911 ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, ma_lpf2* pLPF);
1912 ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF);
1913 ma_result ma_lpf2_process_pcm_frames(ma_lpf2* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
1915 
1916 
1917 typedef struct
1918 {
1923  ma_uint32 order; /* If set to 0, will be treated as a passthrough (no filtering will be applied). */
1924 } ma_lpf_config;
1925 
1927 
1928 typedef struct
1929 {
1934  ma_lpf1 lpf1[1];
1936 } ma_lpf;
1937 
1938 ma_result ma_lpf_init(const ma_lpf_config* pConfig, ma_lpf* pLPF);
1939 ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF);
1940 ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
1942 
1943 
1944 /**************************************************************************************************************************************************************
1945 
1946 High-Pass Filtering
1947 
1948 **************************************************************************************************************************************************************/
1949 typedef struct
1950 {
1951  ma_format format;
1954  double cutoffFrequency;
1955  double q;
1960 
1961 typedef struct
1962 {
1967 } ma_hpf1;
1968 
1969 ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, ma_hpf1* pHPF);
1970 ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF);
1971 ma_result ma_hpf1_process_pcm_frames(ma_hpf1* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
1973 
1974 typedef struct
1975 {
1976  ma_biquad bq; /* The second order high-pass filter is implemented as a biquad filter. */
1977 } ma_hpf2;
1978 
1979 ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, ma_hpf2* pHPF);
1980 ma_result ma_hpf2_reinit(const ma_hpf2_config* pConfig, ma_hpf2* pHPF);
1981 ma_result ma_hpf2_process_pcm_frames(ma_hpf2* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
1983 
1984 
1985 typedef struct
1986 {
1991  ma_uint32 order; /* If set to 0, will be treated as a passthrough (no filtering will be applied). */
1992 } ma_hpf_config;
1993 
1995 
1996 typedef struct
1997 {
2002  ma_hpf1 hpf1[1];
2004 } ma_hpf;
2005 
2006 ma_result ma_hpf_init(const ma_hpf_config* pConfig, ma_hpf* pHPF);
2007 ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF);
2008 ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2010 
2011 
2012 /**************************************************************************************************************************************************************
2013 
2014 Band-Pass Filtering
2015 
2016 **************************************************************************************************************************************************************/
2017 typedef struct
2018 {
2019  ma_format format;
2022  double cutoffFrequency;
2023  double q;
2028 typedef struct
2029 {
2030  ma_biquad bq; /* The second order band-pass filter is implemented as a biquad filter. */
2031 } ma_bpf2;
2032 
2033 ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, ma_bpf2* pBPF);
2034 ma_result ma_bpf2_reinit(const ma_bpf2_config* pConfig, ma_bpf2* pBPF);
2035 ma_result ma_bpf2_process_pcm_frames(ma_bpf2* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2037 
2038 
2039 typedef struct
2040 {
2045  ma_uint32 order; /* If set to 0, will be treated as a passthrough (no filtering will be applied). */
2046 } ma_bpf_config;
2047 
2049 
2050 typedef struct
2051 {
2056 } ma_bpf;
2057 
2058 ma_result ma_bpf_init(const ma_bpf_config* pConfig, ma_bpf* pBPF);
2059 ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF);
2060 ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2062 
2063 
2064 /**************************************************************************************************************************************************************
2065 
2066 Notching Filter
2067 
2068 **************************************************************************************************************************************************************/
2069 typedef struct
2070 {
2071  ma_format format;
2074  double q;
2075  double frequency;
2080 typedef struct
2081 {
2083 } ma_notch2;
2084 
2085 ma_result ma_notch2_init(const ma_notch2_config* pConfig, ma_notch2* pFilter);
2086 ma_result ma_notch2_reinit(const ma_notch2_config* pConfig, ma_notch2* pFilter);
2087 ma_result ma_notch2_process_pcm_frames(ma_notch2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2089 
2090 
2091 /**************************************************************************************************************************************************************
2092 
2093 Peaking EQ Filter
2094 
2095 **************************************************************************************************************************************************************/
2096 typedef struct
2097 {
2098  ma_format format;
2101  double gainDB;
2102  double q;
2103  double frequency;
2108 typedef struct
2109 {
2111 } ma_peak2;
2112 
2113 ma_result ma_peak2_init(const ma_peak2_config* pConfig, ma_peak2* pFilter);
2114 ma_result ma_peak2_reinit(const ma_peak2_config* pConfig, ma_peak2* pFilter);
2115 ma_result ma_peak2_process_pcm_frames(ma_peak2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2117 
2118 
2119 /**************************************************************************************************************************************************************
2120 
2121 Low Shelf Filter
2122 
2123 **************************************************************************************************************************************************************/
2124 typedef struct
2125 {
2126  ma_format format;
2129  double gainDB;
2130  double shelfSlope;
2131  double frequency;
2134 ma_loshelf2_config ma_loshelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency);
2136 typedef struct
2137 {
2139 } ma_loshelf2;
2140 
2141 ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter);
2143 ma_result ma_loshelf2_process_pcm_frames(ma_loshelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2145 
2146 
2147 /**************************************************************************************************************************************************************
2148 
2149 High Shelf Filter
2150 
2151 **************************************************************************************************************************************************************/
2152 typedef struct
2153 {
2154  ma_format format;
2157  double gainDB;
2158  double shelfSlope;
2159  double frequency;
2162 ma_hishelf2_config ma_hishelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency);
2164 typedef struct
2165 {
2167 } ma_hishelf2;
2168 
2169 ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter);
2171 ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2173 
2174 
2175 
2176 /************************************************************************************************************************************************************
2177 *************************************************************************************************************************************************************
2178 
2179 DATA CONVERSION
2180 ===============
2181 
2182 This section contains the APIs for data conversion. You will find everything here for channel mapping, sample format conversion, resampling, etc.
2183 
2184 *************************************************************************************************************************************************************
2185 ************************************************************************************************************************************************************/
2186 
2187 /**************************************************************************************************************************************************************
2188 
2189 Resampling
2190 
2191 **************************************************************************************************************************************************************/
2192 typedef struct
2193 {
2194  ma_format format;
2196  ma_uint32 sampleRateIn;
2197  ma_uint32 sampleRateOut;
2198  ma_uint32 lpfOrder; /* The low-pass filter order. Setting this to 0 will disable low-pass filtering. */
2199  double lpfNyquistFactor; /* 0..1. Defaults to 1. 1 = Half the sampling frequency (Nyquist Frequency), 0.5 = Quarter the sampling frequency (half Nyquest Frequency), etc. */
2201 
2203 
2204 typedef struct
2205 {
2209  ma_uint32 inTimeInt;
2210  ma_uint32 inTimeFrac;
2211  union
2212  {
2213  float f32[MA_MAX_CHANNELS];
2215  } x0; /* The previous input frame. */
2216  union
2217  {
2218  float f32[MA_MAX_CHANNELS];
2220  } x1; /* The next input frame. */
2223 
2226 ma_result ma_linear_resampler_process_pcm_frames(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
2227 ma_result ma_linear_resampler_set_rate(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
2233 
2234 typedef enum
2235 {
2236  ma_resample_algorithm_linear = 0, /* Fastest, lowest quality. Optional low-pass filtering. Default. */
2239 
2240 typedef struct
2241 {
2242  ma_format format; /* Must be either ma_format_f32 or ma_format_s16. */
2247  struct
2248  {
2251  } linear;
2252  struct
2253  {
2254  int quality; /* 0 to 10. Defaults to 3. */
2255  } speex;
2257 
2259 
2260 typedef struct
2261 {
2263  union
2264  {
2266  struct
2267  {
2268  void* pSpeexResamplerState; /* SpeexResamplerState* */
2269  } speex;
2270  } state;
2271 } ma_resampler;
2272 
2273 /*
2274 Initializes a new resampler object from a config.
2275 */
2276 ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resampler* pResampler);
2277 
2278 /*
2279 Uninitializes a resampler.
2280 */
2281 void ma_resampler_uninit(ma_resampler* pResampler);
2282 
2283 /*
2284 Converts the given input data.
2285 
2286 Both the input and output frames must be in the format specified in the config when the resampler was initilized.
2287 
2288 On input, [pFrameCountOut] contains the number of output frames to process. On output it contains the number of output frames that
2289 were actually processed, which may be less than the requested amount which will happen if there's not enough input data. You can use
2290 ma_resampler_get_expected_output_frame_count() to know how many output frames will be processed for a given number of input frames.
2291 
2292 On input, [pFrameCountIn] contains the number of input frames contained in [pFramesIn]. On output it contains the number of whole
2293 input frames that were actually processed. You can use ma_resampler_get_required_input_frame_count() to know how many input frames
2294 you should provide for a given number of output frames. [pFramesIn] can be NULL, in which case zeroes will be used instead.
2295 
2296 If [pFramesOut] is NULL, a seek is performed. In this case, if [pFrameCountOut] is not NULL it will seek by the specified number of
2297 output frames. Otherwise, if [pFramesCountOut] is NULL and [pFrameCountIn] is not NULL, it will seek by the specified number of input
2298 frames. When seeking, [pFramesIn] is allowed to NULL, in which case the internal timing state will be updated, but no input will be
2299 processed. In this case, any internal filter state will be updated as if zeroes were passed in.
2300 
2301 It is an error for [pFramesOut] to be non-NULL and [pFrameCountOut] to be NULL.
2302 
2303 It is an error for both [pFrameCountOut] and [pFrameCountIn] to be NULL.
2304 */
2305 ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
2306 
2307 
2308 /*
2309 Sets the input and output sample sample rate.
2310 */
2311 ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
2312 
2313 /*
2314 Sets the input and output sample rate as a ratio.
2315 
2316 The ration is in/out.
2317 */
2318 ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio);
2319 
2320 
2321 /*
2322 Calculates the number of whole input frames that would need to be read from the client in order to output the specified
2323 number of output frames.
2324 
2325 The returned value does not include cached input frames. It only returns the number of extra frames that would need to be
2326 read from the input buffer in order to output the specified number of output frames.
2327 */
2329 
2330 /*
2331 Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of
2332 input frames.
2333 */
2335 
2336 
2337 /*
2338 Retrieves the latency introduced by the resampler in input frames.
2339 */
2341 
2342 /*
2343 Retrieves the latency introduced by the resampler in output frames.
2344 */
2346 
2347 
2348 
2349 /**************************************************************************************************************************************************************
2350 
2351 Channel Conversion
2352 
2353 **************************************************************************************************************************************************************/
2354 typedef struct
2355 {
2356  ma_format format;
2357  ma_uint32 channelsIn;
2358  ma_uint32 channelsOut;
2359  ma_channel channelMapIn[MA_MAX_CHANNELS];
2360  ma_channel channelMapOut[MA_MAX_CHANNELS];
2362  float weights[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */
2367 typedef struct
2368 {
2373  ma_channel channelMapOut[MA_MAX_CHANNELS];
2375  union
2376  {
2379  } weights;
2384  ma_uint8 shuffleTable[MA_MAX_CHANNELS];
2386 
2389 ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2390 
2391 
2392 /**************************************************************************************************************************************************************
2393 
2394 Data Conversion
2395 
2396 **************************************************************************************************************************************************************/
2397 typedef struct
2398 {
2399  ma_format formatIn;
2400  ma_format formatOut;
2401  ma_uint32 channelsIn;
2402  ma_uint32 channelsOut;
2403  ma_uint32 sampleRateIn;
2404  ma_uint32 sampleRateOut;
2406  ma_channel channelMapOut[MA_MAX_CHANNELS];
2407  ma_dither_mode ditherMode;
2409  float channelWeights[MA_MAX_CHANNELS][MA_MAX_CHANNELS]; /* [in][out]. Only used when channelMixMode is set to ma_channel_mix_mode_custom_weights. */
2410  struct
2411  {
2413  ma_bool32 allowDynamicSampleRate;
2414  struct
2415  {
2417  double lpfNyquistFactor;
2418  } linear;
2419  struct
2420  {
2421  int quality;
2422  } speex;
2423  } resampling;
2427 ma_data_converter_config ma_data_converter_config_init(ma_format formatIn, ma_format formatOut, ma_uint32 channelsIn, ma_uint32 channelsOut, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
2428 
2429 typedef struct
2430 {
2440 
2443 ma_result ma_data_converter_process_pcm_frames(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
2444 ma_result ma_data_converter_set_rate(ma_data_converter* pConverter, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
2445 ma_result ma_data_converter_set_rate_ratio(ma_data_converter* pConverter, float ratioInOut);
2450 
2451 
2452 /************************************************************************************************************************************************************
2453 
2454 Format Conversion
2455 
2456 ************************************************************************************************************************************************************/
2457 void ma_pcm_u8_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2458 void ma_pcm_u8_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2459 void ma_pcm_u8_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2460 void ma_pcm_u8_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2461 void ma_pcm_s16_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2462 void ma_pcm_s16_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2463 void ma_pcm_s16_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2464 void ma_pcm_s16_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2465 void ma_pcm_s24_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2466 void ma_pcm_s24_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2467 void ma_pcm_s24_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2468 void ma_pcm_s24_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2469 void ma_pcm_s32_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2470 void ma_pcm_s32_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2471 void ma_pcm_s32_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2472 void ma_pcm_s32_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2473 void ma_pcm_f32_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2474 void ma_pcm_f32_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2475 void ma_pcm_f32_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2476 void ma_pcm_f32_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2477 void ma_pcm_convert(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 sampleCount, ma_dither_mode ditherMode);
2478 void ma_convert_pcm_frames_format(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 frameCount, ma_uint32 channels, ma_dither_mode ditherMode);
2479 
2480 /*
2481 Deinterleaves an interleaved buffer.
2482 */
2483 void ma_deinterleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void* pInterleavedPCMFrames, void** ppDeinterleavedPCMFrames);
2484 
2485 /*
2486 Interleaves a group of deinterleaved buffers.
2487 */
2488 void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames);
2489 
2490 /************************************************************************************************************************************************************
2491 
2492 Channel Maps
2493 
2494 ************************************************************************************************************************************************************/
2495 
2496 /*
2497 Helper for retrieving a standard channel map.
2498 */
2500 
2501 /*
2502 Copies a channel map.
2503 */
2505 
2506 
2507 /*
2508 Determines whether or not a channel map is valid.
2509 
2510 A blank channel map is valid (all channels set to MA_CHANNEL_NONE). The way a blank channel map is handled is context specific, but
2511 is usually treated as a passthrough.
2512 
2513 Invalid channel maps:
2514  - A channel map with no channels
2515  - A channel map with more than one channel and a mono channel
2516 */
2518 
2519 /*
2520 Helper for comparing two channel maps for equality.
2521 
2522 This assumes the channel count is the same between the two.
2523 */
2525 
2526 /*
2527 Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE).
2528 */
2530 
2531 /*
2532 Helper for determining whether or not a channel is present in the given channel map.
2533 */
2535 
2536 
2537 /************************************************************************************************************************************************************
2538 
2539 Conversion Helpers
2540 
2541 ************************************************************************************************************************************************************/
2542 
2543 /*
2544 High-level helper for doing a full format conversion in one go. Returns the number of output frames. Call this with pOut set to NULL to
2545 determine the required size of the output buffer. frameCountOut should be set to the capacity of pOut. If pOut is NULL, frameCountOut is
2546 ignored.
2547 
2548 A return value of 0 indicates an error.
2549 
2550 This function is useful for one-off bulk conversions, but if you're streaming data you should use the ma_data_converter APIs instead.
2551 */
2552 ma_uint64 ma_convert_frames(void* pOut, ma_uint64 frameCountOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, const void* pIn, ma_uint64 frameCountIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn);
2553 ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const void* pIn, ma_uint64 frameCountIn, const ma_data_converter_config* pConfig);
2554 
2555 
2556 /************************************************************************************************************************************************************
2557 
2558 Ring Buffer
2559 
2560 ************************************************************************************************************************************************************/
2561 typedef struct
2562 {
2563  void* pBuffer;
2564  ma_uint32 subbufferSizeInBytes;
2565  ma_uint32 subbufferCount;
2566  ma_uint32 subbufferStrideInBytes;
2567  volatile ma_uint32 encodedReadOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. */
2568  volatile ma_uint32 encodedWriteOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. */
2569  ma_bool32 ownsBuffer : 1; /* Used to know whether or not miniaudio is responsible for free()-ing the buffer. */
2570  ma_bool32 clearOnWriteAcquire : 1; /* When set, clears the acquired write buffer before returning from ma_rb_acquire_write(). */
2571  ma_allocation_callbacks allocationCallbacks;
2574 ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCount, size_t subbufferStrideInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB);
2575 ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB);
2576 void ma_rb_uninit(ma_rb* pRB);
2577 void ma_rb_reset(ma_rb* pRB);
2578 ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut);
2579 ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut);
2580 ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut);
2581 ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut);
2582 ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes);
2583 ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes);
2584 ma_int32 ma_rb_pointer_distance(ma_rb* pRB); /* Returns the distance between the write pointer and the read pointer. Should never be negative for a correct program. Will return the number of bytes that can be read before the read pointer hits the write pointer. */
2587 size_t ma_rb_get_subbuffer_size(ma_rb* pRB);
2588 size_t ma_rb_get_subbuffer_stride(ma_rb* pRB);
2589 size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex);
2590 void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer);
2591 
2592 
2593 typedef struct
2594 {
2598 } ma_pcm_rb;
2599 
2600 ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint32 subbufferSizeInFrames, ma_uint32 subbufferCount, ma_uint32 subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_pcm_rb* pRB);
2601 ma_result ma_pcm_rb_init(ma_format format, ma_uint32 channels, ma_uint32 bufferSizeInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_pcm_rb* pRB);
2602 void ma_pcm_rb_uninit(ma_pcm_rb* pRB);
2603 void ma_pcm_rb_reset(ma_pcm_rb* pRB);
2604 ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut);
2605 ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut);
2606 ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut);
2607 ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut);
2608 ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames);
2609 ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames);
2610 ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb* pRB); /* Return value is in frames. */
2616 void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer);
2617 
2618 
2619 /************************************************************************************************************************************************************
2620 
2621 Miscellaneous Helpers
2622 
2623 ************************************************************************************************************************************************************/
2624 /*
2625 Retrieves a human readable description of the given result code.
2626 */
2627 const char* ma_result_description(ma_result result);
2628 
2629 /*
2630 malloc(). Calls MA_MALLOC().
2631 */
2632 void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks);
2633 
2634 /*
2635 realloc(). Calls MA_REALLOC().
2636 */
2637 void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks);
2638 
2639 /*
2640 free(). Calls MA_FREE().
2641 */
2642 void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks);
2643 
2644 /*
2645 Performs an aligned malloc, with the assumption that the alignment is a power of 2.
2646 */
2647 void* ma_aligned_malloc(size_t sz, size_t alignment, const ma_allocation_callbacks* pAllocationCallbacks);
2648 
2649 /*
2650 Free's an aligned malloc'd buffer.
2651 */
2652 void ma_aligned_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks);
2653 
2654 /*
2655 Retrieves a friendly name for a format.
2656 */
2657 const char* ma_get_format_name(ma_format format);
2658 
2659 /*
2660 Blends two frames in floating point format.
2661 */
2662 void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels);
2663 
2664 /*
2665 Retrieves the size of a sample in bytes for the given format.
2666 
2667 This API is efficient and is implemented using a lookup table.
2668 
2669 Thread Safety: SAFE
2670  This API is pure.
2671 */
2674 
2675 /*
2676 Converts a log level to a string.
2677 */
2678 const char* ma_log_level_to_string(ma_uint32 logLevel);
2679 
2680 
2681 
2682 /************************************************************************************************************************************************************
2683 *************************************************************************************************************************************************************
2684 
2685 DEVICE I/O
2686 ==========
2687 
2688 This section contains the APIs for device playback and capture. Here is where you'll find ma_device_init(), etc.
2689 
2690 *************************************************************************************************************************************************************
2691 ************************************************************************************************************************************************************/
2692 #ifndef MA_NO_DEVICE_IO
2693 /* Some backends are only supported on certain platforms. */
2694 #if defined(MA_WIN32)
2695  #define MA_SUPPORT_WASAPI
2696  #if defined(MA_WIN32_DESKTOP) /* DirectSound and WinMM backends are only supported on desktops. */
2697  #define MA_SUPPORT_DSOUND
2698  #define MA_SUPPORT_WINMM
2699  #define MA_SUPPORT_JACK /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */
2700  #endif
2701 #endif
2702 #if defined(MA_UNIX)
2703  #if defined(MA_LINUX)
2704  #if !defined(MA_ANDROID) /* ALSA is not supported on Android. */
2705  #define MA_SUPPORT_ALSA
2706  #endif
2707  #endif
2708  #if !defined(MA_BSD) && !defined(MA_ANDROID) && !defined(MA_EMSCRIPTEN)
2709  #define MA_SUPPORT_PULSEAUDIO
2710  #define MA_SUPPORT_JACK
2711  #endif
2712  #if defined(MA_ANDROID)
2713  #define MA_SUPPORT_AAUDIO
2714  #define MA_SUPPORT_OPENSL
2715  #endif
2716  #if defined(__OpenBSD__) /* <-- Change this to "#if defined(MA_BSD)" to enable sndio on all BSD flavors. */
2717  #define MA_SUPPORT_SNDIO /* sndio is only supported on OpenBSD for now. May be expanded later if there's demand. */
2718  #endif
2719  #if defined(__NetBSD__) || defined(__OpenBSD__)
2720  #define MA_SUPPORT_AUDIO4 /* Only support audio(4) on platforms with known support. */
2721  #endif
2722  #if defined(__FreeBSD__) || defined(__DragonFly__)
2723  #define MA_SUPPORT_OSS /* Only support OSS on specific platforms with known support. */
2724  #endif
2725 #endif
2726 #if defined(MA_APPLE)
2727  #define MA_SUPPORT_COREAUDIO
2728 #endif
2729 #if defined(MA_EMSCRIPTEN)
2730  #define MA_SUPPORT_WEBAUDIO
2731 #endif
2732 
2733 /* Explicitly disable the Null backend for Emscripten because it uses a background thread which is not properly supported right now. */
2734 #if !defined(MA_EMSCRIPTEN)
2735 #define MA_SUPPORT_NULL
2736 #endif
2737 
2738 
2739 #if !defined(MA_NO_WASAPI) && defined(MA_SUPPORT_WASAPI)
2740  #define MA_ENABLE_WASAPI
2741 #endif
2742 #if !defined(MA_NO_DSOUND) && defined(MA_SUPPORT_DSOUND)
2743  #define MA_ENABLE_DSOUND
2744 #endif
2745 #if !defined(MA_NO_WINMM) && defined(MA_SUPPORT_WINMM)
2746  #define MA_ENABLE_WINMM
2747 #endif
2748 #if !defined(MA_NO_ALSA) && defined(MA_SUPPORT_ALSA)
2749  #define MA_ENABLE_ALSA
2750 #endif
2751 #if !defined(MA_NO_PULSEAUDIO) && defined(MA_SUPPORT_PULSEAUDIO)
2752  #define MA_ENABLE_PULSEAUDIO
2753 #endif
2754 #if !defined(MA_NO_JACK) && defined(MA_SUPPORT_JACK)
2755  #define MA_ENABLE_JACK
2756 #endif
2757 #if !defined(MA_NO_COREAUDIO) && defined(MA_SUPPORT_COREAUDIO)
2758  #define MA_ENABLE_COREAUDIO
2759 #endif
2760 #if !defined(MA_NO_SNDIO) && defined(MA_SUPPORT_SNDIO)
2761  #define MA_ENABLE_SNDIO
2762 #endif
2763 #if !defined(MA_NO_AUDIO4) && defined(MA_SUPPORT_AUDIO4)
2764  #define MA_ENABLE_AUDIO4
2765 #endif
2766 #if !defined(MA_NO_OSS) && defined(MA_SUPPORT_OSS)
2767  #define MA_ENABLE_OSS
2768 #endif
2769 #if !defined(MA_NO_AAUDIO) && defined(MA_SUPPORT_AAUDIO)
2770  #define MA_ENABLE_AAUDIO
2771 #endif
2772 #if !defined(MA_NO_OPENSL) && defined(MA_SUPPORT_OPENSL)
2773  #define MA_ENABLE_OPENSL
2774 #endif
2775 #if !defined(MA_NO_WEBAUDIO) && defined(MA_SUPPORT_WEBAUDIO)
2776  #define MA_ENABLE_WEBAUDIO
2777 #endif
2778 #if !defined(MA_NO_NULL) && defined(MA_SUPPORT_NULL)
2779  #define MA_ENABLE_NULL
2780 #endif
2781 
2782 #ifdef MA_SUPPORT_WASAPI
2783 /* We need a IMMNotificationClient object for WASAPI. */
2784 typedef struct
2785 {
2786  void* lpVtbl;
2787  ma_uint32 counter;
2788  ma_device* pDevice;
2789 } ma_IMMNotificationClient;
2790 #endif
2791 
2792 /* Backend enums must be in priority order. */
2793 typedef enum
2794 {
2808  ma_backend_null /* <-- Must always be the last item. Lowest priority, and used as the terminator for backend enumeration. */
2809 } ma_backend;
2810 
2811 /* Thread priorties should be ordered such that the default priority of the worker thread is 0. */
2812 typedef enum
2813 {
2823 
2824 typedef struct
2825 {
2827 
2828  union
2829  {
2830 #ifdef MA_WIN32
2831  struct
2832  {
2833  /*HANDLE*/ ma_handle hThread;
2834  } win32;
2835 #endif
2836 #ifdef MA_POSIX
2837  struct
2838  {
2839  pthread_t thread;
2840  } posix;
2841 #endif
2842  int _unused;
2843  };
2844 } ma_thread;
2845 
2846 typedef struct
2847 {
2849 
2850  union
2851  {
2852 #ifdef MA_WIN32
2853  struct
2854  {
2855  /*HANDLE*/ ma_handle hMutex;
2856  } win32;
2857 #endif
2858 #ifdef MA_POSIX
2859  struct
2860  {
2861  pthread_mutex_t mutex;
2862  } posix;
2863 #endif
2864  int _unused;
2865  };
2866 } ma_mutex;
2867 
2868 typedef struct
2869 {
2871 
2872  union
2873  {
2874 #ifdef MA_WIN32
2875  struct
2876  {
2877  /*HANDLE*/ ma_handle hEvent;
2878  } win32;
2879 #endif
2880 #ifdef MA_POSIX
2881  struct
2882  {
2883  pthread_mutex_t mutex;
2884  pthread_cond_t condition;
2886  } posix;
2887 #endif
2888  int _unused;
2889  };
2890 } ma_event;
2891 
2892 typedef struct
2893 {
2895 
2896  union
2897  {
2898 #ifdef MA_WIN32
2899  struct
2900  {
2901  /*HANDLE*/ ma_handle hSemaphore;
2902  } win32;
2903 #endif
2904 #ifdef MA_POSIX
2905  struct
2906  {
2907  sem_t semaphore;
2908  } posix;
2909 #endif
2910  int _unused;
2911  };
2912 } ma_semaphore;
2913 
2914 
2915 /*
2916 The callback for processing audio data from the device.
2917 
2918 The data callback is fired by miniaudio whenever the device needs to have more data delivered to a playback device, or when a capture device has some data
2919 available. This is called as soon as the backend asks for more data which means it may be called with inconsistent frame counts. You cannot assume the
2920 callback will be fired with a consistent frame count.
2921 
2922 
2923 Parameters
2924 ----------
2925 pDevice (in)
2926  A pointer to the relevant device.
2927 
2928 pOutput (out)
2929  A pointer to the output buffer that will receive audio data that will later be played back through the speakers. This will be non-null for a playback or
2930  full-duplex device and null for a capture and loopback device.
2931 
2932 pInput (in)
2933  A pointer to the buffer containing input data from a recording device. This will be non-null for a capture, full-duplex or loopback device and null for a
2934  playback device.
2935 
2936 frameCount (in)
2937  The number of PCM frames to process. Note that this will not necessarily be equal to what you requested when you initialized the device. The
2938  `periodSizeInFrames` and `periodSizeInMilliseconds` members of the device config are just hints, and are not necessarily exactly what you'll get. You must
2939  not assume this will always be the same value each time the callback is fired.
2940 
2941 
2942 Remarks
2943 -------
2944 You cannot stop and start the device from inside the callback or else you'll get a deadlock. You must also not uninitialize the device from inside the
2945 callback. The following APIs cannot be called from inside the callback:
2946 
2947  ma_device_init()
2948  ma_device_init_ex()
2949  ma_device_uninit()
2950  ma_device_start()
2951  ma_device_stop()
2952 
2953 The proper way to stop the device is to call `ma_device_stop()` from a different thread, normally the main application thread.
2954 */
2955 typedef void (* ma_device_callback_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
2956 
2957 /*
2958 The callback for when the device has been stopped.
2959 
2960 This will be called when the device is stopped explicitly with `ma_device_stop()` and also called implicitly when the device is stopped through external forces
2961 such as being unplugged or an internal error occuring.
2962 
2963 
2964 Parameters
2965 ----------
2966 pDevice (in)
2967  A pointer to the device that has just stopped.
2968 
2969 
2970 Remarks
2971 -------
2972 Do not restart or uninitialize the device from the callback.
2973 */
2974 typedef void (* ma_stop_proc)(ma_device* pDevice);
2975 
2976 /*
2977 The callback for handling log messages.
2978 
2979 
2980 Parameters
2981 ----------
2982 pContext (in)
2983  A pointer to the context the log message originated from.
2984 
2985 pDevice (in)
2986  A pointer to the device the log message originate from, if any. This can be null, in which case the message came from the context.
2987 
2988 logLevel (in)
2989  The log level. This can be one of the following:
2990 
2991  |----------------------|
2992  | Log Level |
2993  |----------------------|
2994  | MA_LOG_LEVEL_VERBOSE |
2995  | MA_LOG_LEVEL_INFO |
2996  | MA_LOG_LEVEL_WARNING |
2997  | MA_LOG_LEVEL_ERROR |
2998  |----------------------|
2999 
3000 message (in)
3001  The log message.
3002 
3003 
3004 Remarks
3005 -------
3006 Do not modify the state of the device from inside the callback.
3007 */
3008 typedef void (* ma_log_proc)(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message);
3009 
3010 typedef enum
3011 {
3016 } ma_device_type;
3017 
3018 typedef enum
3019 {
3022 } ma_share_mode;
3023 
3024 /* iOS/tvOS/watchOS session categories. */
3025 typedef enum
3026 {
3027  ma_ios_session_category_default = 0, /* AVAudioSessionCategoryPlayAndRecord with AVAudioSessionCategoryOptionDefaultToSpeaker. */
3028  ma_ios_session_category_none, /* Leave the session category unchanged. */
3029  ma_ios_session_category_ambient, /* AVAudioSessionCategoryAmbient */
3030  ma_ios_session_category_solo_ambient, /* AVAudioSessionCategorySoloAmbient */
3031  ma_ios_session_category_playback, /* AVAudioSessionCategoryPlayback */
3032  ma_ios_session_category_record, /* AVAudioSessionCategoryRecord */
3033  ma_ios_session_category_play_and_record, /* AVAudioSessionCategoryPlayAndRecord */
3034  ma_ios_session_category_multi_route /* AVAudioSessionCategoryMultiRoute */
3036 
3037 /* iOS/tvOS/watchOS session category options */
3038 typedef enum
3039 {
3040  ma_ios_session_category_option_mix_with_others = 0x01, /* AVAudioSessionCategoryOptionMixWithOthers */
3041  ma_ios_session_category_option_duck_others = 0x02, /* AVAudioSessionCategoryOptionDuckOthers */
3042  ma_ios_session_category_option_allow_bluetooth = 0x04, /* AVAudioSessionCategoryOptionAllowBluetooth */
3043  ma_ios_session_category_option_default_to_speaker = 0x08, /* AVAudioSessionCategoryOptionDefaultToSpeaker */
3044  ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others = 0x11, /* AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers */
3045  ma_ios_session_category_option_allow_bluetooth_a2dp = 0x20, /* AVAudioSessionCategoryOptionAllowBluetoothA2DP */
3046  ma_ios_session_category_option_allow_air_play = 0x40, /* AVAudioSessionCategoryOptionAllowAirPlay */
3048 
3049 typedef union
3050 {
3052  double counterD;
3053 } ma_timer;
3054 
3055 typedef union
3056 {
3057  wchar_t wasapi[64]; /* WASAPI uses a wchar_t string for identification. */
3058  ma_uint8 dsound[16]; /* DirectSound uses a GUID for identification. */
3059  /*UINT_PTR*/ ma_uint32 winmm; /* When creating a device, WinMM expects a Win32 UINT_PTR for device identification. In practice it's actually just a UINT. */
3060  char alsa[256]; /* ALSA uses a name string for identification. */
3061  char pulse[256]; /* PulseAudio uses a name string for identification. */
3062  int jack; /* JACK always uses default devices. */
3063  char coreaudio[256]; /* Core Audio uses a string for identification. */
3064  char sndio[256]; /* "snd/0", etc. */
3065  char audio4[256]; /* "/dev/audio", etc. */
3066  char oss[64]; /* "dev/dsp0", etc. "dev/dsp" for the default device. */
3067  ma_int32 aaudio; /* AAudio uses a 32-bit integer for identification. */
3068  ma_uint32 opensl; /* OpenSL|ES uses a 32-bit unsigned integer for identification. */
3069  char webaudio[32]; /* Web Audio always uses default devices for now, but if this changes it'll be a GUID. */
3070  int nullbackend; /* The null backend uses an integer for device IDs. */
3071 } ma_device_id;
3072 
3073 typedef struct
3074 {
3075  /* Basic info. This is the only information guaranteed to be filled in during device enumeration. */
3077  char name[256];
3078 
3079  /*
3080  Detailed info. As much of this is filled as possible with ma_context_get_device_info(). Note that you are allowed to initialize
3081  a device with settings outside of this range, but it just means the data will be converted using miniaudio's data conversion
3082  pipeline before sending the data to/from the device. Most programs will need to not worry about these values, but it's provided
3083  here mainly for informational purposes or in the rare case that someone might find it useful.
3084 
3085  These will be set to 0 when returned by ma_context_enumerate_devices() or ma_context_get_devices().
3086  */
3093 
3094  struct
3095  {
3097  } _private;
3098 } ma_device_info;
3099 
3100 typedef struct
3101 {
3108  ma_bool32 noPreZeroedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */
3109  ma_bool32 noClip; /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */
3112  void* pUserData;
3113  struct
3114  {
3116  struct
3117  {
3119  } linear;
3120  struct
3121  {
3122  int quality;
3123  } speex;
3124  } resampling;
3125  struct
3126  {
3132  } playback;
3133  struct
3134  {
3135  ma_device_id* pDeviceID;
3136  ma_format format;
3140  } capture;
3141 
3142  struct
3143  {
3144  ma_bool32 noAutoConvertSRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */
3145  ma_bool32 noDefaultQualitySRC; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */
3146  ma_bool32 noAutoStreamRouting; /* Disables automatic stream routing. */
3147  ma_bool32 noHardwareOffloading; /* Disables WASAPI's hardware offloading feature. */
3148  } wasapi;
3149  struct
3150  {
3151  ma_bool32 noMMap; /* Disables MMap mode. */
3152  } alsa;
3153  struct
3154  {
3155  const char* pStreamNamePlayback;
3156  const char* pStreamNameCapture;
3157  } pulse;
3159 
3160 typedef struct
3161 {
3164  void* pUserData;
3166  struct
3167  {
3169  } alsa;
3170  struct
3171  {
3172  const char* pApplicationName;
3173  const char* pServerName;
3174  ma_bool32 tryAutoSpawn; /* Enables autospawning of the PulseAudio daemon if necessary. */
3175  } pulse;
3176  struct
3177  {
3180  } coreaudio;
3181  struct
3182  {
3183  const char* pClientName;
3185  } jack;
3187 
3188 /*
3189 The callback for handling device enumeration. This is fired from `ma_context_enumerated_devices()`.
3190 
3191 
3192 Parameters
3193 ----------
3194 pContext (in)
3195  A pointer to the context performing the enumeration.
3196 
3197 deviceType (in)
3198  The type of the device being enumerated. This will always be either `ma_device_type_playback` or `ma_device_type_capture`.
3199 
3200 pInfo (in)
3201  A pointer to a `ma_device_info` containing the ID and name of the enumerated device. Note that this will not include detailed information about the device,
3202  only basic information (ID and name). The reason for this is that it would otherwise require opening the backend device to probe for the information which
3203  is too inefficient.
3204 
3205 pUserData (in)
3206  The user data pointer passed into `ma_context_enumerate_devices()`.
3207 */
3209 
3211 {
3212  ma_backend backend; /* DirectSound, ALSA, etc. */
3215  void* pUserData;
3217  ma_mutex deviceEnumLock; /* Used to make ma_context_get_devices() thread safe. */
3218  ma_mutex deviceInfoLock; /* Used to make ma_context_get_device_info() thread safe. */
3219  ma_uint32 deviceInfoCapacity; /* Total capacity of pDeviceInfos. */
3222  ma_device_info* pDeviceInfos; /* Playback devices first, then capture. */
3223  ma_bool32 isBackendAsynchronous : 1; /* Set when the context is initialized. Set to 1 for asynchronous backends such as Core Audio and JACK. Do not modify. */
3224 
3225  ma_result (* onUninit )(ma_context* pContext);
3226  ma_bool32 (* onDeviceIDEqual )(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1);
3227  ma_result (* onEnumDevices )(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData); /* Return false from the callback to stop enumeration. */
3228  ma_result (* onGetDeviceInfo )(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo);
3229  ma_result (* onDeviceInit )(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice);
3230  void (* onDeviceUninit )(ma_device* pDevice);
3234 
3235  union
3236  {
3237 #ifdef MA_SUPPORT_WASAPI
3238  struct
3239  {
3240  int _unused;
3241  } wasapi;
3242 #endif
3243 #ifdef MA_SUPPORT_DSOUND
3244  struct
3245  {
3246  ma_handle hDSoundDLL;
3247  ma_proc DirectSoundCreate;
3248  ma_proc DirectSoundEnumerateA;
3249  ma_proc DirectSoundCaptureCreate;
3250  ma_proc DirectSoundCaptureEnumerateA;
3251  } dsound;
3252 #endif
3253 #ifdef MA_SUPPORT_WINMM
3254  struct
3255  {
3256  ma_handle hWinMM;
3257  ma_proc waveOutGetNumDevs;
3258  ma_proc waveOutGetDevCapsA;
3259  ma_proc waveOutOpen;
3260  ma_proc waveOutClose;
3261  ma_proc waveOutPrepareHeader;
3262  ma_proc waveOutUnprepareHeader;
3263  ma_proc waveOutWrite;
3264  ma_proc waveOutReset;
3265  ma_proc waveInGetNumDevs;
3266  ma_proc waveInGetDevCapsA;
3267  ma_proc waveInOpen;
3268  ma_proc waveInClose;
3269  ma_proc waveInPrepareHeader;
3270  ma_proc waveInUnprepareHeader;
3271  ma_proc waveInAddBuffer;
3272  ma_proc waveInStart;
3273  ma_proc waveInReset;
3274  } winmm;
3275 #endif
3276 #ifdef MA_SUPPORT_ALSA
3277  struct
3278  {
3279  ma_handle asoundSO;
3280  ma_proc snd_pcm_open;
3281  ma_proc snd_pcm_close;
3282  ma_proc snd_pcm_hw_params_sizeof;
3283  ma_proc snd_pcm_hw_params_any;
3284  ma_proc snd_pcm_hw_params_set_format;
3285  ma_proc snd_pcm_hw_params_set_format_first;
3286  ma_proc snd_pcm_hw_params_get_format_mask;
3287  ma_proc snd_pcm_hw_params_set_channels_near;
3288  ma_proc snd_pcm_hw_params_set_rate_resample;
3289  ma_proc snd_pcm_hw_params_set_rate_near;
3290  ma_proc snd_pcm_hw_params_set_buffer_size_near;
3291  ma_proc snd_pcm_hw_params_set_periods_near;
3292  ma_proc snd_pcm_hw_params_set_access;
3293  ma_proc snd_pcm_hw_params_get_format;
3294  ma_proc snd_pcm_hw_params_get_channels;
3295  ma_proc snd_pcm_hw_params_get_channels_min;
3296  ma_proc snd_pcm_hw_params_get_channels_max;
3297  ma_proc snd_pcm_hw_params_get_rate;
3298  ma_proc snd_pcm_hw_params_get_rate_min;
3299  ma_proc snd_pcm_hw_params_get_rate_max;
3300  ma_proc snd_pcm_hw_params_get_buffer_size;
3301  ma_proc snd_pcm_hw_params_get_periods;
3302  ma_proc snd_pcm_hw_params_get_access;
3303  ma_proc snd_pcm_hw_params;
3304  ma_proc snd_pcm_sw_params_sizeof;
3305  ma_proc snd_pcm_sw_params_current;
3306  ma_proc snd_pcm_sw_params_get_boundary;
3307  ma_proc snd_pcm_sw_params_set_avail_min;
3308  ma_proc snd_pcm_sw_params_set_start_threshold;
3309  ma_proc snd_pcm_sw_params_set_stop_threshold;
3310  ma_proc snd_pcm_sw_params;
3311  ma_proc snd_pcm_format_mask_sizeof;
3312  ma_proc snd_pcm_format_mask_test;
3313  ma_proc snd_pcm_get_chmap;
3314  ma_proc snd_pcm_state;
3315  ma_proc snd_pcm_prepare;
3316  ma_proc snd_pcm_start;
3317  ma_proc snd_pcm_drop;
3318  ma_proc snd_pcm_drain;
3319  ma_proc snd_device_name_hint;
3320  ma_proc snd_device_name_get_hint;
3321  ma_proc snd_card_get_index;
3322  ma_proc snd_device_name_free_hint;
3323  ma_proc snd_pcm_mmap_begin;
3324  ma_proc snd_pcm_mmap_commit;
3325  ma_proc snd_pcm_recover;
3326  ma_proc snd_pcm_readi;
3327  ma_proc snd_pcm_writei;
3328  ma_proc snd_pcm_avail;
3329  ma_proc snd_pcm_avail_update;
3330  ma_proc snd_pcm_wait;
3331  ma_proc snd_pcm_info;
3332  ma_proc snd_pcm_info_sizeof;
3333  ma_proc snd_pcm_info_get_name;
3334  ma_proc snd_config_update_free_global;
3335 
3336  ma_mutex internalDeviceEnumLock;
3337  ma_bool32 useVerboseDeviceEnumeration;
3338  } alsa;
3339 #endif
3340 #ifdef MA_SUPPORT_PULSEAUDIO
3341  struct
3342  {
3343  ma_handle pulseSO;
3344  ma_proc pa_mainloop_new;
3345  ma_proc pa_mainloop_free;
3346  ma_proc pa_mainloop_get_api;
3347  ma_proc pa_mainloop_iterate;
3348  ma_proc pa_mainloop_wakeup;
3349  ma_proc pa_context_new;
3350  ma_proc pa_context_unref;
3351  ma_proc pa_context_connect;
3352  ma_proc pa_context_disconnect;
3353  ma_proc pa_context_set_state_callback;
3354  ma_proc pa_context_get_state;
3355  ma_proc pa_context_get_sink_info_list;
3356  ma_proc pa_context_get_source_info_list;
3357  ma_proc pa_context_get_sink_info_by_name;
3358  ma_proc pa_context_get_source_info_by_name;
3359  ma_proc pa_operation_unref;
3360  ma_proc pa_operation_get_state;
3361  ma_proc pa_channel_map_init_extend;
3362  ma_proc pa_channel_map_valid;
3363  ma_proc pa_channel_map_compatible;
3364  ma_proc pa_stream_new;
3365  ma_proc pa_stream_unref;
3366  ma_proc pa_stream_connect_playback;
3367  ma_proc pa_stream_connect_record;
3368  ma_proc pa_stream_disconnect;
3369  ma_proc pa_stream_get_state;
3370  ma_proc pa_stream_get_sample_spec;
3371  ma_proc pa_stream_get_channel_map;
3372  ma_proc pa_stream_get_buffer_attr;
3373  ma_proc pa_stream_set_buffer_attr;
3374  ma_proc pa_stream_get_device_name;
3375  ma_proc pa_stream_set_write_callback;
3376  ma_proc pa_stream_set_read_callback;
3377  ma_proc pa_stream_flush;
3378  ma_proc pa_stream_drain;
3379  ma_proc pa_stream_is_corked;
3380  ma_proc pa_stream_cork;
3381  ma_proc pa_stream_trigger;
3382  ma_proc pa_stream_begin_write;
3383  ma_proc pa_stream_write;
3384  ma_proc pa_stream_peek;
3385  ma_proc pa_stream_drop;
3386  ma_proc pa_stream_writable_size;
3387  ma_proc pa_stream_readable_size;
3388 
3389  char* pApplicationName;
3390  char* pServerName;
3391  ma_bool32 tryAutoSpawn;
3392  } pulse;
3393 #endif
3394 #ifdef MA_SUPPORT_JACK
3395  struct
3396  {
3397  ma_handle jackSO;
3398  ma_proc jack_client_open;
3399  ma_proc jack_client_close;
3400  ma_proc jack_client_name_size;
3401  ma_proc jack_set_process_callback;
3402  ma_proc jack_set_buffer_size_callback;
3403  ma_proc jack_on_shutdown;
3404  ma_proc jack_get_sample_rate;
3405  ma_proc jack_get_buffer_size;
3406  ma_proc jack_get_ports;
3407  ma_proc jack_activate;
3408  ma_proc jack_deactivate;
3409  ma_proc jack_connect;
3410  ma_proc jack_port_register;
3411  ma_proc jack_port_name;
3412  ma_proc jack_port_get_buffer;
3413  ma_proc jack_free;
3414 
3415  char* pClientName;
3416  ma_bool32 tryStartServer;
3417  } jack;
3418 #endif
3419 #ifdef MA_SUPPORT_COREAUDIO
3420  struct
3421  {
3422  ma_handle hCoreFoundation;
3423  ma_proc CFStringGetCString;
3424  ma_proc CFRelease;
3425 
3426  ma_handle hCoreAudio;
3427  ma_proc AudioObjectGetPropertyData;
3428  ma_proc AudioObjectGetPropertyDataSize;
3429  ma_proc AudioObjectSetPropertyData;
3430  ma_proc AudioObjectAddPropertyListener;
3431  ma_proc AudioObjectRemovePropertyListener;
3432 
3433  ma_handle hAudioUnit; /* Could possibly be set to AudioToolbox on later versions of macOS. */
3434  ma_proc AudioComponentFindNext;
3435  ma_proc AudioComponentInstanceDispose;
3436  ma_proc AudioComponentInstanceNew;
3437  ma_proc AudioOutputUnitStart;
3438  ma_proc AudioOutputUnitStop;
3439  ma_proc AudioUnitAddPropertyListener;
3440  ma_proc AudioUnitGetPropertyInfo;
3441  ma_proc AudioUnitGetProperty;
3442  ma_proc AudioUnitSetProperty;
3443  ma_proc AudioUnitInitialize;
3444  ma_proc AudioUnitRender;
3445 
3446  /*AudioComponent*/ ma_ptr component;
3447  } coreaudio;
3448 #endif
3449 #ifdef MA_SUPPORT_SNDIO
3450  struct
3451  {
3452  ma_handle sndioSO;
3453  ma_proc sio_open;
3454  ma_proc sio_close;
3455  ma_proc sio_setpar;
3456  ma_proc sio_getpar;
3457  ma_proc sio_getcap;
3458  ma_proc sio_start;
3459  ma_proc sio_stop;
3460  ma_proc sio_read;
3461  ma_proc sio_write;
3462  ma_proc sio_onmove;
3463  ma_proc sio_nfds;
3464  ma_proc sio_pollfd;
3465  ma_proc sio_revents;
3466  ma_proc sio_eof;
3467  ma_proc sio_setvol;
3468  ma_proc sio_onvol;
3469  ma_proc sio_initpar;
3470  } sndio;
3471 #endif
3472 #ifdef MA_SUPPORT_AUDIO4
3473  struct
3474  {
3475  int _unused;
3476  } audio4;
3477 #endif
3478 #ifdef MA_SUPPORT_OSS
3479  struct
3480  {
3481  int versionMajor;
3482  int versionMinor;
3483  } oss;
3484 #endif
3485 #ifdef MA_SUPPORT_AAUDIO
3486  struct
3487  {
3488  ma_handle hAAudio; /* libaaudio.so */
3489  ma_proc AAudio_createStreamBuilder;
3490  ma_proc AAudioStreamBuilder_delete;
3491  ma_proc AAudioStreamBuilder_setDeviceId;
3492  ma_proc AAudioStreamBuilder_setDirection;
3493  ma_proc AAudioStreamBuilder_setSharingMode;
3494  ma_proc AAudioStreamBuilder_setFormat;
3495  ma_proc AAudioStreamBuilder_setChannelCount;
3496  ma_proc AAudioStreamBuilder_setSampleRate;
3497  ma_proc AAudioStreamBuilder_setBufferCapacityInFrames;
3498  ma_proc AAudioStreamBuilder_setFramesPerDataCallback;
3499  ma_proc AAudioStreamBuilder_setDataCallback;
3500  ma_proc AAudioStreamBuilder_setErrorCallback;
3501  ma_proc AAudioStreamBuilder_setPerformanceMode;
3502  ma_proc AAudioStreamBuilder_openStream;
3503  ma_proc AAudioStream_close;
3504  ma_proc AAudioStream_getState;
3505  ma_proc AAudioStream_waitForStateChange;
3506  ma_proc AAudioStream_getFormat;
3507  ma_proc AAudioStream_getChannelCount;
3508  ma_proc AAudioStream_getSampleRate;
3509  ma_proc AAudioStream_getBufferCapacityInFrames;
3510  ma_proc AAudioStream_getFramesPerDataCallback;
3511  ma_proc AAudioStream_getFramesPerBurst;
3512  ma_proc AAudioStream_requestStart;
3513  ma_proc AAudioStream_requestStop;
3514  } aaudio;
3515 #endif
3516 #ifdef MA_SUPPORT_OPENSL
3517  struct
3518  {
3519  int _unused;
3520  } opensl;
3521 #endif
3522 #ifdef MA_SUPPORT_WEBAUDIO
3523  struct
3524  {
3525  int _unused;
3526  } webaudio;
3527 #endif
3528 #ifdef MA_SUPPORT_NULL
3529  struct
3530  {
3531  int _unused;
3532  } null_backend;
3533 #endif
3534  };
3535 
3536  union
3537  {
3538 #ifdef MA_WIN32
3539  struct
3540  {
3541  /*HMODULE*/ ma_handle hOle32DLL;
3542  ma_proc CoInitializeEx;
3543  ma_proc CoUninitialize;
3544  ma_proc CoCreateInstance;
3545  ma_proc CoTaskMemFree;
3546  ma_proc PropVariantClear;
3547  ma_proc StringFromGUID2;
3548 
3549  /*HMODULE*/ ma_handle hUser32DLL;
3550  ma_proc GetForegroundWindow;
3551  ma_proc GetDesktopWindow;
3552 
3553  /*HMODULE*/ ma_handle hAdvapi32DLL;
3554  ma_proc RegOpenKeyExA;
3555  ma_proc RegCloseKey;
3556  ma_proc RegQueryValueExA;
3557  } win32;
3558 #endif
3559 #ifdef MA_POSIX
3560  struct
3561  {
3578  } posix;
3579 #endif
3580  int _unused;
3581  };
3582 };
3583 
3585 {
3589  volatile ma_uint32 state; /* The state of the device is variable and can change at any time on any thread, so tell the compiler as such with `volatile`. */
3590  ma_device_callback_proc onData; /* Set once at initialization time and should not be changed after. */
3591  ma_stop_proc onStop; /* Set once at initialization time and should not be changed after. */
3592  void* pUserData; /* Application defined data. */
3598  ma_result workResult; /* This is set by the worker thread after it's finished doing a job. */
3602  ma_bool32 isOwnerOfContext : 1; /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */
3605  volatile float masterVolumeFactor; /* Volatile so we can use some thread safety when applying volume to periods. */
3606  struct
3607  {
3609  struct
3610  {
3612  } linear;
3613  struct
3614  {
3615  int quality;
3616  } speex;
3617  } resampling;
3618  struct
3619  {
3620  char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */
3621  ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */
3635  } playback;
3636  struct
3637  {
3638  char name[256]; /* Maybe temporary. Likely to be replaced with a query API. */
3639  ma_share_mode shareMode; /* Set to whatever was passed in when the device was initialized. */
3643  ma_format format;
3653  } capture;
3654 
3655  union
3656  {
3657 #ifdef MA_SUPPORT_WASAPI
3658  struct
3659  {
3660  /*IAudioClient**/ ma_ptr pAudioClientPlayback;
3661  /*IAudioClient**/ ma_ptr pAudioClientCapture;
3662  /*IAudioRenderClient**/ ma_ptr pRenderClient;
3663  /*IAudioCaptureClient**/ ma_ptr pCaptureClient;
3664  /*IMMDeviceEnumerator**/ ma_ptr pDeviceEnumerator; /* Used for IMMNotificationClient notifications. Required for detecting default device changes. */
3665  ma_IMMNotificationClient notificationClient;
3666  /*HANDLE*/ ma_handle hEventPlayback; /* Auto reset. Initialized to signaled. */
3667  /*HANDLE*/ ma_handle hEventCapture; /* Auto reset. Initialized to unsignaled. */
3668  ma_uint32 actualPeriodSizeInFramesPlayback; /* Value from GetBufferSize(). internalPeriodSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */
3669  ma_uint32 actualPeriodSizeInFramesCapture;
3670  ma_uint32 originalPeriodSizeInFrames;
3671  ma_uint32 originalPeriodSizeInMilliseconds;
3672  ma_uint32 originalPeriods;
3673  ma_bool32 hasDefaultPlaybackDeviceChanged; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
3674  ma_bool32 hasDefaultCaptureDeviceChanged; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
3675  ma_uint32 periodSizeInFramesPlayback;
3676  ma_uint32 periodSizeInFramesCapture;
3677  ma_bool32 isStartedCapture; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
3678  ma_bool32 isStartedPlayback; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
3679  ma_bool32 noAutoConvertSRC : 1; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */
3680  ma_bool32 noDefaultQualitySRC : 1; /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */
3681  ma_bool32 noHardwareOffloading : 1;
3682  ma_bool32 allowCaptureAutoStreamRouting : 1;
3683  ma_bool32 allowPlaybackAutoStreamRouting : 1;
3684  } wasapi;
3685 #endif
3686 #ifdef MA_SUPPORT_DSOUND
3687  struct
3688  {
3689  /*LPDIRECTSOUND*/ ma_ptr pPlayback;
3690  /*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackPrimaryBuffer;
3691  /*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackBuffer;
3692  /*LPDIRECTSOUNDCAPTURE*/ ma_ptr pCapture;
3693  /*LPDIRECTSOUNDCAPTUREBUFFER*/ ma_ptr pCaptureBuffer;
3694  } dsound;
3695 #endif
3696 #ifdef MA_SUPPORT_WINMM
3697  struct
3698  {
3699  /*HWAVEOUT*/ ma_handle hDevicePlayback;
3700  /*HWAVEIN*/ ma_handle hDeviceCapture;
3701  /*HANDLE*/ ma_handle hEventPlayback;
3702  /*HANDLE*/ ma_handle hEventCapture;
3703  ma_uint32 fragmentSizeInFrames;
3704  ma_uint32 fragmentSizeInBytes;
3705  ma_uint32 iNextHeaderPlayback; /* [0,periods). Used as an index into pWAVEHDRPlayback. */
3706  ma_uint32 iNextHeaderCapture; /* [0,periods). Used as an index into pWAVEHDRCapture. */
3707  ma_uint32 headerFramesConsumedPlayback; /* The number of PCM frames consumed in the buffer in pWAVEHEADER[iNextHeader]. */
3708  ma_uint32 headerFramesConsumedCapture; /* ^^^ */
3709  /*WAVEHDR**/ ma_uint8* pWAVEHDRPlayback; /* One instantiation for each period. */
3710  /*WAVEHDR**/ ma_uint8* pWAVEHDRCapture; /* One instantiation for each period. */
3711  ma_uint8* pIntermediaryBufferPlayback;
3712  ma_uint8* pIntermediaryBufferCapture;
3713  ma_uint8* _pHeapData; /* Used internally and is used for the heap allocated data for the intermediary buffer and the WAVEHDR structures. */
3714  } winmm;
3715 #endif
3716 #ifdef MA_SUPPORT_ALSA
3717  struct
3718  {
3719  /*snd_pcm_t**/ ma_ptr pPCMPlayback;
3720  /*snd_pcm_t**/ ma_ptr pPCMCapture;
3721  ma_bool32 isUsingMMapPlayback : 1;
3722  ma_bool32 isUsingMMapCapture : 1;
3723  } alsa;
3724 #endif
3725 #ifdef MA_SUPPORT_PULSEAUDIO
3726  struct
3727  {
3728  /*pa_mainloop**/ ma_ptr pMainLoop;
3729  /*pa_mainloop_api**/ ma_ptr pAPI;
3730  /*pa_context**/ ma_ptr pPulseContext;
3731  /*pa_stream**/ ma_ptr pStreamPlayback;
3732  /*pa_stream**/ ma_ptr pStreamCapture;
3733  /*pa_context_state*/ ma_uint32 pulseContextState;
3734  void* pMappedBufferPlayback;
3735  const void* pMappedBufferCapture;
3736  ma_uint32 mappedBufferFramesRemainingPlayback;
3737  ma_uint32 mappedBufferFramesRemainingCapture;
3738  ma_uint32 mappedBufferFramesCapacityPlayback;
3739  ma_uint32 mappedBufferFramesCapacityCapture;
3740  ma_bool32 breakFromMainLoop : 1;
3741  } pulse;
3742 #endif
3743 #ifdef MA_SUPPORT_JACK
3744  struct
3745  {
3746  /*jack_client_t**/ ma_ptr pClient;
3747  /*jack_port_t**/ ma_ptr pPortsPlayback[MA_MAX_CHANNELS];
3748  /*jack_port_t**/ ma_ptr pPortsCapture[MA_MAX_CHANNELS];
3749  float* pIntermediaryBufferPlayback; /* Typed as a float because JACK is always floating point. */
3750  float* pIntermediaryBufferCapture;
3752  } jack;
3753 #endif
3754 #ifdef MA_SUPPORT_COREAUDIO
3755  struct
3756  {
3757  ma_uint32 deviceObjectIDPlayback;
3758  ma_uint32 deviceObjectIDCapture;
3759  /*AudioUnit*/ ma_ptr audioUnitPlayback;
3760  /*AudioUnit*/ ma_ptr audioUnitCapture;
3761  /*AudioBufferList**/ ma_ptr pAudioBufferList; /* Only used for input devices. */
3763  ma_uint32 originalPeriodSizeInFrames;
3764  ma_uint32 originalPeriodSizeInMilliseconds;
3765  ma_uint32 originalPeriods;
3766  ma_bool32 isDefaultPlaybackDevice;
3767  ma_bool32 isDefaultCaptureDevice;
3768  ma_bool32 isSwitchingPlaybackDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */
3769  ma_bool32 isSwitchingCaptureDevice; /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */
3771  void* pRouteChangeHandler; /* Only used on mobile platforms. Obj-C object for handling route changes. */
3772  } coreaudio;
3773 #endif
3774 #ifdef MA_SUPPORT_SNDIO
3775  struct
3776  {
3777  ma_ptr handlePlayback;
3778  ma_ptr handleCapture;
3779  ma_bool32 isStartedPlayback;
3780  ma_bool32 isStartedCapture;
3781  } sndio;
3782 #endif
3783 #ifdef MA_SUPPORT_AUDIO4
3784  struct
3785  {
3786  int fdPlayback;
3787  int fdCapture;
3788  } audio4;
3789 #endif
3790 #ifdef MA_SUPPORT_OSS
3791  struct
3792  {
3793  int fdPlayback;
3794  int fdCapture;
3795  } oss;
3796 #endif
3797 #ifdef MA_SUPPORT_AAUDIO
3798  struct
3799  {
3800  /*AAudioStream**/ ma_ptr pStreamPlayback;
3801  /*AAudioStream**/ ma_ptr pStreamCapture;
3803  } aaudio;
3804 #endif
3805 #ifdef MA_SUPPORT_OPENSL
3806  struct
3807  {
3808  /*SLObjectItf*/ ma_ptr pOutputMixObj;
3809  /*SLOutputMixItf*/ ma_ptr pOutputMix;
3810  /*SLObjectItf*/ ma_ptr pAudioPlayerObj;
3811  /*SLPlayItf*/ ma_ptr pAudioPlayer;
3812  /*SLObjectItf*/ ma_ptr pAudioRecorderObj;
3813  /*SLRecordItf*/ ma_ptr pAudioRecorder;
3814  /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueuePlayback;
3815  /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueueCapture;
3816  ma_bool32 isDrainingCapture;
3817  ma_bool32 isDrainingPlayback;
3818  ma_uint32 currentBufferIndexPlayback;
3819  ma_uint32 currentBufferIndexCapture;
3820  ma_uint8* pBufferPlayback; /* This is malloc()'d and is used for storing audio data. Typed as ma_uint8 for easy offsetting. */
3821  ma_uint8* pBufferCapture;
3823  } opensl;
3824 #endif
3825 #ifdef MA_SUPPORT_WEBAUDIO
3826  struct
3827  {
3828  int indexPlayback; /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */
3829  int indexCapture;
3830  ma_pcm_rb duplexRB; /* In external capture format. */
3831  } webaudio;
3832 #endif
3833 #ifdef MA_SUPPORT_NULL
3834  struct
3835  {
3848  } null_device;
3849 #endif
3850  };
3851 };
3852 #if defined(_MSC_VER) && !defined(__clang__)
3853  #pragma warning(pop)
3854 #else
3855  #pragma GCC diagnostic pop /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
3856 #endif
3857 
3858 /*
3859 Initializes a `ma_context_config` object.
3860 
3861 
3862 Return Value
3863 ------------
3864 A `ma_context_config` initialized to defaults.
3865 
3866 
3867 Remarks
3868 -------
3869 You must always use this to initialize the default state of the `ma_context_config` object. Not using this will result in your program breaking when miniaudio
3870 is updated and new members are added to `ma_context_config`. It also sets logical defaults.
3871 
3872 You can override members of the returned object by changing it's members directly.
3873 
3874 
3875 See Also
3876 --------
3877 ma_context_init()
3878 */
3880 
3881 /*
3882 Initializes a context.
3883 
3884 The context is used for selecting and initializing an appropriate backend and to represent the backend at a more global level than that of an individual
3885 device. There is one context to many devices, and a device is created from a context. A context is required to enumerate devices.
3886 
3887 
3888 Parameters
3889 ----------
3890 backends (in, optional)
3891  A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order.
3892 
3893 backendCount (in, optional)
3894  The number of items in `backend`. Ignored if `backend` is NULL.
3895 
3896 pConfig (in, optional)
3897  The context configuration.
3898 
3899 pContext (in)
3900  A pointer to the context object being initialized.
3901 
3902 
3903 Return Value
3904 ------------
3905 MA_SUCCESS if successful; any other error code otherwise.
3906 
3907 
3908 Thread Safety
3909 -------------
3910 Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
3911 
3912 
3913 Remarks
3914 -------
3915 When `backends` is NULL, the default priority order will be used. Below is a list of backends in priority order:
3916 
3917  |-------------|-----------------------|--------------------------------------------------------|
3918  | Name | Enum Name | Supported Operating Systems |
3919  |-------------|-----------------------|--------------------------------------------------------|
3920  | WASAPI | ma_backend_wasapi | Windows Vista+ |
3921  | DirectSound | ma_backend_dsound | Windows XP+ |
3922  | WinMM | ma_backend_winmm | Windows XP+ (may work on older versions, but untested) |
3923  | Core Audio | ma_backend_coreaudio | macOS, iOS |
3924  | ALSA | ma_backend_alsa | Linux |
3925  | PulseAudio | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android) |
3926  | JACK | ma_backend_jack | Cross Platform (disabled on BSD and Android) |
3927  | sndio | ma_backend_sndio | OpenBSD |
3928  | audio(4) | ma_backend_audio4 | NetBSD, OpenBSD |
3929  | OSS | ma_backend_oss | FreeBSD |
3930  | AAudio | ma_backend_aaudio | Android 8+ |
3931  | OpenSL|ES | ma_backend_opensl | Android (API level 16+) |
3932  | Web Audio | ma_backend_webaudio | Web (via Emscripten) |
3933  | Null | ma_backend_null | Cross Platform (not used on Web) |
3934  |-------------|-----------------------|--------------------------------------------------------|
3935 
3936 The context can be configured via the `pConfig` argument. The config object is initialized with `ma_context_config_init()`. Individual configuration settings
3937 can then be set directly on the structure. Below are the members of the `ma_context_config` object.
3938 
3939  logCallback
3940  Callback for handling log messages from miniaudio.
3941 
3942  threadPriority
3943  The desired priority to use for the audio thread. Allowable values include the following:
3944 
3945  |--------------------------------------|
3946  | Thread Priority |
3947  |--------------------------------------|
3948  | ma_thread_priority_idle |
3949  | ma_thread_priority_lowest |
3950  | ma_thread_priority_low |
3951  | ma_thread_priority_normal |
3952  | ma_thread_priority_high |
3953  | ma_thread_priority_highest (default) |
3954  | ma_thread_priority_realtime |
3955  | ma_thread_priority_default |
3956  |--------------------------------------|
3957 
3958  pUserData
3959  A pointer to application-defined data. This can be accessed from the context object directly such as `context.pUserData`.
3960 
3961  allocationCallbacks
3962  Structure containing custom allocation callbacks. Leaving this at defaults will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. These allocation
3963  callbacks will be used for anything tied to the context, including devices.
3964 
3965  alsa.useVerboseDeviceEnumeration
3966  ALSA will typically enumerate many different devices which can be intrusive and unuser-friendly. To combat this, miniaudio will enumerate only unique
3967  card/device pairs by default. The problem with this is that you lose a bit of flexibility and control. Setting alsa.useVerboseDeviceEnumeration makes
3968  it so the ALSA backend includes all devices. Defaults to false.
3969 
3970  pulse.pApplicationName
3971  PulseAudio only. The application name to use when initializing the PulseAudio context with `pa_context_new()`.
3972 
3973  pulse.pServerName
3974  PulseAudio only. The name of the server to connect to with `pa_context_connect()`.
3975 
3976  pulse.tryAutoSpawn
3977  PulseAudio only. Whether or not to try automatically starting the PulseAudio daemon. Defaults to false. If you set this to true, keep in mind that
3978  miniaudio uses a trial and error method to find the most appropriate backend, and this will result in the PulseAudio daemon starting which may be
3979  intrusive for the end user.
3980 
3981  coreaudio.sessionCategory
3982  iOS only. The session category to use for the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents.
3983 
3984  |-----------------------------------------|-------------------------------------|
3985  | miniaudio Token | Core Audio Token |
3986  |-----------------------------------------|-------------------------------------|
3987  | ma_ios_session_category_ambient | AVAudioSessionCategoryAmbient |
3988  | ma_ios_session_category_solo_ambient | AVAudioSessionCategorySoloAmbient |
3989  | ma_ios_session_category_playback | AVAudioSessionCategoryPlayback |
3990  | ma_ios_session_category_record | AVAudioSessionCategoryRecord |
3991  | ma_ios_session_category_play_and_record | AVAudioSessionCategoryPlayAndRecord |
3992  | ma_ios_session_category_multi_route | AVAudioSessionCategoryMultiRoute |
3993  | ma_ios_session_category_none | AVAudioSessionCategoryAmbient |
3994  | ma_ios_session_category_default | AVAudioSessionCategoryAmbient |
3995  |-----------------------------------------|-------------------------------------|
3996 
3997  coreaudio.sessionCategoryOptions
3998  iOS only. Session category options to use with the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents.
3999 
4000  |---------------------------------------------------------------------------|------------------------------------------------------------------|
4001  | miniaudio Token | Core Audio Token |
4002  |---------------------------------------------------------------------------|------------------------------------------------------------------|
4003  | ma_ios_session_category_option_mix_with_others | AVAudioSessionCategoryOptionMixWithOthers |
4004  | ma_ios_session_category_option_duck_others | AVAudioSessionCategoryOptionDuckOthers |
4005  | ma_ios_session_category_option_allow_bluetooth | AVAudioSessionCategoryOptionAllowBluetooth |
4006  | ma_ios_session_category_option_default_to_speaker | AVAudioSessionCategoryOptionDefaultToSpeaker |
4007  | ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers |
4008  | ma_ios_session_category_option_allow_bluetooth_a2dp | AVAudioSessionCategoryOptionAllowBluetoothA2DP |
4009  | ma_ios_session_category_option_allow_air_play | AVAudioSessionCategoryOptionAllowAirPlay |
4010  |---------------------------------------------------------------------------|------------------------------------------------------------------|
4011 
4012  jack.pClientName
4013  The name of the client to pass to `jack_client_open()`.
4014 
4015  jack.tryStartServer
4016  Whether or not to try auto-starting the JACK server. Defaults to false.
4017 
4018 
4019 It is recommended that only a single context is active at any given time because it's a bulky data structure which performs run-time linking for the
4020 relevant backends every time it's initialized.
4021 
4022 The location of the context cannot change throughout it's lifetime. Consider allocating the `ma_context` object with `malloc()` if this is an issue. The
4023 reason for this is that a pointer to the context is stored in the `ma_device` structure.
4024 
4025 
4026 Example 1 - Default Initialization
4027 ----------------------------------
4028 The example below shows how to initialize the context using the default configuration.
4029 
4030 ```c
4031 ma_context context;
4032 ma_result result = ma_context_init(NULL, 0, NULL, &context);
4033 if (result != MA_SUCCESS) {
4034  // Error.
4035 }
4036 ```
4037 
4038 
4039 Example 2 - Custom Configuration
4040 --------------------------------
4041 The example below shows how to initialize the context using custom backend priorities and a custom configuration. In this hypothetical example, the program
4042 wants to prioritize ALSA over PulseAudio on Linux. They also want to avoid using the WinMM backend on Windows because it's latency is too high. They also
4043 want an error to be returned if no valid backend is available which they achieve by excluding the Null backend.
4044 
4045 For the configuration, the program wants to capture any log messages so they can, for example, route it to a log file and user interface.
4046 
4047 ```c
4048 ma_backend backends[] = {
4049  ma_backend_alsa,
4050  ma_backend_pulseaudio,
4051  ma_backend_wasapi,
4052  ma_backend_dsound
4053 };
4054 
4055 ma_context_config config = ma_context_config_init();
4056 config.logCallback = my_log_callback;
4057 config.pUserData = pMyUserData;
4058 
4059 ma_context context;
4060 ma_result result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &config, &context);
4061 if (result != MA_SUCCESS) {
4062  // Error.
4063  if (result == MA_NO_BACKEND) {
4064  // Couldn't find an appropriate backend.
4065  }
4066 }
4067 ```
4068 
4069 
4070 See Also
4071 --------
4072 ma_context_config_init()
4073 ma_context_uninit()
4074 */
4075 ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext);
4076 
4077 /*
4078 Uninitializes a context.
4079 
4080 
4081 Return Value
4082 ------------
4083 MA_SUCCESS if successful; any other error code otherwise.
4084 
4085 
4086 Thread Safety
4087 -------------
4088 Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
4089 
4090 
4091 Remarks
4092 -------
4093 Results are undefined if you call this while any device created by this context is still active.
4094 
4095 
4096 See Also
4097 --------
4098 ma_context_init()
4099 */
4101 
4102 /*
4103 Enumerates over every device (both playback and capture).
4104 
4105 This is a lower-level enumeration function to the easier to use `ma_context_get_devices()`. Use `ma_context_enumerate_devices()` if you would rather not incur
4106 an internal heap allocation, or it simply suits your code better.
4107 
4108 Note that this only retrieves the ID and name/description of the device. The reason for only retrieving basic information is that it would otherwise require
4109 opening the backend device in order to probe it for more detailed information which can be inefficient. Consider using `ma_context_get_device_info()` for this,
4110 but don't call it from within the enumeration callback.
4111 
4112 Returning false from the callback will stop enumeration. Returning true will continue enumeration.
4113 
4114 
4115 Parameters
4116 ----------
4117 pContext (in)
4118  A pointer to the context performing the enumeration.
4119 
4120 callback (in)
4121  The callback to fire for each enumerated device.
4122 
4123 pUserData (in)
4124  A pointer to application-defined data passed to the callback.
4125 
4126 
4127 Return Value
4128 ------------
4129 MA_SUCCESS if successful; any other error code otherwise.
4130 
4131 
4132 Thread Safety
4133 -------------
4134 Safe. This is guarded using a simple mutex lock.
4135 
4136 
4137 Remarks
4138 -------
4139 Do _not_ assume the first enumerated device of a given type is the default device.
4140 
4141 Some backends and platforms may only support default playback and capture devices.
4142 
4143 In general, you should not do anything complicated from within the callback. In particular, do not try initializing a device from within the callback. Also,
4144 do not try to call `ma_context_get_device_info()` from within the callback.
4145 
4146 Consider using `ma_context_get_devices()` for a simpler and safer API, albeit at the expense of an internal heap allocation.
4147 
4148 
4149 Example 1 - Simple Enumeration
4150 ------------------------------
4151 ma_bool32 ma_device_enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData)
4152 {
4153  printf("Device Name: %s\n", pInfo->name);
4154  return MA_TRUE;
4155 }
4156 
4157 ma_result result = ma_context_enumerate_devices(&context, my_device_enum_callback, pMyUserData);
4158 if (result != MA_SUCCESS) {
4159  // Error.
4160 }
4161 
4162 
4163 See Also
4164 --------
4165 ma_context_get_devices()
4166 */
4168 
4169 /*
4170 Retrieves basic information about every active playback and/or capture device.
4171 
4172 This function will allocate memory internally for the device lists and return a pointer to them through the `ppPlaybackDeviceInfos` and `ppCaptureDeviceInfos`
4173 parameters. If you do not want to incur the overhead of these allocations consider using `ma_context_enumerate_devices()` which will instead use a callback.
4174 
4175 
4176 Parameters
4177 ----------
4178 pContext (in)
4179  A pointer to the context performing the enumeration.
4180 
4181 ppPlaybackDeviceInfos (out)
4182  A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for playback devices.
4183 
4184 pPlaybackDeviceCount (out)
4185  A pointer to an unsigned integer that will receive the number of playback devices.
4186 
4187 ppCaptureDeviceInfos (out)
4188  A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for capture devices.
4189 
4190 pCaptureDeviceCount (out)
4191  A pointer to an unsigned integer that will receive the number of capture devices.
4192 
4193 
4194 Return Value
4195 ------------
4196 MA_SUCCESS if successful; any other error code otherwise.
4197 
4198 
4199 Thread Safety
4200 -------------
4201 Unsafe. Since each call to this function invalidates the pointers from the previous call, you should not be calling this simultaneously across multiple
4202 threads. Instead, you need to make a copy of the returned data with your own higher level synchronization.
4203 
4204 
4205 Remarks
4206 -------
4207 It is _not_ safe to assume the first device in the list is the default device.
4208 
4209 You can pass in NULL for the playback or capture lists in which case they'll be ignored.
4210 
4211 The returned pointers will become invalid upon the next call this this function, or when the context is uninitialized. Do not free the returned pointers.
4212 
4213 
4214 See Also
4215 --------
4216 ma_context_get_devices()
4217 */
4218 ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** ppPlaybackDeviceInfos, ma_uint32* pPlaybackDeviceCount, ma_device_info** ppCaptureDeviceInfos, ma_uint32* pCaptureDeviceCount);
4219 
4220 /*
4221 Retrieves information about a device of the given type, with the specified ID and share mode.
4222 
4223 
4224 Parameters
4225 ----------
4226 pContext (in)
4227  A pointer to the context performing the query.
4228 
4229 deviceType (in)
4230  The type of the device being queried. Must be either `ma_device_type_playback` or `ma_device_type_capture`.
4231 
4232 pDeviceID (in)
4233  The ID of the device being queried.
4234 
4235 shareMode (in)
4236  The share mode to query for device capabilities. This should be set to whatever you're intending on using when initializing the device. If you're unsure,
4237  set this to `ma_share_mode_shared`.
4238 
4239 pDeviceInfo (out)
4240  A pointer to the `ma_device_info` structure that will receive the device information.
4241 
4242 
4243 Return Value
4244 ------------
4245 MA_SUCCESS if successful; any other error code otherwise.
4246 
4247 
4248 Thread Safety
4249 -------------
4250 Safe. This is guarded using a simple mutex lock.
4251 
4252 
4253 Remarks
4254 -------
4255 Do _not_ call this from within the `ma_context_enumerate_devices()` callback.
4256 
4257 It's possible for a device to have different information and capabilities depending on whether or not it's opened in shared or exclusive mode. For example, in
4258 shared mode, WASAPI always uses floating point samples for mixing, but in exclusive mode it can be anything. Therefore, this function allows you to specify
4259 which share mode you want information for. Note that not all backends and devices support shared or exclusive mode, in which case this function will fail if
4260 the requested share mode is unsupported.
4261 
4262 This leaves pDeviceInfo unmodified in the result of an error.
4263 */
4264 ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo);
4265 
4266 /*
4267 Determines if the given context supports loopback mode.
4268 
4269 
4270 Parameters
4271 ----------
4272 pContext (in)
4273  A pointer to the context getting queried.
4274 
4275 
4276 Return Value
4277 ------------
4278 MA_TRUE if the context supports loopback mode; MA_FALSE otherwise.
4279 */
4281 
4282 
4283 
4284 /*
4285 Initializes a device config with default settings.
4286 
4287 
4288 Parameters
4289 ----------
4290 deviceType (in)
4291  The type of the device this config is being initialized for. This must set to one of the following:
4292 
4293  |-------------------------|
4294  | Device Type |
4295  |-------------------------|
4296  | ma_device_type_playback |
4297  | ma_device_type_capture |
4298  | ma_device_type_duplex |
4299  | ma_device_type_loopback |
4300  |-------------------------|
4301 
4302 
4303 Return Value
4304 ------------
4305 A new device config object with default settings. You will typically want to adjust the config after this function returns. See remarks.
4306 
4307 
4308 Thread Safety
4309 -------------
4310 Safe.
4311 
4312 
4313 Callback Safety
4314 ---------------
4315 Safe, but don't try initializing a device in a callback.
4316 
4317 
4318 Remarks
4319 -------
4320 The returned config will be initialized to defaults. You will normally want to customize a few variables before initializing the device. See Example 1 for a
4321 typical configuration which sets the sample format, channel count, sample rate, data callback and user data. These are usually things you will want to change
4322 before initializing the device.
4323 
4324 See `ma_device_init()` for details on specific configuration options.
4325 
4326 
4327 Example 1 - Simple Configuration
4328 --------------------------------
4329 The example below is what a program will typically want to configure for each device at a minimum. Notice how `ma_device_config_init()` is called first, and
4330 then the returned object is modified directly. This is important because it ensures that your program continues to work as new configuration options are added
4331 to the `ma_device_config` structure.
4332 
4333 ```c
4334 ma_device_config config = ma_device_config_init(ma_device_type_playback);
4335 config.playback.format = ma_format_f32;
4336 config.playback.channels = 2;
4337 config.sampleRate = 48000;
4338 config.dataCallback = ma_data_callback;
4339 config.pUserData = pMyUserData;
4340 ```
4341 
4342 
4343 See Also
4344 --------
4345 ma_device_init()
4346 ma_device_init_ex()
4347 */
4349 
4350 
4351 /*
4352 Initializes a device.
4353 
4354 A device represents a physical audio device. The idea is you send or receive audio data from the device to either play it back through a speaker, or capture it
4355 from a microphone. Whether or not you should send or receive data from the device (or both) depends on the type of device you are initializing which can be
4356 playback, capture, full-duplex or loopback. (Note that loopback mode is only supported on select backends.) Sending and receiving audio data to and from the
4357 device is done via a callback which is fired by miniaudio at periodic time intervals.
4358 
4359 The frequency at which data is deilvered to and from a device depends on the size of it's period which is defined by a buffer size and a period count. The size
4360 of the buffer can be defined in terms of PCM frames or milliseconds, whichever is more convenient. The size of a period is the size of this buffer, divided by
4361 the period count. Generally speaking, the smaller the period, the lower the latency at the expense of higher CPU usage and increased risk of glitching due to
4362 the more frequent and granular data deliver intervals. The size of a period will depend on your requirements, but miniaudio's defaults should work fine for
4363 most scenarios. If you're building a game you should leave this fairly small, whereas if you're building a simple media player you can make it larger. Note
4364 that the period size you request is actually just a hint - miniaudio will tell the backend what you want, but the backend is ultimately responsible for what it
4365 gives you. You cannot assume you will get exactly what you ask for.
4366 
4367 When delivering data to and from a device you need to make sure it's in the correct format which you can set through the device configuration. You just set the
4368 format that you want to use and miniaudio will perform all of the necessary conversion for you internally. When delivering data to and from the callback you
4369 can assume the format is the same as what you requested when you initialized the device. See Remarks for more details on miniaudio's data conversion pipeline.
4370 
4371 
4372 Parameters
4373 ----------
4374 pContext (in, optional)
4375  A pointer to the context that owns the device. This can be null, in which case it creates a default context internally.
4376 
4377 pConfig (in)
4378  A pointer to the device configuration. Cannot be null. See remarks for details.
4379 
4380 pDevice (out)
4381  A pointer to the device object being initialized.
4382 
4383 
4384 Return Value
4385 ------------
4386 MA_SUCCESS if successful; any other error code otherwise.
4387 
4388 
4389 Thread Safety
4390 -------------
4391 Unsafe. It is not safe to call this function simultaneously for different devices because some backends depend on and mutate global state. The same applies to
4392 calling this at the same time as `ma_device_uninit()`.
4393 
4394 
4395 Callback Safety
4396 ---------------
4397 Unsafe. It is not safe to call this inside any callback.
4398 
4399 
4400 Remarks
4401 -------
4402 Setting `pContext` to NULL will result in miniaudio creating a default context internally and is equivalent to passing in a context initialized like so:
4403 
4404  ```c
4405  ma_context_init(NULL, 0, NULL, &context);
4406  ```
4407 
4408 Do not set `pContext` to NULL if you are needing to open multiple devices. You can, however, use NULL when initializing the first device, and then use
4409 device.pContext for the initialization of other devices.
4410 
4411 The device can be configured via the `pConfig` argument. The config object is initialized with `ma_device_config_init()`. Individual configuration settings can
4412 then be set directly on the structure. Below are the members of the `ma_device_config` object.
4413 
4414  deviceType
4415  Must be `ma_device_type_playback`, `ma_device_type_capture`, `ma_device_type_duplex` of `ma_device_type_loopback`.
4416 
4417  sampleRate
4418  The sample rate, in hertz. The most common sample rates are 48000 and 44100. Setting this to 0 will use the device's native sample rate.
4419 
4420  periodSizeInFrames
4421  The desired size of a period in PCM frames. If this is 0, `periodSizeInMilliseconds` will be used instead. If both are 0 the default buffer size will
4422  be used depending on the selected performance profile. This value affects latency. See below for details.
4423 
4424  periodSizeInMilliseconds
4425  The desired size of a period in milliseconds. If this is 0, `periodSizeInFrames` will be used instead. If both are 0 the default buffer size will be
4426  used depending on the selected performance profile. The value affects latency. See below for details.
4427 
4428  periods
4429  The number of periods making up the device's entire buffer. The total buffer size is `periodSizeInFrames` or `periodSizeInMilliseconds` multiplied by
4430  this value. This is just a hint as backends will be the ones who ultimately decide how your periods will be configured.
4431 
4432  performanceProfile
4433  A hint to miniaudio as to the performance requirements of your program. Can be either `ma_performance_profile_low_latency` (default) or
4434  `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at it's default value.
4435 
4436  noPreZeroedOutputBuffer
4437  When set to true, the contents of the output buffer passed into the data callback will be left undefined. When set to false (default), the contents of
4438  the output buffer will be cleared the zero. You can use this to avoid the overhead of zeroing out the buffer if you know can guarantee that your data
4439  callback will write to every sample in the output buffer, or if you are doing your own clearing.
4440 
4441  noClip
4442  When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. When set to false (default), the
4443  contents of the output buffer are left alone after returning and it will be left up to the backend itself to decide whether or not the clip. This only
4444  applies when the playback sample format is f32.
4445 
4446  dataCallback
4447  The callback to fire whenever data is ready to be delivered to or from the device.
4448 
4449  stopCallback
4450  The callback to fire whenever the device has stopped, either explicitly via `ma_device_stop()`, or implicitly due to things like the device being
4451  disconnected.
4452 
4453  pUserData
4454  The user data pointer to use with the device. You can access this directly from the device object like `device.pUserData`.
4455 
4456  resampling.algorithm
4457  The resampling algorithm to use when miniaudio needs to perform resampling between the rate specified by `sampleRate` and the device's native rate. The
4458  default value is `ma_resample_algorithm_linear`, and the quality can be configured with `resampling.linear.lpfOrder`.
4459 
4460  resampling.linear.lpfOrder
4461  The linear resampler applies a low-pass filter as part of it's procesing for anti-aliasing. This setting controls the order of the filter. The higher
4462  the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is
4463  `MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`.
4464 
4465  playback.pDeviceID
4466  A pointer to a `ma_device_id` structure containing the ID of the playback device to initialize. Setting this NULL (default) will use the system's
4467  default playback device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration.
4468 
4469  playback.format
4470  The sample format to use for playback. When set to `ma_format_unknown` the device's native format will be used. This can be retrieved after
4471  initialization from the device object directly with `device.playback.format`.
4472 
4473  playback.channels
4474  The number of channels to use for playback. When set to 0 the device's native channel count will be used. This can be retrieved after initialization
4475  from the device object directly with `device.playback.channels`.
4476 
4477  playback.channelMap
4478  The channel map to use for playback. When left empty, the device's native channel map will be used. This can be retrieved after initialization from the
4479  device object direct with `device.playback.channelMap`.
4480 
4481  playback.shareMode
4482  The preferred share mode to use for playback. Can be either `ma_share_mode_shared` (default) or `ma_share_mode_exclusive`. Note that if you specify
4483  exclusive mode, but it's not supported by the backend, initialization will fail. You can then fall back to shared mode if desired.
4484 
4485  playback.pDeviceID
4486  A pointer to a `ma_device_id` structure containing the ID of the playback device to initialize. Setting this NULL (default) will use the system's
4487  default playback device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration.
4488 
4489  capture.format
4490  The sample format to use for capture. When set to `ma_format_unknown` the device's native format will be used. This can be retrieved after
4491  initialization from the device object directly with `device.capture.format`.
4492 
4493  capture.channels
4494  The number of channels to use for capture. When set to 0 the device's native channel count will be used. This can be retrieved after initialization
4495  from the device object directly with `device.capture.channels`.
4496 
4497  capture.channelMap
4498  The channel map to use for capture. When left empty, the device's native channel map will be used. This can be retrieved after initialization from the
4499  device object direct with `device.capture.channelMap`.
4500 
4501  capture.shareMode
4502  The preferred share mode to use for capture. Can be either `ma_share_mode_shared` (default) or `ma_share_mode_exclusive`. Note that if you specify
4503  exclusive mode, but it's not supported by the backend, initialization will fail. You can then fall back to shared mode if desired.
4504 
4505  wasapi.noAutoConvertSRC
4506  WASAPI only. When set to true, disables WASAPI's automatic resampling and forces the use of miniaudio's resampler. Defaults to false.
4507 
4508  wasapi.noDefaultQualitySRC
4509  WASAPI only. Only used when `wasapi.noAutoConvertSRC` is set to false. When set to true, disables the use of `AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY`.
4510  You should usually leave this set to false, which is the default.
4511 
4512  wasapi.noAutoStreamRouting
4513  WASAPI only. When set to true, disables automatic stream routing on the WASAPI backend. Defaults to false.
4514 
4515  wasapi.noHardwareOffloading
4516  WASAPI only. When set to true, disables the use of WASAPI's hardware offloading feature. Defaults to false.
4517 
4518  alsa.noMMap
4519  ALSA only. When set to true, disables MMap mode. Defaults to false.
4520 
4521  pulse.pStreamNamePlayback
4522  PulseAudio only. Sets the stream name for playback.
4523 
4524  pulse.pStreamNameCapture
4525  PulseAudio only. Sets the stream name for capture.
4526 
4527 
4528 Once initialized, the device's config is immutable. If you need to change the config you will need to initialize a new device.
4529 
4530 If both `periodSizeInFrames` and `periodSizeInMilliseconds` are set to zero, it will default to `MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY` or
4531 `MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE`, depending on whether or not `performanceProfile` is set to `ma_performance_profile_low_latency` or
4532 `ma_performance_profile_conservative`.
4533 
4534 If you request exclusive mode and the backend does not support it an error will be returned. For robustness, you may want to first try initializing the device
4535 in exclusive mode, and then fall back to shared mode if required. Alternatively you can just request shared mode (the default if you leave it unset in the
4536 config) which is the most reliable option. Some backends do not have a practical way of choosing whether or not the device should be exclusive or not (ALSA,
4537 for example) in which case it just acts as a hint. Unless you have special requirements you should try avoiding exclusive mode as it's intrusive to the user.
4538 Starting with Windows 10, miniaudio will use low-latency shared mode where possible which may make exclusive mode unnecessary.
4539 
4540 After initializing the device it will be in a stopped state. To start it, use `ma_device_start()`.
4541 
4542 When sending or receiving data to/from a device, miniaudio will internally perform a format conversion to convert between the format specified by pConfig and
4543 the format used internally by the backend. If you pass in 0 for the sample format, channel count, sample rate _and_ channel map, data transmission will run on
4544 an optimized pass-through fast path. You can retrieve the format, channel count and sample rate by inspecting the `playback/capture.format`,
4545 `playback/capture.channels` and `sampleRate` members of the device object.
4546 
4547 When compiling for UWP you must ensure you call this function on the main UI thread because the operating system may need to present the user with a message
4548 asking for permissions. Please refer to the official documentation for ActivateAudioInterfaceAsync() for more information.
4549 
4550 ALSA Specific: When initializing the default device, requesting shared mode will try using the "dmix" device for playback and the "dsnoop" device for capture.
4551 If these fail it will try falling back to the "hw" device.
4552 
4553 
4554 Example 1 - Simple Initialization
4555 ---------------------------------
4556 This example shows how to initialize a simple playback default using a standard configuration. If you are just needing to do simple playback from the default
4557 playback device this is usually all you need.
4558 
4559 ```c
4560 ma_device_config config = ma_device_config_init(ma_device_type_playback);
4561 config.playback.format = ma_format_f32;
4562 config.playback.channels = 2;
4563 config.sampleRate = 48000;
4564 config.dataCallback = ma_data_callback;
4565 config.pMyUserData = pMyUserData;
4566 
4567 ma_device device;
4568 ma_result result = ma_device_init(NULL, &config, &device);
4569 if (result != MA_SUCCESS) {
4570  // Error
4571 }
4572 ```
4573 
4574 
4575 Example 2 - Advanced Initialization
4576 -----------------------------------
4577 This example show how you might do some more advanced initialization. In this hypothetical example we want to control the latency by setting the buffer size
4578 and period count. We also want to allow the user to be able to choose which device to output from which means we need a context so we can perform device
4579 enumeration.
4580 
4581 ```c
4582 ma_context context;
4583 ma_result result = ma_context_init(NULL, 0, NULL, &context);
4584 if (result != MA_SUCCESS) {
4585  // Error
4586 }
4587 
4588 ma_device_info* pPlaybackDeviceInfos;
4589 ma_uint32 playbackDeviceCount;
4590 result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL);
4591 if (result != MA_SUCCESS) {
4592  // Error
4593 }
4594 
4595 // ... choose a device from pPlaybackDeviceInfos ...
4596 
4597 ma_device_config config = ma_device_config_init(ma_device_type_playback);
4598 config.playback.pDeviceID = pMyChosenDeviceID; // <-- Get this from the `id` member of one of the `ma_device_info` objects returned by ma_context_get_devices().
4599 config.playback.format = ma_format_f32;
4600 config.playback.channels = 2;
4601 config.sampleRate = 48000;
4602 config.dataCallback = ma_data_callback;
4603 config.pUserData = pMyUserData;
4604 config.periodSizeInMilliseconds = 10;
4605 config.periods = 3;
4606 
4607 ma_device device;
4608 result = ma_device_init(&context, &config, &device);
4609 if (result != MA_SUCCESS) {
4610  // Error
4611 }
4612 ```
4613 
4614 
4615 See Also
4616 --------
4617 ma_device_config_init()
4618 ma_device_uninit()
4619 ma_device_start()
4620 ma_context_init()
4621 ma_context_get_devices()
4622 ma_context_enumerate_devices()
4623 */
4624 ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice);
4625 
4626 /*
4627 Initializes a device without a context, with extra parameters for controlling the configuration of the internal self-managed context.
4628 
4629 This is the same as `ma_device_init()`, only instead of a context being passed in, the parameters from `ma_context_init()` are passed in instead. This function
4630 allows you to configure the internally created context.
4631 
4632 
4633 Parameters
4634 ----------
4635 backends (in, optional)
4636  A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order.
4637 
4638 backendCount (in, optional)
4639  The number of items in `backend`. Ignored if `backend` is NULL.
4640 
4641 pContextConfig (in, optional)
4642  The context configuration.
4643 
4644 pConfig (in)
4645  A pointer to the device configuration. Cannot be null. See remarks for details.
4646 
4647 pDevice (out)
4648  A pointer to the device object being initialized.
4649 
4650 
4651 Return Value
4652 ------------
4653 MA_SUCCESS if successful; any other error code otherwise.
4654 
4655 
4656 Thread Safety
4657 -------------
4658 Unsafe. It is not safe to call this function simultaneously for different devices because some backends depend on and mutate global state. The same applies to
4659 calling this at the same time as `ma_device_uninit()`.
4660 
4661 
4662 Callback Safety
4663 ---------------
4664 Unsafe. It is not safe to call this inside any callback.
4665 
4666 
4667 Remarks
4668 -------
4669 You only need to use this function if you want to configure the context differently to it's defaults. You should never use this function if you want to manage
4670 your own context.
4671 
4672 See the documentation for `ma_context_init()` for information on the different context configuration options.
4673 
4674 
4675 See Also
4676 --------
4677 ma_device_init()
4678 ma_device_uninit()
4679 ma_device_config_init()
4680 ma_context_init()
4681 */
4682 ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pContextConfig, const ma_device_config* pConfig, ma_device* pDevice);
4683 
4684 /*
4685 Uninitializes a device.
4686 
4687 This will explicitly stop the device. You do not need to call `ma_device_stop()` beforehand, but it's harmless if you do.
4688 
4689 
4690 Parameters
4691 ----------
4692 pDevice (in)
4693  A pointer to the device to stop.
4694 
4695 
4696 Return Value
4697 ------------
4698 MA_SUCCESS if successful; any other error code otherwise.
4699 
4700 
4701 Thread Safety
4702 -------------
4703 Unsafe. As soon as this API is called the device should be considered undefined.
4704 
4705 
4706 Callback Safety
4707 ---------------
4708 Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock.
4709 
4710 
4711 See Also
4712 --------
4713 ma_device_init()
4714 ma_device_stop()
4715 */
4716 void ma_device_uninit(ma_device* pDevice);
4717 
4718 /*
4719 Starts the device. For playback devices this begins playback. For capture devices it begins recording.
4720 
4721 Use `ma_device_stop()` to stop the device.
4722 
4723 
4724 Parameters
4725 ----------
4726 pDevice (in)
4727  A pointer to the device to start.
4728 
4729 
4730 Return Value
4731 ------------
4732 MA_SUCCESS if successful; any other error code otherwise.
4733 
4734 
4735 Thread Safety
4736 -------------
4737 Safe. It's safe to call this from any thread with the exception of the callback thread.
4738 
4739 
4740 Callback Safety
4741 ---------------
4742 Unsafe. It is not safe to call this inside any callback.
4743 
4744 
4745 Remarks
4746 -------
4747 For a playback device, this will retrieve an initial chunk of audio data from the client before returning. The reason for this is to ensure there is valid
4748 audio data in the buffer, which needs to be done before the device begins playback.
4749 
4750 This API waits until the backend device has been started for real by the worker thread. It also waits on a mutex for thread-safety.
4751 
4752 Do not call this in any callback.
4753 
4754 
4755 See Also
4756 --------
4757 ma_device_stop()
4758 */
4760 
4761 /*
4762 Stops the device. For playback devices this stops playback. For capture devices it stops recording.
4763 
4764 Use `ma_device_start()` to start the device again.
4765 
4766 
4767 Parameters
4768 ----------
4769 pDevice (in)
4770  A pointer to the device to stop.
4771 
4772 
4773 Return Value
4774 ------------
4775 MA_SUCCESS if successful; any other error code otherwise.
4776 
4777 
4778 Thread Safety
4779 -------------
4780 Safe. It's safe to call this from any thread with the exception of the callback thread.
4781 
4782 
4783 Callback Safety
4784 ---------------
4785 Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock.
4786 
4787 
4788 Remarks
4789 -------
4790 This API needs to wait on the worker thread to stop the backend device properly before returning. It also waits on a mutex for thread-safety. In addition, some
4791 backends need to wait for the device to finish playback/recording of the current fragment which can take some time (usually proportionate to the buffer size
4792 that was specified at initialization time).
4793 
4794 Backends are required to either pause the stream in-place or drain the buffer if pausing is not possible. The reason for this is that stopping the device and
4795 the resuming it with ma_device_start() (which you might do when your program loses focus) may result in a situation where those samples are never output to the
4796 speakers or received from the microphone which can in turn result in de-syncs.
4797 
4798 Do not call this in any callback.
4799 
4800 This will be called implicitly by `ma_device_uninit()`.
4801 
4802 
4803 See Also
4804 --------
4805 ma_device_start()
4806 */
4808 
4809 /*
4810 Determines whether or not the device is started.
4811 
4812 
4813 Parameters
4814 ----------
4815 pDevice (in)
4816  A pointer to the device whose start state is being retrieved.
4817 
4818 
4819 Return Value
4820 ------------
4821 True if the device is started, false otherwise.
4822 
4823 
4824 Thread Safety
4825 -------------
4826 Safe. If another thread calls `ma_device_start()` or `ma_device_stop()` at this same time as this function is called, there's a very small chance the return
4827 value will be out of sync.
4828 
4829 
4830 Callback Safety
4831 ---------------
4832 Safe. This is implemented as a simple accessor.
4833 
4834 
4835 See Also
4836 --------
4837 ma_device_start()
4838 ma_device_stop()
4839 */
4841 
4842 /*
4843 Sets the master volume factor for the device.
4844 
4845 The volume factor must be between 0 (silence) and 1 (full volume). Use `ma_device_set_master_gain_db()` to use decibel notation, where 0 is full volume and
4846 values less than 0 decreases the volume.
4847 
4848 
4849 Parameters
4850 ----------
4851 pDevice (in)
4852  A pointer to the device whose volume is being set.
4853 
4854 volume (in)
4855  The new volume factor. Must be within the range of [0, 1].
4856 
4857 
4858 Return Value
4859 ------------
4860 MA_SUCCESS if the volume was set successfully.
4861 MA_INVALID_ARGS if pDevice is NULL.
4862 MA_INVALID_ARGS if the volume factor is not within the range of [0, 1].
4863 
4864 
4865 Thread Safety
4866 -------------
4867 Safe. This just sets a local member of the device object.
4868 
4869 
4870 Callback Safety
4871 ---------------
4872 Safe. If you set the volume in the data callback, that data written to the output buffer will have the new volume applied.
4873 
4874 
4875 Remarks
4876 -------
4877 This applies the volume factor across all channels.
4878 
4879 This does not change the operating system's volume. It only affects the volume for the given `ma_device` object's audio stream.
4880 
4881 
4882 See Also
4883 --------
4884 ma_device_get_master_volume()
4885 ma_device_set_master_volume_gain_db()
4886 ma_device_get_master_volume_gain_db()
4887 */
4888 ma_result ma_device_set_master_volume(ma_device* pDevice, float volume);
4889 
4890 /*
4891 Retrieves the master volume factor for the device.
4892 
4893 
4894 Parameters
4895 ----------
4896 pDevice (in)
4897  A pointer to the device whose volume factor is being retrieved.
4898 
4899 pVolume (in)
4900  A pointer to the variable that will receive the volume factor. The returned value will be in the range of [0, 1].
4901 
4902 
4903 Return Value
4904 ------------
4905 MA_SUCCESS if successful.
4906 MA_INVALID_ARGS if pDevice is NULL.
4907 MA_INVALID_ARGS if pVolume is NULL.
4908 
4909 
4910 Thread Safety
4911 -------------
4912 Safe. This just a simple member retrieval.
4913 
4914 
4915 Callback Safety
4916 ---------------
4917 Safe.
4918 
4919 
4920 Remarks
4921 -------
4922 If an error occurs, `*pVolume` will be set to 0.
4923 
4924 
4925 See Also
4926 --------
4927 ma_device_set_master_volume()
4928 ma_device_set_master_volume_gain_db()
4929 ma_device_get_master_volume_gain_db()
4930 */
4931 ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume);
4932 
4933 /*
4934 Sets the master volume for the device as gain in decibels.
4935 
4936 A gain of 0 is full volume, whereas a gain of < 0 will decrease the volume.
4937 
4938 
4939 Parameters
4940 ----------
4941 pDevice (in)
4942  A pointer to the device whose gain is being set.
4943 
4944 gainDB (in)
4945  The new volume as gain in decibels. Must be less than or equal to 0, where 0 is full volume and anything less than 0 decreases the volume.
4946 
4947 
4948 Return Value
4949 ------------
4950 MA_SUCCESS if the volume was set successfully.
4951 MA_INVALID_ARGS if pDevice is NULL.
4952 MA_INVALID_ARGS if the gain is > 0.
4953 
4954 
4955 Thread Safety
4956 -------------
4957 Safe. This just sets a local member of the device object.
4958 
4959 
4960 Callback Safety
4961 ---------------
4962 Safe. If you set the volume in the data callback, that data written to the output buffer will have the new volume applied.
4963 
4964 
4965 Remarks
4966 -------
4967 This applies the gain across all channels.
4968 
4969 This does not change the operating system's volume. It only affects the volume for the given `ma_device` object's audio stream.
4970 
4971 
4972 See Also
4973 --------
4974 ma_device_get_master_volume_gain_db()
4975 ma_device_set_master_volume()
4976 ma_device_get_master_volume()
4977 */
4978 ma_result ma_device_set_master_gain_db(ma_device* pDevice, float gainDB);
4979 
4980 /*
4981 Retrieves the master gain in decibels.
4982 
4983 
4984 Parameters
4985 ----------
4986 pDevice (in)
4987  A pointer to the device whose gain is being retrieved.
4988 
4989 pGainDB (in)
4990  A pointer to the variable that will receive the gain in decibels. The returned value will be <= 0.
4991 
4992 
4993 Return Value
4994 ------------
4995 MA_SUCCESS if successful.
4996 MA_INVALID_ARGS if pDevice is NULL.
4997 MA_INVALID_ARGS if pGainDB is NULL.
4998 
4999 
5000 Thread Safety
5001 -------------
5002 Safe. This just a simple member retrieval.
5003 
5004 
5005 Callback Safety
5006 ---------------
5007 Safe.
5008 
5009 
5010 Remarks
5011 -------
5012 If an error occurs, `*pGainDB` will be set to 0.
5013 
5014 
5015 See Also
5016 --------
5017 ma_device_set_master_volume_gain_db()
5018 ma_device_set_master_volume()
5019 ma_device_get_master_volume()
5020 */
5021 ma_result ma_device_get_master_gain_db(ma_device* pDevice, float* pGainDB);
5022 
5023 
5024 
5025 /************************************************************************************************************************************************************
5026 
5027 Utiltities
5028 
5029 ************************************************************************************************************************************************************/
5030 
5031 /*
5032 Creates a mutex.
5033 
5034 A mutex must be created from a valid context. A mutex is initially unlocked.
5035 */
5036 ma_result ma_mutex_init(ma_context* pContext, ma_mutex* pMutex);
5037 
5038 /*
5039 Deletes a mutex.
5040 */
5041 void ma_mutex_uninit(ma_mutex* pMutex);
5042 
5043 /*
5044 Locks a mutex with an infinite timeout.
5045 */
5046 void ma_mutex_lock(ma_mutex* pMutex);
5047 
5048 /*
5049 Unlocks a mutex.
5050 */
5051 void ma_mutex_unlock(ma_mutex* pMutex);
5052 
5053 
5054 /*
5055 Retrieves a friendly name for a backend.
5056 */
5057 const char* ma_get_backend_name(ma_backend backend);
5058 
5059 /*
5060 Determines whether or not loopback mode is support by a backend.
5061 */
5063 
5064 
5065 /*
5066 Adjust buffer size based on a scaling factor.
5067 
5068 This just multiplies the base size by the scaling factor, making sure it's a size of at least 1.
5069 */
5070 ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale);
5071 
5072 /*
5073 Calculates a buffer size in milliseconds from the specified number of frames and sample rate.
5074 */
5076 
5077 /*
5078 Calculates a buffer size in frames from the specified number of milliseconds and sample rate.
5079 */
5081 
5082 /*
5083 Copies silent frames into the given buffer.
5084 */
5085 void ma_zero_pcm_frames(void* p, ma_uint32 frameCount, ma_format format, ma_uint32 channels);
5086 
5087 /*
5088 Clips f32 samples.
5089 */
5090 void ma_clip_samples_f32(float* p, ma_uint32 sampleCount);
5091 MA_INLINE void ma_clip_pcm_frames_f32(float* p, ma_uint32 frameCount, ma_uint32 channels) { ma_clip_samples_f32(p, frameCount*channels); }
5092 
5093 /*
5094 Helper for applying a volume factor to samples.
5095 
5096 Note that the source and destination buffers can be the same, in which case it'll perform the operation in-place.
5097 */
5098 void ma_copy_and_apply_volume_factor_u8(ma_uint8* pSamplesOut, const ma_uint8* pSamplesIn, ma_uint32 sampleCount, float factor);
5099 void ma_copy_and_apply_volume_factor_s16(ma_int16* pSamplesOut, const ma_int16* pSamplesIn, ma_uint32 sampleCount, float factor);
5100 void ma_copy_and_apply_volume_factor_s24(void* pSamplesOut, const void* pSamplesIn, ma_uint32 sampleCount, float factor);
5101 void ma_copy_and_apply_volume_factor_s32(ma_int32* pSamplesOut, const ma_int32* pSamplesIn, ma_uint32 sampleCount, float factor);
5102 void ma_copy_and_apply_volume_factor_f32(float* pSamplesOut, const float* pSamplesIn, ma_uint32 sampleCount, float factor);
5103 
5104 void ma_apply_volume_factor_u8(ma_uint8* pSamples, ma_uint32 sampleCount, float factor);
5105 void ma_apply_volume_factor_s16(ma_int16* pSamples, ma_uint32 sampleCount, float factor);
5106 void ma_apply_volume_factor_s24(void* pSamples, ma_uint32 sampleCount, float factor);
5107 void ma_apply_volume_factor_s32(ma_int32* pSamples, ma_uint32 sampleCount, float factor);
5108 void ma_apply_volume_factor_f32(float* pSamples, ma_uint32 sampleCount, float factor);
5109 
5110 void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFramesOut, const ma_uint8* pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor);
5111 void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFramesOut, const ma_int16* pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor);
5112 void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor);
5113 void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFramesOut, const ma_int32* pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor);
5114 void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pPCMFramesOut, const float* pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor);
5115 void ma_copy_and_apply_volume_factor_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount, ma_format format, ma_uint32 channels, float factor);
5116 
5117 void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pFrames, ma_uint32 frameCount, ma_uint32 channels, float factor);
5118 void ma_apply_volume_factor_pcm_frames_s16(ma_int16* pFrames, ma_uint32 frameCount, ma_uint32 channels, float factor);
5119 void ma_apply_volume_factor_pcm_frames_s24(void* pFrames, ma_uint32 frameCount, ma_uint32 channels, float factor);
5120 void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pFrames, ma_uint32 frameCount, ma_uint32 channels, float factor);
5121 void ma_apply_volume_factor_pcm_frames_f32(float* pFrames, ma_uint32 frameCount, ma_uint32 channels, float factor);
5122 void ma_apply_volume_factor_pcm_frames(void* pFrames, ma_uint32 frameCount, ma_format format, ma_uint32 channels, float factor);
5123 
5124 
5125 /*
5126 Helper for converting a linear factor to gain in decibels.
5127 */
5128 float ma_factor_to_gain_db(float factor);
5129 
5130 /*
5131 Helper for converting gain in decibels to a linear factor.
5132 */
5133 float ma_gain_db_to_factor(float gain);
5134 
5135 #endif /* MA_NO_DEVICE_IO */
5136 
5137 
5138 #if !defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING)
5139 typedef enum
5140 {
5143 } ma_seek_origin;
5144 
5145 typedef enum
5146 {
5149 #endif
5150 
5151 /************************************************************************************************************************************************************
5152 
5153 Decoding
5154 ========
5155 
5156 Decoders are independent of the main device API. Decoding APIs can be called freely inside the device's data callback, but they are not thread safe unless
5157 you do your own synchronization.
5158 
5159 ************************************************************************************************************************************************************/
5160 #ifndef MA_NO_DECODING
5161 typedef struct ma_decoder ma_decoder;
5162 
5163 typedef size_t (* ma_decoder_read_proc) (ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead); /* Returns the number of bytes read. */
5164 typedef ma_bool32 (* ma_decoder_seek_proc) (ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin);
5165 typedef ma_uint64 (* ma_decoder_read_pcm_frames_proc) (ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount); /* Returns the number of frames read. Output data is in internal format. */
5169 
5170 typedef struct
5171 {
5172  ma_format format; /* Set to 0 or ma_format_unknown to use the stream's internal format. */
5173  ma_uint32 channels; /* Set to 0 to use the stream's internal channels. */
5174  ma_uint32 sampleRate; /* Set to 0 to use the stream's internal sample rate. */
5178  struct
5179  {
5181  struct
5182  {
5184  } linear;
5185  struct
5186  {
5187  int quality;
5188  } speex;
5189  } resampling;
5192 
5194 {
5197  void* pUserData;
5198  ma_uint64 readPointer; /* Used for returning back to a previous position after analysing the stream or whatnot. */
5207  ma_data_converter converter; /* <-- Data conversion is achieved by running frames through this. */
5213  void* pInternalDecoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */
5214  struct
5215  {
5216  const ma_uint8* pData;
5217  size_t dataSize;
5219  } memory; /* Only used for decoders that were opened against a block of memory. */
5220 };
5221 
5222 ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate);
5223 
5224 ma_result ma_decoder_init(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5225 ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5226 ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5227 ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5228 ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5229 ma_result ma_decoder_init_raw(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder);
5230 
5231 ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5232 ma_result ma_decoder_init_memory_wav(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5233 ma_result ma_decoder_init_memory_flac(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5234 ma_result ma_decoder_init_memory_vorbis(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5235 ma_result ma_decoder_init_memory_mp3(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5236 ma_result ma_decoder_init_memory_raw(const void* pData, size_t dataSize, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder);
5237 
5238 #ifndef MA_NO_STDIO
5239 ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5240 ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5241 ma_result ma_decoder_init_file_flac(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5242 ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5243 ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5244 
5245 ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5246 ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5247 ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5248 ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5249 ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
5250 #endif
5251 
5253 
5254 /*
5255 Retrieves the length of the decoder in PCM frames.
5256 
5257 Do not call this on streams of an undefined length, such as internet radio.
5258 
5259 If the length is unknown or an error occurs, 0 will be returned.
5260 
5261 This will always return 0 for Vorbis decoders. This is due to a limitation with stb_vorbis in push mode which is what miniaudio
5262 uses internally.
5263 
5264 For MP3's, this will decode the entire file. Do not call this in time critical scenarios.
5265 
5266 This function is not thread safe without your own synchronization.
5267 */
5269 
5270 /*
5271 Reads PCM frames from the given decoder.
5272 
5273 This is not thread safe without your own synchronization.
5274 */
5275 ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount);
5276 
5277 /*
5278 Seeks to a PCM frame based on it's absolute index.
5279 
5280 This is not thread safe without your own synchronization.
5281 */
5283 
5284 /*
5285 Helper for opening and decoding a file into a heap allocated block of memory. Free the returned pointer with ma_free(). On input,
5286 pConfig should be set to what you want. On output it will be set to what you got.
5287 */
5288 #ifndef MA_NO_STDIO
5289 ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppDataOut);
5290 #endif
5291 ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppDataOut);
5292 
5293 #endif /* MA_NO_DECODING */
5294 
5295 
5296 /************************************************************************************************************************************************************
5297 
5298 Encoding
5299 ========
5300 
5301 Encoders do not perform any format conversion for you. If your target format does not support the format, and error will be returned.
5302 
5303 ************************************************************************************************************************************************************/
5304 #ifndef MA_NO_ENCODING
5305 typedef struct ma_encoder ma_encoder;
5306 
5307 typedef size_t (* ma_encoder_write_proc) (ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite); /* Returns the number of bytes written. */
5308 typedef ma_bool32 (* ma_encoder_seek_proc) (ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin);
5310 typedef void (* ma_encoder_uninit_proc) (ma_encoder* pEncoder);
5311 typedef ma_uint64 (* ma_encoder_write_pcm_frames_proc)(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount);
5312 
5313 typedef struct
5314 {
5321 
5322 ma_encoder_config ma_encoder_config_init(ma_resource_format resourceFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate);
5323 
5325 {
5332  void* pUserData;
5333  void* pInternalEncoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */
5334  void* pFile; /* FILE*. Only used when initialized with ma_encoder_init_file(). */
5335 };
5336 
5337 ma_result ma_encoder_init(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void* pUserData, const ma_encoder_config* pConfig, ma_encoder* pEncoder);
5338 #ifndef MA_NO_STDIO
5339 ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder);
5340 ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder);
5341 #endif
5342 void ma_encoder_uninit(ma_encoder* pEncoder);
5343 ma_uint64 ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount);
5344 
5345 #endif /* MA_NO_ENCODING */
5346 
5347 
5348 /************************************************************************************************************************************************************
5349 
5350 Generation
5351 
5352 ************************************************************************************************************************************************************/
5353 typedef enum
5354 {
5361 typedef struct
5367  double amplitude;
5368  double frequency;
5370 
5371 ma_waveform_config ma_waveform_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_waveform_type type, double amplitude, double frequency);
5372 
5373 typedef struct
5374 {
5376  double advance;
5377  double time;
5378 } ma_waveform;
5379 
5380 ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform);
5381 ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount);
5382 ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude);
5383 ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency);
5385 
5386 
5387 
5388 typedef struct
5389 {
5391 } ma_lcg;
5392 
5393 typedef enum
5394 {
5398 } ma_noise_type;
5399 
5400 typedef struct
5401 {
5406  double amplitude;
5408 } ma_noise_config;
5409 
5410 ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels, ma_noise_type type, ma_int32 seed, double amplitude);
5411 
5412 typedef struct
5413 {
5416  union
5417  {
5418  struct
5419  {
5420  double bin[MA_MAX_CHANNELS][16];
5421  double accumulation[MA_MAX_CHANNELS];
5423  } pink;
5424  struct
5425  {
5426  double accumulation[MA_MAX_CHANNELS];
5427  } brownian;
5428  } state;
5429 } ma_noise;
5430 
5431 ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise);
5432 ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount);
5433 
5434 
5435 #ifdef __cplusplus
5436 }
5437 #endif
5438 #endif /* miniaudio_h */
5439 
5440 
5441 
5442 /************************************************************************************************************************************************************
5443 *************************************************************************************************************************************************************
5444 
5445 IMPLEMENTATION
5446 
5447 *************************************************************************************************************************************************************
5448 ************************************************************************************************************************************************************/
5449 #if defined(MINIAUDIO_IMPLEMENTATION) || defined(MA_IMPLEMENTATION)
5450 #include <assert.h>
5451 #include <limits.h> /* For INT_MAX */
5452 #include <math.h> /* sin(), etc. */
5453 
5454 #if !defined(MA_NO_STDIO) || defined(MA_DEBUG_OUTPUT)
5455  #include <stdio.h>
5456  #if !defined(_MSC_VER) && !defined(__DMC__)
5457  #include <strings.h> /* For strcasecmp(). */
5458  #include <wchar.h> /* For wcslen(), wcsrtombs() */
5459  #endif
5460 #endif
5461 
5462 #ifdef MA_WIN32
5463 #include <windows.h>
5464 #include <objbase.h>
5465 #include <mmreg.h>
5466 #include <mmsystem.h>
5467 #else
5468 #include <stdlib.h> /* For malloc(), free(), wcstombs(). */
5469 #include <string.h> /* For memset() */
5470 #endif
5471 
5472 #if defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
5473 #include <mach/mach_time.h> /* For mach_absolute_time() */
5474 #endif
5475 
5476 #ifdef MA_POSIX
5477 #include <sys/time.h>
5478 #include <sys/types.h>
5479 #include <unistd.h>
5480 #include <dlfcn.h>
5481 #endif
5482 
5483 #ifdef MA_EMSCRIPTEN
5484 #include <emscripten/emscripten.h>
5485 #endif
5486 
5487 #if !defined(MA_64BIT) && !defined(MA_32BIT)
5488 #ifdef _WIN32
5489 #ifdef _WIN64
5490 #define MA_64BIT
5491 #else
5492 #define MA_32BIT
5493 #endif
5494 #endif
5495 #endif
5496 
5497 #if !defined(MA_64BIT) && !defined(MA_32BIT)
5498 #ifdef __GNUC__
5499 #ifdef __LP64__
5500 #define MA_64BIT
5501 #else
5502 #define MA_32BIT
5503 #endif
5504 #endif
5505 #endif
5506 
5507 #if !defined(MA_64BIT) && !defined(MA_32BIT)
5508 #include <stdint.h>
5509 #if INTPTR_MAX == INT64_MAX
5510 #define MA_64BIT
5511 #else
5512 #define MA_32BIT
5513 #endif
5514 #endif
5515 
5516 /* Architecture Detection */
5517 #if defined(__x86_64__) || defined(_M_X64)
5518 #define MA_X64
5519 #elif defined(__i386) || defined(_M_IX86)
5520 #define MA_X86
5521 #elif defined(__arm__) || defined(_M_ARM)
5522 #define MA_ARM
5523 #endif
5524 
5525 /* Cannot currently support AVX-512 if AVX is disabled. */
5526 #if !defined(MA_NO_AVX512) && defined(MA_NO_AVX2)
5527 #define MA_NO_AVX512
5528 #endif
5529 
5530 /* Intrinsics Support */
5531 #if defined(MA_X64) || defined(MA_X86)
5532  #if defined(_MSC_VER) && !defined(__clang__)
5533  /* MSVC. */
5534  #if _MSC_VER >= 1400 && !defined(MA_NO_SSE2) /* 2005 */
5535  #define MA_SUPPORT_SSE2
5536  #endif
5537  /*#if _MSC_VER >= 1600 && !defined(MA_NO_AVX)*/ /* 2010 */
5538  /* #define MA_SUPPORT_AVX*/
5539  /*#endif*/
5540  #if _MSC_VER >= 1700 && !defined(MA_NO_AVX2) /* 2012 */
5541  #define MA_SUPPORT_AVX2
5542  #endif
5543  #if _MSC_VER >= 1910 && !defined(MA_NO_AVX512) /* 2017 */
5544  #define MA_SUPPORT_AVX512
5545  #endif
5546  #else
5547  /* Assume GNUC-style. */
5548  #if defined(__SSE2__) && !defined(MA_NO_SSE2)
5549  #define MA_SUPPORT_SSE2
5550  #endif
5551  /*#if defined(__AVX__) && !defined(MA_NO_AVX)*/
5552  /* #define MA_SUPPORT_AVX*/
5553  /*#endif*/
5554  #if defined(__AVX2__) && !defined(MA_NO_AVX2)
5555  #define MA_SUPPORT_AVX2
5556  #endif
5557  #if defined(__AVX512F__) && !defined(MA_NO_AVX512)
5558  #define MA_SUPPORT_AVX512
5559  #endif
5560  #endif
5561 
5562  /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */
5563  #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
5564  #if !defined(MA_SUPPORT_SSE2) && !defined(MA_NO_SSE2) && __has_include(<emmintrin.h>)
5565  #define MA_SUPPORT_SSE2
5566  #endif
5567  /*#if !defined(MA_SUPPORT_AVX) && !defined(MA_NO_AVX) && __has_include(<immintrin.h>)*/
5568  /* #define MA_SUPPORT_AVX*/
5569  /*#endif*/
5570  #if !defined(MA_SUPPORT_AVX2) && !defined(MA_NO_AVX2) && __has_include(<immintrin.h>)
5571  #define MA_SUPPORT_AVX2
5572  #endif
5573  #if !defined(MA_SUPPORT_AVX512) && !defined(MA_NO_AVX512) && __has_include(<zmmintrin.h>)
5574  #define MA_SUPPORT_AVX512
5575  #endif
5576  #endif
5577 
5578  #if defined(MA_SUPPORT_AVX512)
5579  #include <immintrin.h> /* Not a mistake. Intentionally including <immintrin.h> instead of <zmmintrin.h> because otherwise the compiler will complain. */
5580  #elif defined(MA_SUPPORT_AVX2) || defined(MA_SUPPORT_AVX)
5581  #include <immintrin.h>
5582  #elif defined(MA_SUPPORT_SSE2)
5583  #include <emmintrin.h>
5584  #endif
5585 #endif
5586 
5587 #if defined(MA_ARM)
5588  #if !defined(MA_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
5589  #define MA_SUPPORT_NEON
5590  #endif
5591 
5592  /* Fall back to looking for the #include file. */
5593  #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
5594  #if !defined(MA_SUPPORT_NEON) && !defined(MA_NO_NEON) && __has_include(<arm_neon.h>)
5595  #define MA_SUPPORT_NEON
5596  #endif
5597  #endif
5598 
5599  #if defined(MA_SUPPORT_NEON)
5600  #include <arm_neon.h>
5601  #endif
5602 #endif
5603 
5604 /* Begin globally disabled warnings. */
5605 #if defined(_MSC_VER)
5606  #pragma warning(push)
5607  #pragma warning(disable:4752) /* found Intel(R) Advanced Vector Extensions; consider using /arch:AVX */
5608 #endif
5609 
5610 #if defined(MA_X64) || defined(MA_X86)
5611  #if defined(_MSC_VER) && !defined(__clang__)
5612  #if _MSC_VER >= 1400
5613  #include <intrin.h>
5614  static MA_INLINE void ma_cpuid(int info[4], int fid)
5615  {
5616  __cpuid(info, fid);
5617  }
5618  #else
5619  #define MA_NO_CPUID
5620  #endif
5621 
5622  #if _MSC_VER >= 1600 && (defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219)
5623  static MA_INLINE unsigned __int64 ma_xgetbv(int reg)
5624  {
5625  return _xgetbv(reg);
5626  }
5627  #else
5628  #define MA_NO_XGETBV
5629  #endif
5630  #elif (defined(__GNUC__) || defined(__clang__)) && !defined(MA_ANDROID)
5631  static MA_INLINE void ma_cpuid(int info[4], int fid)
5632  {
5633  /*
5634  It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the
5635  specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for
5636  supporting different assembly dialects.
5637 
5638  What's basically happening is that we're saving and restoring the ebx register manually.
5639  */
5640  #if defined(DRFLAC_X86) && defined(__PIC__)
5641  __asm__ __volatile__ (
5642  "xchg{l} {%%}ebx, %k1;"
5643  "cpuid;"
5644  "xchg{l} {%%}ebx, %k1;"
5645  : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
5646  );
5647  #else
5648  __asm__ __volatile__ (
5649  "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
5650  );
5651  #endif
5652  }
5653 
5654  static MA_INLINE ma_uint64 ma_xgetbv(int reg)
5655  {
5656  unsigned int hi;
5657  unsigned int lo;
5658 
5659  __asm__ __volatile__ (
5660  "xgetbv" : "=a"(lo), "=d"(hi) : "c"(reg)
5661  );
5662 
5663  return ((ma_uint64)hi << 32) | (ma_uint64)lo;
5664  }
5665  #else
5666  #define MA_NO_CPUID
5667  #define MA_NO_XGETBV
5668  #endif
5669 #else
5670  #define MA_NO_CPUID
5671  #define MA_NO_XGETBV
5672 #endif
5673 
5675 {
5676 #if defined(MA_SUPPORT_SSE2)
5677  #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_SSE2)
5678  #if defined(MA_X64)
5679  return MA_TRUE; /* 64-bit targets always support SSE2. */
5680  #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)
5681  return MA_TRUE; /* If the compiler is allowed to freely generate SSE2 code we can assume support. */
5682  #else
5683  #if defined(MA_NO_CPUID)
5684  return MA_FALSE;
5685  #else
5686  int info[4];
5687  ma_cpuid(info, 1);
5688  return (info[3] & (1 << 26)) != 0;
5689  #endif
5690  #endif
5691  #else
5692  return MA_FALSE; /* SSE2 is only supported on x86 and x64 architectures. */
5693  #endif
5694 #else
5695  return MA_FALSE; /* No compiler support. */
5696 #endif
5697 }
5698 
5699 #if 0
5700 static MA_INLINE ma_bool32 ma_has_avx()
5701 {
5702 #if defined(MA_SUPPORT_AVX)
5703  #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX)
5704  #if defined(_AVX_) || defined(__AVX__)
5705  return MA_TRUE; /* If the compiler is allowed to freely generate AVX code we can assume support. */
5706  #else
5707  /* AVX requires both CPU and OS support. */
5708  #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV)
5709  return MA_FALSE;
5710  #else
5711  int info[4];
5712  ma_cpuid(info, 1);
5713  if (((info[2] & (1 << 27)) != 0) && ((info[2] & (1 << 28)) != 0)) {
5714  ma_uint64 xrc = ma_xgetbv(0);
5715  if ((xrc & 0x06) == 0x06) {
5716  return MA_TRUE;
5717  } else {
5718  return MA_FALSE;
5719  }
5720  } else {
5721  return MA_FALSE;
5722  }
5723  #endif
5724  #endif
5725  #else
5726  return MA_FALSE; /* AVX is only supported on x86 and x64 architectures. */
5727  #endif
5728 #else
5729  return MA_FALSE; /* No compiler support. */
5730 #endif
5731 }
5732 #endif
5733 
5735 {
5736 #if defined(MA_SUPPORT_AVX2)
5737  #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX2)
5738  #if defined(_AVX2_) || defined(__AVX2__)
5739  return MA_TRUE; /* If the compiler is allowed to freely generate AVX2 code we can assume support. */
5740  #else
5741  /* AVX2 requires both CPU and OS support. */
5742  #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV)
5743  return MA_FALSE;
5744  #else
5745  int info1[4];
5746  int info7[4];
5747  ma_cpuid(info1, 1);
5748  ma_cpuid(info7, 7);
5749  if (((info1[2] & (1 << 27)) != 0) && ((info7[1] & (1 << 5)) != 0)) {
5750  ma_uint64 xrc = ma_xgetbv(0);
5751  if ((xrc & 0x06) == 0x06) {
5752  return MA_TRUE;
5753  } else {
5754  return MA_FALSE;
5755  }
5756  } else {
5757  return MA_FALSE;
5758  }
5759  #endif
5760  #endif
5761  #else
5762  return MA_FALSE; /* AVX2 is only supported on x86 and x64 architectures. */
5763  #endif
5764 #else
5765  return MA_FALSE; /* No compiler support. */
5766 #endif
5767 }
5768 
5770 {
5771 #if defined(MA_SUPPORT_AVX512)
5772  #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX512)
5773  #if defined(__AVX512F__)
5774  return MA_TRUE; /* If the compiler is allowed to freely generate AVX-512F code we can assume support. */
5775  #else
5776  /* AVX-512 requires both CPU and OS support. */
5777  #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV)
5778  return MA_FALSE;
5779  #else
5780  int info1[4];
5781  int info7[4];
5782  ma_cpuid(info1, 1);
5783  ma_cpuid(info7, 7);
5784  if (((info1[2] & (1 << 27)) != 0) && ((info7[1] & (1 << 16)) != 0)) {
5785  ma_uint64 xrc = ma_xgetbv(0);
5786  if ((xrc & 0xE6) == 0xE6) {
5787  return MA_TRUE;
5788  } else {
5789  return MA_FALSE;
5790  }
5791  } else {
5792  return MA_FALSE;
5793  }
5794  #endif
5795  #endif
5796  #else
5797  return MA_FALSE; /* AVX-512F is only supported on x86 and x64 architectures. */
5798  #endif
5799 #else
5800  return MA_FALSE; /* No compiler support. */
5801 #endif
5802 }
5803 
5805 {
5806 #if defined(MA_SUPPORT_NEON)
5807  #if defined(MA_ARM) && !defined(MA_NO_NEON)
5808  #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
5809  return MA_TRUE; /* If the compiler is allowed to freely generate NEON code we can assume support. */
5810  #else
5811  /* TODO: Runtime check. */
5812  return MA_FALSE;
5813  #endif
5814  #else
5815  return MA_FALSE; /* NEON is only supported on ARM architectures. */
5816  #endif
5817 #else
5818  return MA_FALSE; /* No compiler support. */
5819 #endif
5820 }
5821 
5822 #define MA_SIMD_NONE 0
5823 #define MA_SIMD_SSE2 1
5824 #define MA_SIMD_AVX2 2
5825 #define MA_SIMD_NEON 3
5826 
5827 #ifndef MA_PREFERRED_SIMD
5828  # if defined(MA_SUPPORT_SSE2) && defined(MA_PREFER_SSE2)
5829  #define MA_PREFERRED_SIMD MA_SIMD_SSE2
5830  #elif defined(MA_SUPPORT_AVX2) && defined(MA_PREFER_AVX2)
5831  #define MA_PREFERRED_SIMD MA_SIMD_AVX2
5832  #elif defined(MA_SUPPORT_NEON) && defined(MA_PREFER_NEON)
5833  #define MA_PREFERRED_SIMD MA_SIMD_NEON
5834  #else
5835  #define MA_PREFERRED_SIMD MA_SIMD_NONE
5836  #endif
5837 #endif
5838 
5839 
5841 {
5842 #if defined(MA_X86) || defined(MA_X64)
5843  return MA_TRUE;
5844 #else
5845  int n = 1;
5846  return (*(char*)&n) == 1;
5847 #endif
5848 }
5849 
5851 {
5852  return !ma_is_little_endian();
5853 }
5854 
5855 
5856 #ifndef MA_COINIT_VALUE
5857 #define MA_COINIT_VALUE 0 /* 0 = COINIT_MULTITHREADED */
5858 #endif
5859 
5860 
5861 
5862 #ifndef MA_PI
5863 #define MA_PI 3.14159265358979323846264f
5864 #endif
5865 #ifndef MA_PI_D
5866 #define MA_PI_D 3.14159265358979323846264
5867 #endif
5868 #ifndef MA_TAU
5869 #define MA_TAU 6.28318530717958647693f
5870 #endif
5871 #ifndef MA_TAU_D
5872 #define MA_TAU_D 6.28318530717958647693
5873 #endif
5874 
5875 
5876 /* The default format when ma_format_unknown (0) is requested when initializing a device. */
5877 #ifndef MA_DEFAULT_FORMAT
5878 #define MA_DEFAULT_FORMAT ma_format_f32
5879 #endif
5880 
5881 /* The default channel count to use when 0 is used when initializing a device. */
5882 #ifndef MA_DEFAULT_CHANNELS
5883 #define MA_DEFAULT_CHANNELS 2
5884 #endif
5885 
5886 /* The default sample rate to use when 0 is used when initializing a device. */
5887 #ifndef MA_DEFAULT_SAMPLE_RATE
5888 #define MA_DEFAULT_SAMPLE_RATE 48000
5889 #endif
5890 
5891 /* Default periods when none is specified in ma_device_init(). More periods means more work on the CPU. */
5892 #ifndef MA_DEFAULT_PERIODS
5893 #define MA_DEFAULT_PERIODS 3
5894 #endif
5895 
5896 /* The default period size in milliseconds for low latency mode. */
5897 #ifndef MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY
5898 #define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY 10
5899 #endif
5900 
5901 /* The default buffer size in milliseconds for conservative mode. */
5902 #ifndef MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE
5903 #define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE 100
5904 #endif
5905 
5906 /* The default LPF filter order for linear resampling. Note that this is clamped to MA_MAX_FILTER_ORDER. */
5907 #ifndef MA_DEFAULT_RESAMPLER_LPF_ORDER
5908  #if MA_MAX_FILTER_ORDER >= 4
5909  #define MA_DEFAULT_RESAMPLER_LPF_ORDER 4
5910  #else
5911  #define MA_DEFAULT_RESAMPLER_LPF_ORDER MA_MAX_FILTER_ORDER
5912  #endif
5913 #endif
5914 
5915 
5916 /* Standard sample rates, in order of priority. */
5918  MA_SAMPLE_RATE_48000, /* Most common */
5920 
5921  MA_SAMPLE_RATE_32000, /* Lows */
5924 
5925  MA_SAMPLE_RATE_88200, /* Highs */
5929 
5930  MA_SAMPLE_RATE_16000, /* Extreme lows */
5933 
5934  MA_SAMPLE_RATE_352800, /* Extreme highs */
5936 };
5937 
5939  ma_format_s16, /* Most common */
5940  ma_format_f32,
5941 
5942  /*ma_format_s24_32,*/ /* Clean alignment */
5943  ma_format_s32,
5944 
5945  ma_format_s24, /* Unclean alignment */
5946 
5947  ma_format_u8 /* Low quality */
5948 };
5949 
5950 
5951 
5952 /******************************************************************************
5953 
5954 Standard Library Stuff
5955 
5956 ******************************************************************************/
5957 #ifndef MA_MALLOC
5958 #ifdef MA_WIN32
5959 #define MA_MALLOC(sz) HeapAlloc(GetProcessHeap(), 0, (sz))
5960 #else
5961 #define MA_MALLOC(sz) malloc((sz))
5962 #endif
5963 #endif
5964 
5965 #ifndef MA_REALLOC
5966 #ifdef MA_WIN32
5967 #define MA_REALLOC(p, sz) (((sz) > 0) ? ((p) ? HeapReAlloc(GetProcessHeap(), 0, (p), (sz)) : HeapAlloc(GetProcessHeap(), 0, (sz))) : ((VOID*)(size_t)(HeapFree(GetProcessHeap(), 0, (p)) & 0)))
5968 #else
5969 #define MA_REALLOC(p, sz) realloc((p), (sz))
5970 #endif
5971 #endif
5972 
5973 #ifndef MA_FREE
5974 #ifdef MA_WIN32
5975 #define MA_FREE(p) HeapFree(GetProcessHeap(), 0, (p))
5976 #else
5977 #define MA_FREE(p) free((p))
5978 #endif
5979 #endif
5980 
5981 #ifndef MA_ZERO_MEMORY
5982 #ifdef MA_WIN32
5983 #define MA_ZERO_MEMORY(p, sz) ZeroMemory((p), (sz))
5984 #else
5985 #define MA_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
5986 #endif
5987 #endif
5988 
5989 #ifndef MA_COPY_MEMORY
5990 #ifdef MA_WIN32
5991 #define MA_COPY_MEMORY(dst, src, sz) CopyMemory((dst), (src), (sz))
5992 #else
5993 #define MA_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
5994 #endif
5995 #endif
5996 
5997 #ifndef MA_ASSERT
5998 #ifdef MA_WIN32
5999 #define MA_ASSERT(condition) assert(condition)
6000 #else
6001 #define MA_ASSERT(condition) assert(condition)
6002 #endif
6003 #endif
6004 
6005 #define MA_ZERO_OBJECT(p) MA_ZERO_MEMORY((p), sizeof(*(p)))
6006 
6007 #define ma_countof(x) (sizeof(x) / sizeof(x[0]))
6008 #define ma_max(x, y) (((x) > (y)) ? (x) : (y))
6009 #define ma_min(x, y) (((x) < (y)) ? (x) : (y))
6010 #define ma_abs(x) (((x) > 0) ? (x) : -(x))
6011 #define ma_clamp(x, lo, hi) (ma_max(lo, ma_min(x, hi)))
6012 #define ma_offset_ptr(p, offset) (((ma_uint8*)(p)) + (offset))
6013 
6014 #define ma_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / ma_get_bytes_per_sample(format) / (channels))
6015 
6016 static MA_INLINE double ma_sin(double x)
6017 {
6018  /* TODO: Implement custom sin(x). */
6019  return sin(x);
6020 }
6021 
6022 static MA_INLINE double ma_exp(double x)
6023 {
6024  /* TODO: Implement custom exp(x). */
6025  return exp(x);
6026 }
6027 
6028 static MA_INLINE double ma_log(double x)
6029 {
6030  /* TODO: Implement custom log(x). */
6031  return log(x);
6032 }
6033 
6034 static MA_INLINE double ma_pow(double x, double y)
6035 {
6036  /* TODO: Implement custom pow(x, y). */
6037  return pow(x, y);
6038 }
6039 
6040 static MA_INLINE double ma_sqrt(double x)
6041 {
6042  /* TODO: Implement custom sqrt(x). */
6043  return sqrt(x);
6044 }
6045 
6046 
6047 static MA_INLINE double ma_cos(double x)
6048 {
6049  return ma_sin((MA_PI*0.5) - x);
6050 }
6051 
6052 static MA_INLINE double ma_log10(double x)
6053 {
6054  return ma_log(x) * 0.43429448190325182765;
6055 }
6056 
6057 static MA_INLINE float ma_powf(float x, float y)
6058 {
6059  return (float)ma_pow((double)x, (double)y);
6060 }
6061 
6062 static MA_INLINE float ma_log10f(float x)
6063 {
6064  return (float)ma_log10((double)x);
6065 }
6066 
6067 
6068 /*
6069 Return Values:
6070  0: Success
6071  22: EINVAL
6072  34: ERANGE
6073 
6074 Not using symbolic constants for errors because I want to avoid #including errno.h
6075 */
6076 int ma_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src)
6077 {
6078  size_t i;
6079 
6080  if (dst == 0) {
6081  return 22;
6082  }
6083  if (dstSizeInBytes == 0) {
6084  return 34;
6085  }
6086  if (src == 0) {
6087  dst[0] = '\0';
6088  return 22;
6089  }
6090 
6091  for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) {
6092  dst[i] = src[i];
6093  }
6094 
6095  if (i < dstSizeInBytes) {
6096  dst[i] = '\0';
6097  return 0;
6098  }
6099 
6100  dst[0] = '\0';
6101  return 34;
6102 }
6103 
6104 int ma_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count)
6105 {
6106  size_t maxcount;
6107  size_t i;
6108 
6109  if (dst == 0) {
6110  return 22;
6111  }
6112  if (dstSizeInBytes == 0) {
6113  return 34;
6114  }
6115  if (src == 0) {
6116  dst[0] = '\0';
6117  return 22;
6118  }
6119 
6120  maxcount = count;
6121  if (count == ((size_t)-1) || count >= dstSizeInBytes) { /* -1 = _TRUNCATE */
6122  maxcount = dstSizeInBytes - 1;
6123  }
6124 
6125  for (i = 0; i < maxcount && src[i] != '\0'; ++i) {
6126  dst[i] = src[i];
6127  }
6128 
6129  if (src[i] == '\0' || i == count || count == ((size_t)-1)) {
6130  dst[i] = '\0';
6131  return 0;
6132  }
6133 
6134  dst[0] = '\0';
6135  return 34;
6136 }
6137 
6138 int ma_strcat_s(char* dst, size_t dstSizeInBytes, const char* src)
6139 {
6140  char* dstorig;
6141 
6142  if (dst == 0) {
6143  return 22;
6144  }
6145  if (dstSizeInBytes == 0) {
6146  return 34;
6147  }
6148  if (src == 0) {
6149  dst[0] = '\0';
6150  return 22;
6151  }
6152 
6153  dstorig = dst;
6154 
6155  while (dstSizeInBytes > 0 && dst[0] != '\0') {
6156  dst += 1;
6157  dstSizeInBytes -= 1;
6158  }
6159 
6160  if (dstSizeInBytes == 0) {
6161  return 22; /* Unterminated. */
6162  }
6163 
6164 
6165  while (dstSizeInBytes > 0 && src[0] != '\0') {
6166  *dst++ = *src++;
6167  dstSizeInBytes -= 1;
6168  }
6169 
6170  if (dstSizeInBytes > 0) {
6171  dst[0] = '\0';
6172  } else {
6173  dstorig[0] = '\0';
6174  return 34;
6175  }
6176 
6177  return 0;
6178 }
6179 
6180 int ma_strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count)
6181 {
6182  char* dstorig;
6183 
6184  if (dst == 0) {
6185  return 22;
6186  }
6187  if (dstSizeInBytes == 0) {
6188  return 34;
6189  }
6190  if (src == 0) {
6191  return 22;
6192  }
6193 
6194  dstorig = dst;
6195 
6196  while (dstSizeInBytes > 0 && dst[0] != '\0') {
6197  dst += 1;
6198  dstSizeInBytes -= 1;
6199  }
6200 
6201  if (dstSizeInBytes == 0) {
6202  return 22; /* Unterminated. */
6203  }
6204 
6205 
6206  if (count == ((size_t)-1)) { /* _TRUNCATE */
6207  count = dstSizeInBytes - 1;
6208  }
6209 
6210  while (dstSizeInBytes > 0 && src[0] != '\0' && count > 0) {
6211  *dst++ = *src++;
6212  dstSizeInBytes -= 1;
6213  count -= 1;
6214  }
6215 
6216  if (dstSizeInBytes > 0) {
6217  dst[0] = '\0';
6218  } else {
6219  dstorig[0] = '\0';
6220  return 34;
6221  }
6222 
6223  return 0;
6224 }
6225 
6226 int ma_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix)
6227 {
6228  int sign;
6229  unsigned int valueU;
6230  char* dstEnd;
6231 
6232  if (dst == NULL || dstSizeInBytes == 0) {
6233  return 22;
6234  }
6235  if (radix < 2 || radix > 36) {
6236  dst[0] = '\0';
6237  return 22;
6238  }
6239 
6240  sign = (value < 0 && radix == 10) ? -1 : 1; /* The negative sign is only used when the base is 10. */
6241 
6242  if (value < 0) {
6243  valueU = -value;
6244  } else {
6245  valueU = value;
6246  }
6247 
6248  dstEnd = dst;
6249  do
6250  {
6251  int remainder = valueU % radix;
6252  if (remainder > 9) {
6253  *dstEnd = (char)((remainder - 10) + 'a');
6254  } else {
6255  *dstEnd = (char)(remainder + '0');
6256  }
6257 
6258  dstEnd += 1;
6259  dstSizeInBytes -= 1;
6260  valueU /= radix;
6261  } while (dstSizeInBytes > 0 && valueU > 0);
6262 
6263  if (dstSizeInBytes == 0) {
6264  dst[0] = '\0';
6265  return 22; /* Ran out of room in the output buffer. */
6266  }
6267 
6268  if (sign < 0) {
6269  *dstEnd++ = '-';
6270  dstSizeInBytes -= 1;
6271  }
6272 
6273  if (dstSizeInBytes == 0) {
6274  dst[0] = '\0';
6275  return 22; /* Ran out of room in the output buffer. */
6276  }
6277 
6278  *dstEnd = '\0';
6279 
6280 
6281  /* At this point the string will be reversed. */
6282  dstEnd -= 1;
6283  while (dst < dstEnd) {
6284  char temp = *dst;
6285  *dst = *dstEnd;
6286  *dstEnd = temp;
6287 
6288  dst += 1;
6289  dstEnd -= 1;
6290  }
6291 
6292  return 0;
6293 }
6294 
6295 int ma_strcmp(const char* str1, const char* str2)
6296 {
6297  if (str1 == str2) return 0;
6298 
6299  /* These checks differ from the standard implementation. It's not important, but I prefer it just for sanity. */
6300  if (str1 == NULL) return -1;
6301  if (str2 == NULL) return 1;
6302 
6303  for (;;) {
6304  if (str1[0] == '\0') {
6305  break;
6306  }
6307  if (str1[0] != str2[0]) {
6308  break;
6309  }
6310 
6311  str1 += 1;
6312  str2 += 1;
6313  }
6314 
6315  return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0];
6316 }
6317 
6318 int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB)
6319 {
6320  int result;
6321 
6322  result = ma_strncpy_s(dst, dstSize, srcA, (size_t)-1);
6323  if (result != 0) {
6324  return result;
6325  }
6326 
6327  result = ma_strncat_s(dst, dstSize, srcB, (size_t)-1);
6328  if (result != 0) {
6329  return result;
6330  }
6331 
6332  return result;
6333 }
6334 
6335 char* ma_copy_string(const char* src, const ma_allocation_callbacks* pAllocationCallbacks)
6336 {
6337  size_t sz = strlen(src)+1;
6338  char* dst = (char*)ma_malloc(sz, pAllocationCallbacks);
6339  if (dst == NULL) {
6340  return NULL;
6341  }
6342 
6343  ma_strcpy_s(dst, sz, src);
6344 
6345  return dst;
6346 }
6347 
6348 
6349 #include <errno.h>
6350 static ma_result ma_result_from_errno(int e)
6351 {
6352  switch (e)
6353  {
6354  case 0: return MA_SUCCESS;
6355  #ifdef EPERM
6356  case EPERM: return MA_INVALID_OPERATION;
6357  #endif
6358  #ifdef ENOENT
6359  case ENOENT: return MA_DOES_NOT_EXIST;
6360  #endif
6361  #ifdef ESRCH
6362  case ESRCH: return MA_DOES_NOT_EXIST;
6363  #endif
6364  #ifdef EINTR
6365  case EINTR: return MA_INTERRUPT;
6366  #endif
6367  #ifdef EIO
6368  case EIO: return MA_IO_ERROR;
6369  #endif
6370  #ifdef ENXIO
6371  case ENXIO: return MA_DOES_NOT_EXIST;
6372  #endif
6373  #ifdef E2BIG
6374  case E2BIG: return MA_INVALID_ARGS;
6375  #endif
6376  #ifdef ENOEXEC
6377  case ENOEXEC: return MA_INVALID_FILE;
6378  #endif
6379  #ifdef EBADF
6380  case EBADF: return MA_INVALID_FILE;
6381  #endif
6382  #ifdef ECHILD
6383  case ECHILD: return MA_ERROR;
6384  #endif
6385  #ifdef EAGAIN
6386  case EAGAIN: return MA_UNAVAILABLE;
6387  #endif
6388  #ifdef ENOMEM
6389  case ENOMEM: return MA_OUT_OF_MEMORY;
6390  #endif
6391  #ifdef EACCES
6392  case EACCES: return MA_ACCESS_DENIED;
6393  #endif
6394  #ifdef EFAULT
6395  case EFAULT: return MA_BAD_ADDRESS;
6396  #endif
6397  #ifdef ENOTBLK
6398  case ENOTBLK: return MA_ERROR;
6399  #endif
6400  #ifdef EBUSY
6401  case EBUSY: return MA_BUSY;
6402  #endif
6403  #ifdef EEXIST
6404  case EEXIST: return MA_ALREADY_EXISTS;
6405  #endif
6406  #ifdef EXDEV
6407  case EXDEV: return MA_ERROR;
6408  #endif
6409  #ifdef ENODEV
6410  case ENODEV: return MA_DOES_NOT_EXIST;
6411  #endif
6412  #ifdef ENOTDIR
6413  case ENOTDIR: return MA_NOT_DIRECTORY;
6414  #endif
6415  #ifdef EISDIR
6416  case EISDIR: return MA_IS_DIRECTORY;
6417  #endif
6418  #ifdef EINVAL
6419  case EINVAL: return MA_INVALID_ARGS;
6420  #endif
6421  #ifdef ENFILE
6422  case ENFILE: return MA_TOO_MANY_OPEN_FILES;
6423  #endif
6424  #ifdef EMFILE
6425  case EMFILE: return MA_TOO_MANY_OPEN_FILES;
6426  #endif
6427  #ifdef ENOTTY
6428  case ENOTTY: return MA_INVALID_OPERATION;
6429  #endif
6430  #ifdef ETXTBSY
6431  case ETXTBSY: return MA_BUSY;
6432  #endif
6433  #ifdef EFBIG
6434  case EFBIG: return MA_TOO_BIG;
6435  #endif
6436  #ifdef ENOSPC
6437  case ENOSPC: return MA_NO_SPACE;
6438  #endif
6439  #ifdef ESPIPE
6440  case ESPIPE: return MA_BAD_SEEK;
6441  #endif
6442  #ifdef EROFS
6443  case EROFS: return MA_ACCESS_DENIED;
6444  #endif
6445  #ifdef EMLINK
6446  case EMLINK: return MA_TOO_MANY_LINKS;
6447  #endif
6448  #ifdef EPIPE
6449  case EPIPE: return MA_BAD_PIPE;
6450  #endif
6451  #ifdef EDOM
6452  case EDOM: return MA_OUT_OF_RANGE;
6453  #endif
6454  #ifdef ERANGE
6455  case ERANGE: return MA_OUT_OF_RANGE;
6456  #endif
6457  #ifdef EDEADLK
6458  case EDEADLK: return MA_DEADLOCK;
6459  #endif
6460  #ifdef ENAMETOOLONG
6461  case ENAMETOOLONG: return MA_PATH_TOO_LONG;
6462  #endif
6463  #ifdef ENOLCK
6464  case ENOLCK: return MA_ERROR;
6465  #endif
6466  #ifdef ENOSYS
6467  case ENOSYS: return MA_NOT_IMPLEMENTED;
6468  #endif
6469  #ifdef ENOTEMPTY
6470  case ENOTEMPTY: return MA_DIRECTORY_NOT_EMPTY;
6471  #endif
6472  #ifdef ELOOP
6473  case ELOOP: return MA_TOO_MANY_LINKS;
6474  #endif
6475  #ifdef ENOMSG
6476  case ENOMSG: return MA_NO_MESSAGE;
6477  #endif
6478  #ifdef EIDRM
6479  case EIDRM: return MA_ERROR;
6480  #endif
6481  #ifdef ECHRNG
6482  case ECHRNG: return MA_ERROR;
6483  #endif
6484  #ifdef EL2NSYNC
6485  case EL2NSYNC: return MA_ERROR;
6486  #endif
6487  #ifdef EL3HLT
6488  case EL3HLT: return MA_ERROR;
6489  #endif
6490  #ifdef EL3RST
6491  case EL3RST: return MA_ERROR;
6492  #endif
6493  #ifdef ELNRNG
6494  case ELNRNG: return MA_OUT_OF_RANGE;
6495  #endif
6496  #ifdef EUNATCH
6497  case EUNATCH: return MA_ERROR;
6498  #endif
6499  #ifdef ENOCSI
6500  case ENOCSI: return MA_ERROR;
6501  #endif
6502  #ifdef EL2HLT
6503  case EL2HLT: return MA_ERROR;
6504  #endif
6505  #ifdef EBADE
6506  case EBADE: return MA_ERROR;
6507  #endif
6508  #ifdef EBADR
6509  case EBADR: return MA_ERROR;
6510  #endif
6511  #ifdef EXFULL
6512  case EXFULL: return MA_ERROR;
6513  #endif
6514  #ifdef ENOANO
6515  case ENOANO: return MA_ERROR;
6516  #endif
6517  #ifdef EBADRQC
6518  case EBADRQC: return MA_ERROR;
6519  #endif
6520  #ifdef EBADSLT
6521  case EBADSLT: return MA_ERROR;
6522  #endif
6523  #ifdef EBFONT
6524  case EBFONT: return MA_INVALID_FILE;
6525  #endif
6526  #ifdef ENOSTR
6527  case ENOSTR: return MA_ERROR;
6528  #endif
6529  #ifdef ENODATA
6530  case ENODATA: return MA_NO_DATA_AVAILABLE;
6531  #endif
6532  #ifdef ETIME
6533  case ETIME: return MA_TIMEOUT;
6534  #endif
6535  #ifdef ENOSR
6536  case ENOSR: return MA_NO_DATA_AVAILABLE;
6537  #endif
6538  #ifdef ENONET
6539  case ENONET: return MA_NO_NETWORK;
6540  #endif
6541  #ifdef ENOPKG
6542  case ENOPKG: return MA_ERROR;
6543  #endif
6544  #ifdef EREMOTE
6545  case EREMOTE: return MA_ERROR;
6546  #endif
6547  #ifdef ENOLINK
6548  case ENOLINK: return MA_ERROR;
6549  #endif
6550  #ifdef EADV
6551  case EADV: return MA_ERROR;
6552  #endif
6553  #ifdef ESRMNT
6554  case ESRMNT: return MA_ERROR;
6555  #endif
6556  #ifdef ECOMM
6557  case ECOMM: return MA_ERROR;
6558  #endif
6559  #ifdef EPROTO
6560  case EPROTO: return MA_ERROR;
6561  #endif
6562  #ifdef EMULTIHOP
6563  case EMULTIHOP: return MA_ERROR;
6564  #endif
6565  #ifdef EDOTDOT
6566  case EDOTDOT: return MA_ERROR;
6567  #endif
6568  #ifdef EBADMSG
6569  case EBADMSG: return MA_BAD_MESSAGE;
6570  #endif
6571  #ifdef EOVERFLOW
6572  case EOVERFLOW: return MA_TOO_BIG;
6573  #endif
6574  #ifdef ENOTUNIQ
6575  case ENOTUNIQ: return MA_NOT_UNIQUE;
6576  #endif
6577  #ifdef EBADFD
6578  case EBADFD: return MA_ERROR;
6579  #endif
6580  #ifdef EREMCHG
6581  case EREMCHG: return MA_ERROR;
6582  #endif
6583  #ifdef ELIBACC
6584  case ELIBACC: return MA_ACCESS_DENIED;
6585  #endif
6586  #ifdef ELIBBAD
6587  case ELIBBAD: return MA_INVALID_FILE;
6588  #endif
6589  #ifdef ELIBSCN
6590  case ELIBSCN: return MA_INVALID_FILE;
6591  #endif
6592  #ifdef ELIBMAX
6593  case ELIBMAX: return MA_ERROR;
6594  #endif
6595  #ifdef ELIBEXEC
6596  case ELIBEXEC: return MA_ERROR;
6597  #endif
6598  #ifdef EILSEQ
6599  case EILSEQ: return MA_INVALID_DATA;
6600  #endif
6601  #ifdef ERESTART
6602  case ERESTART: return MA_ERROR;
6603  #endif
6604  #ifdef ESTRPIPE
6605  case ESTRPIPE: return MA_ERROR;
6606  #endif
6607  #ifdef EUSERS
6608  case EUSERS: return MA_ERROR;
6609  #endif
6610  #ifdef ENOTSOCK
6611  case ENOTSOCK: return MA_NOT_SOCKET;
6612  #endif
6613  #ifdef EDESTADDRREQ
6614  case EDESTADDRREQ: return MA_NO_ADDRESS;
6615  #endif
6616  #ifdef EMSGSIZE
6617  case EMSGSIZE: return MA_TOO_BIG;
6618  #endif
6619  #ifdef EPROTOTYPE
6620  case EPROTOTYPE: return MA_BAD_PROTOCOL;
6621  #endif
6622  #ifdef ENOPROTOOPT
6623  case ENOPROTOOPT: return MA_PROTOCOL_UNAVAILABLE;
6624  #endif
6625  #ifdef EPROTONOSUPPORT
6626  case EPROTONOSUPPORT: return MA_PROTOCOL_NOT_SUPPORTED;
6627  #endif
6628  #ifdef ESOCKTNOSUPPORT
6629  case ESOCKTNOSUPPORT: return MA_SOCKET_NOT_SUPPORTED;
6630  #endif
6631  #ifdef EOPNOTSUPP
6632  case EOPNOTSUPP: return MA_INVALID_OPERATION;
6633  #endif
6634  #ifdef EPFNOSUPPORT
6635  case EPFNOSUPPORT: return MA_PROTOCOL_FAMILY_NOT_SUPPORTED;
6636  #endif
6637  #ifdef EAFNOSUPPORT
6638  case EAFNOSUPPORT: return MA_ADDRESS_FAMILY_NOT_SUPPORTED;
6639  #endif
6640  #ifdef EADDRINUSE
6641  case EADDRINUSE: return MA_ALREADY_IN_USE;
6642  #endif
6643  #ifdef EADDRNOTAVAIL
6644  case EADDRNOTAVAIL: return MA_ERROR;
6645  #endif
6646  #ifdef ENETDOWN
6647  case ENETDOWN: return MA_NO_NETWORK;
6648  #endif
6649  #ifdef ENETUNREACH
6650  case ENETUNREACH: return MA_NO_NETWORK;
6651  #endif
6652  #ifdef ENETRESET
6653  case ENETRESET: return MA_NO_NETWORK;
6654  #endif
6655  #ifdef ECONNABORTED
6656  case ECONNABORTED: return MA_NO_NETWORK;
6657  #endif
6658  #ifdef ECONNRESET
6659  case ECONNRESET: return MA_CONNECTION_RESET;
6660  #endif
6661  #ifdef ENOBUFS
6662  case ENOBUFS: return MA_NO_SPACE;
6663  #endif
6664  #ifdef EISCONN
6665  case EISCONN: return MA_ALREADY_CONNECTED;
6666  #endif
6667  #ifdef ENOTCONN
6668  case ENOTCONN: return MA_NOT_CONNECTED;
6669  #endif
6670  #ifdef ESHUTDOWN
6671  case ESHUTDOWN: return MA_ERROR;
6672  #endif
6673  #ifdef ETOOMANYREFS
6674  case ETOOMANYREFS: return MA_ERROR;
6675  #endif
6676  #ifdef ETIMEDOUT
6677  case ETIMEDOUT: return MA_TIMEOUT;
6678  #endif
6679  #ifdef ECONNREFUSED
6680  case ECONNREFUSED: return MA_CONNECTION_REFUSED;
6681  #endif
6682  #ifdef EHOSTDOWN
6683  case EHOSTDOWN: return MA_NO_HOST;
6684  #endif
6685  #ifdef EHOSTUNREACH
6686  case EHOSTUNREACH: return MA_NO_HOST;
6687  #endif
6688  #ifdef EALREADY
6689  case EALREADY: return MA_IN_PROGRESS;
6690  #endif
6691  #ifdef EINPROGRESS
6692  case EINPROGRESS: return MA_IN_PROGRESS;
6693  #endif
6694  #ifdef ESTALE
6695  case ESTALE: return MA_INVALID_FILE;
6696  #endif
6697  #ifdef EUCLEAN
6698  case EUCLEAN: return MA_ERROR;
6699  #endif
6700  #ifdef ENOTNAM
6701  case ENOTNAM: return MA_ERROR;
6702  #endif
6703  #ifdef ENAVAIL
6704  case ENAVAIL: return MA_ERROR;
6705  #endif
6706  #ifdef EISNAM
6707  case EISNAM: return MA_ERROR;
6708  #endif
6709  #ifdef EREMOTEIO
6710  case EREMOTEIO: return MA_IO_ERROR;
6711  #endif
6712  #ifdef EDQUOT
6713  case EDQUOT: return MA_NO_SPACE;
6714  #endif
6715  #ifdef ENOMEDIUM
6716  case ENOMEDIUM: return MA_DOES_NOT_EXIST;
6717  #endif
6718  #ifdef EMEDIUMTYPE
6719  case EMEDIUMTYPE: return MA_ERROR;
6720  #endif
6721  #ifdef ECANCELED
6722  case ECANCELED: return MA_CANCELLED;
6723  #endif
6724  #ifdef ENOKEY
6725  case ENOKEY: return MA_ERROR;
6726  #endif
6727  #ifdef EKEYEXPIRED
6728  case EKEYEXPIRED: return MA_ERROR;
6729  #endif
6730  #ifdef EKEYREVOKED
6731  case EKEYREVOKED: return MA_ERROR;
6732  #endif
6733  #ifdef EKEYREJECTED
6734  case EKEYREJECTED: return MA_ERROR;
6735  #endif
6736  #ifdef EOWNERDEAD
6737  case EOWNERDEAD: return MA_ERROR;
6738  #endif
6739  #ifdef ENOTRECOVERABLE
6740  case ENOTRECOVERABLE: return MA_ERROR;
6741  #endif
6742  #ifdef ERFKILL
6743  case ERFKILL: return MA_ERROR;
6744  #endif
6745  #ifdef EHWPOISON
6746  case EHWPOISON: return MA_ERROR;
6747  #endif
6748  default: return MA_ERROR;
6749  }
6750 }
6751 
6752 ma_result ma_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
6753 {
6754 #if _MSC_VER
6755  errno_t err;
6756 #endif
6757 
6758  if (ppFile != NULL) {
6759  *ppFile = NULL; /* Safety. */
6760  }
6761 
6762  if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
6763  return MA_INVALID_ARGS;
6764  }
6765 
6766 #if _MSC_VER
6767  err = fopen_s(ppFile, pFilePath, pOpenMode);
6768  if (err != 0) {
6769  return ma_result_from_errno(err);
6770  }
6771 #else
6772 #if defined(_WIN32) || defined(__APPLE__)
6773  *ppFile = fopen(pFilePath, pOpenMode);
6774 #else
6775  #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
6776  *ppFile = fopen64(pFilePath, pOpenMode);
6777  #else
6778  *ppFile = fopen(pFilePath, pOpenMode);
6779  #endif
6780 #endif
6781  if (*ppFile == NULL) {
6783  if (result == MA_SUCCESS) {
6784  return MA_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */
6785  }
6786  }
6787 #endif
6788 
6789  return MA_SUCCESS;
6790 }
6791 
6792 
6793 
6794 /*
6795 _wfopen() isn't always available in all compilation environments.
6796 
6797  * Windows only.
6798  * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
6799  * MinGW-64 (both 32- and 64-bit) seems to support it.
6800  * MinGW wraps it in !defined(__STRICT_ANSI__).
6801 
6802 This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
6803 fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
6804 */
6805 #if defined(_WIN32)
6806  #if defined(_MSC_VER) || defined(__MINGW64__) || !defined(__STRICT_ANSI__)
6807  #define MA_HAS_WFOPEN
6808  #endif
6809 #endif
6810 
6811 ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, ma_allocation_callbacks* pAllocationCallbacks)
6812 {
6813 #if _MSC_VER
6814  errno_t err;
6815 #endif
6816 
6817  if (ppFile != NULL) {
6818  *ppFile = NULL; /* Safety. */
6819  }
6820 
6821  if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
6822  return MA_INVALID_ARGS;
6823  }
6824 
6825 #if defined(MA_HAS_WFOPEN)
6826  (void)pAllocationCallbacks;
6827 
6828  /* Use _wfopen() on Windows. */
6829  #if defined(_MSC_VER) && _MSC_VER >= 1400
6830  err = _wfopen_s(ppFile, pFilePath, pOpenMode);
6831  if (err != 0) {
6832  return ma_result_from_errno(err);
6833  }
6834  #else
6835  *ppFile = _wfopen(pFilePath, pOpenMode);
6836  if (*ppFile == NULL) {
6837  return ma_result_from_errno(errno);
6838  }
6839  #endif
6840 #else
6841  /*
6842  Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
6843  think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
6844  maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
6845  */
6846  {
6847  mbstate_t mbs;
6848  size_t lenMB;
6849  const wchar_t* pFilePathTemp = pFilePath;
6850  char* pFilePathMB = NULL;
6851  char pOpenModeMB[32] = {0};
6852 
6853  /* Get the length first. */
6854  MA_ZERO_OBJECT(&mbs);
6855  lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
6856  if (lenMB == (size_t)-1) {
6857  return ma_result_from_errno(errno);
6858  }
6859 
6860  pFilePathMB = (char*)ma_malloc(lenMB + 1, pAllocationCallbacks);
6861  if (pFilePathMB == NULL) {
6862  return MA_OUT_OF_MEMORY;
6863  }
6864 
6865  pFilePathTemp = pFilePath;
6866  MA_ZERO_OBJECT(&mbs);
6867  wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
6868 
6869  /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
6870  {
6871  size_t i = 0;
6872  for (;;) {
6873  if (pOpenMode[i] == 0) {
6874  pOpenModeMB[i] = '\0';
6875  break;
6876  }
6877 
6878  pOpenModeMB[i] = (char)pOpenMode[i];
6879  i += 1;
6880  }
6881  }
6882 
6883  *ppFile = fopen(pFilePathMB, pOpenModeMB);
6884 
6885  ma_free(pFilePathMB, pAllocationCallbacks);
6886  }
6887 
6888  if (*ppFile == NULL) {
6889  return MA_ERROR;
6890  }
6891 #endif
6892 
6893  return MA_SUCCESS;
6894 }
6895 
6896 
6897 
6898 static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 sizeInBytes)
6899 {
6900 #if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX
6901  MA_COPY_MEMORY(dst, src, (size_t)sizeInBytes);
6902 #else
6903  while (sizeInBytes > 0) {
6904  ma_uint64 bytesToCopyNow = sizeInBytes;
6905  if (bytesToCopyNow > MA_SIZE_MAX) {
6906  bytesToCopyNow = MA_SIZE_MAX;
6907  }
6908 
6909  MA_COPY_MEMORY(dst, src, (size_t)bytesToCopyNow); /* Safe cast to size_t. */
6910 
6911  sizeInBytes -= bytesToCopyNow;
6912  dst = ( void*)(( ma_uint8*)dst + bytesToCopyNow);
6913  src = (const void*)((const ma_uint8*)src + bytesToCopyNow);
6914  }
6915 #endif
6916 }
6917 
6918 static MA_INLINE void ma_zero_memory_64(void* dst, ma_uint64 sizeInBytes)
6919 {
6920 #if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX
6921  MA_ZERO_MEMORY(dst, (size_t)sizeInBytes);
6922 #else
6923  while (sizeInBytes > 0) {
6924  ma_uint64 bytesToZeroNow = sizeInBytes;
6925  if (bytesToZeroNow > MA_SIZE_MAX) {
6926  bytesToZeroNow = MA_SIZE_MAX;
6927  }
6928 
6929  MA_ZERO_MEMORY(dst, (size_t)bytesToZeroNow); /* Safe cast to size_t. */
6930 
6931  sizeInBytes -= bytesToZeroNow;
6932  dst = (void*)((ma_uint8*)dst + bytesToZeroNow);
6933  }
6934 #endif
6935 }
6936 
6937 
6938 /* Thanks to good old Bit Twiddling Hacks for this one: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */
6939 static MA_INLINE unsigned int ma_next_power_of_2(unsigned int x)
6940 {
6941  x--;
6942  x |= x >> 1;
6943  x |= x >> 2;
6944  x |= x >> 4;
6945  x |= x >> 8;
6946  x |= x >> 16;
6947  x++;
6948 
6949  return x;
6950 }
6951 
6952 static MA_INLINE unsigned int ma_prev_power_of_2(unsigned int x)
6953 {
6954  return ma_next_power_of_2(x) >> 1;
6955 }
6956 
6957 static MA_INLINE unsigned int ma_round_to_power_of_2(unsigned int x)
6958 {
6959  unsigned int prev = ma_prev_power_of_2(x);
6960  unsigned int next = ma_next_power_of_2(x);
6961  if ((next - x) > (x - prev)) {
6962  return prev;
6963  } else {
6964  return next;
6965  }
6966 }
6967 
6968 static MA_INLINE unsigned int ma_count_set_bits(unsigned int x)
6969 {
6970  unsigned int count = 0;
6971  while (x != 0) {
6972  if (x & 1) {
6973  count += 1;
6974  }
6975 
6976  x = x >> 1;
6977  }
6978 
6979  return count;
6980 }
6981 
6982 
6983 
6984 /* Clamps an f32 sample to -1..1 */
6985 static MA_INLINE float ma_clip_f32(float x)
6986 {
6987  if (x < -1) return -1;
6988  if (x > +1) return +1;
6989  return x;
6990 }
6991 
6992 static MA_INLINE float ma_mix_f32(float x, float y, float a)
6993 {
6994  return x*(1-a) + y*a;
6995 }
6996 static MA_INLINE float ma_mix_f32_fast(float x, float y, float a)
6997 {
6998  float r0 = (y - x);
6999  float r1 = r0*a;
7000  return x + r1;
7001  /*return x + (y - x)*a;*/
7002 }
7003 
7004 
7005 #if defined(MA_SUPPORT_SSE2)
7006 static MA_INLINE __m128 ma_mix_f32_fast__sse2(__m128 x, __m128 y, __m128 a)
7007 {
7008  return _mm_add_ps(x, _mm_mul_ps(_mm_sub_ps(y, x), a));
7009 }
7010 #endif
7011 #if defined(MA_SUPPORT_AVX2)
7012 static MA_INLINE __m256 ma_mix_f32_fast__avx2(__m256 x, __m256 y, __m256 a)
7013 {
7014  return _mm256_add_ps(x, _mm256_mul_ps(_mm256_sub_ps(y, x), a));
7015 }
7016 #endif
7017 #if defined(MA_SUPPORT_AVX512)
7018 static MA_INLINE __m512 ma_mix_f32_fast__avx512(__m512 x, __m512 y, __m512 a)
7019 {
7020  return _mm512_add_ps(x, _mm512_mul_ps(_mm512_sub_ps(y, x), a));
7021 }
7022 #endif
7023 #if defined(MA_SUPPORT_NEON)
7024 static MA_INLINE float32x4_t ma_mix_f32_fast__neon(float32x4_t x, float32x4_t y, float32x4_t a)
7025 {
7026  return vaddq_f32(x, vmulq_f32(vsubq_f32(y, x), a));
7027 }
7028 #endif
7029 
7030 
7031 static MA_INLINE double ma_mix_f64(double x, double y, double a)
7032 {
7033  return x*(1-a) + y*a;
7034 }
7035 static MA_INLINE double ma_mix_f64_fast(double x, double y, double a)
7036 {
7037  return x + (y - x)*a;
7038 }
7039 
7040 static MA_INLINE float ma_scale_to_range_f32(float x, float lo, float hi)
7041 {
7042  return lo + x*(hi-lo);
7043 }
7044 
7045 
7046 /*
7047 Greatest common factor using Euclid's algorithm iteratively.
7048 */
7050 {
7051  for (;;) {
7052  if (b == 0) {
7053  break;
7054  } else {
7055  ma_uint32 t = a;
7056  a = b;
7057  b = t % a;
7058  }
7059  }
7060 
7061  return a;
7062 }
7063 
7064 
7065 /*
7066 Random Number Generation
7067 
7068 miniaudio uses the LCG random number generation algorithm. This is good enough for audio.
7069 
7070 Note that miniaudio's global LCG implementation uses global state which is _not_ thread-local. When this is called across
7071 multiple threads, results will be unpredictable. However, it won't crash and results will still be random enough for
7072 miniaudio's purposes.
7073 */
7074 #ifndef MA_DEFAULT_LCG_SEED
7075 #define MA_DEFAULT_LCG_SEED 4321
7076 #endif
7077 
7078 #define MA_LCG_M 2147483647
7079 #define MA_LCG_A 48271
7080 #define MA_LCG_C 0
7081 
7082 static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_seed() to use an explicit seed. */
7083 
7084 static MA_INLINE void ma_lcg_seed(ma_lcg* pLCG, ma_int32 seed)
7085 {
7086  MA_ASSERT(pLCG != NULL);
7087  pLCG->state = seed;
7088 }
7089 
7091 {
7092  pLCG->state = (MA_LCG_A * pLCG->state + MA_LCG_C) % MA_LCG_M;
7093  return pLCG->state;
7094 }
7095 
7097 {
7098  return (ma_uint32)ma_lcg_rand_s32(pLCG);
7099 }
7100 
7102 {
7103  return (ma_int16)(ma_lcg_rand_s32(pLCG) & 0xFFFF);
7104 }
7105 
7106 static MA_INLINE double ma_lcg_rand_f64(ma_lcg* pLCG)
7107 {
7108  return ma_lcg_rand_s32(pLCG) / (double)0x7FFFFFFF;
7109 }
7110 
7111 static MA_INLINE float ma_lcg_rand_f32(ma_lcg* pLCG)
7112 {
7113  return (float)ma_lcg_rand_f64(pLCG);
7114 }
7115 
7116 static MA_INLINE float ma_lcg_rand_range_f32(ma_lcg* pLCG, float lo, float hi)
7117 {
7118  return ma_scale_to_range_f32(ma_lcg_rand_f32(pLCG), lo, hi);
7119 }
7120 
7122 {
7123  if (lo == hi) {
7124  return lo;
7125  }
7126 
7127  return lo + ma_lcg_rand_u32(pLCG) / (0xFFFFFFFF / (hi - lo + 1) + 1);
7128 }
7129 
7130 
7131 
7132 static MA_INLINE void ma_seed(ma_int32 seed)
7133 {
7134  ma_lcg_seed(&g_maLCG, seed);
7135 }
7136 
7138 {
7139  return ma_lcg_rand_s32(&g_maLCG);
7140 }
7141 
7143 {
7144  return ma_lcg_rand_u32(&g_maLCG);
7145 }
7146 
7147 static MA_INLINE double ma_rand_f64()
7148 {
7149  return ma_lcg_rand_f64(&g_maLCG);
7150 }
7151 
7152 static MA_INLINE float ma_rand_f32()
7153 {
7154  return ma_lcg_rand_f32(&g_maLCG);
7155 }
7156 
7157 static MA_INLINE float ma_rand_range_f32(float lo, float hi)
7158 {
7159  return ma_lcg_rand_range_f32(&g_maLCG, lo, hi);
7160 }
7161 
7163 {
7164  return ma_lcg_rand_range_s32(&g_maLCG, lo, hi);
7165 }
7166 
7167 
7168 static MA_INLINE float ma_dither_f32_rectangle(float ditherMin, float ditherMax)
7169 {
7170  return ma_rand_range_f32(ditherMin, ditherMax);
7171 }
7172 
7173 static MA_INLINE float ma_dither_f32_triangle(float ditherMin, float ditherMax)
7174 {
7175  float a = ma_rand_range_f32(ditherMin, 0);
7176  float b = ma_rand_range_f32(0, ditherMax);
7177  return a + b;
7178 }
7179 
7180 static MA_INLINE float ma_dither_f32(ma_dither_mode ditherMode, float ditherMin, float ditherMax)
7181 {
7182  if (ditherMode == ma_dither_mode_rectangle) {
7183  return ma_dither_f32_rectangle(ditherMin, ditherMax);
7184  }
7185  if (ditherMode == ma_dither_mode_triangle) {
7186  return ma_dither_f32_triangle(ditherMin, ditherMax);
7187  }
7188 
7189  return 0;
7190 }
7191 
7192 static MA_INLINE ma_int32 ma_dither_s32(ma_dither_mode ditherMode, ma_int32 ditherMin, ma_int32 ditherMax)
7193 {
7194  if (ditherMode == ma_dither_mode_rectangle) {
7195  ma_int32 a = ma_rand_range_s32(ditherMin, ditherMax);
7196  return a;
7197  }
7198  if (ditherMode == ma_dither_mode_triangle) {
7199  ma_int32 a = ma_rand_range_s32(ditherMin, 0);
7200  ma_int32 b = ma_rand_range_s32(0, ditherMax);
7201  return a + b;
7202  }
7203 
7204  return 0;
7205 }
7206 
7207 
7208 /******************************************************************************
7209 
7210 Atomics
7211 
7212 ******************************************************************************/
7213 #if defined(__clang__)
7214  #if defined(__has_builtin)
7215  #if __has_builtin(__sync_swap)
7216  #define MA_HAS_SYNC_SWAP
7217  #endif
7218  #endif
7219 #elif defined(__GNUC__)
7220  #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC__ >= 7)
7221  #define MA_HAS_GNUC_ATOMICS
7222  #endif
7223 #endif
7224 
7225 #if defined(_WIN32) && !defined(__GNUC__) && !defined(__clang__)
7226 #define ma_memory_barrier() MemoryBarrier()
7227 #define ma_atomic_exchange_32(a, b) InterlockedExchange((LONG*)a, (LONG)b)
7228 #define ma_atomic_exchange_64(a, b) InterlockedExchange64((LONGLONG*)a, (LONGLONG)b)
7229 #define ma_atomic_increment_32(a) InterlockedIncrement((LONG*)a)
7230 #define ma_atomic_decrement_32(a) InterlockedDecrement((LONG*)a)
7231 #else
7232 #define ma_memory_barrier() __sync_synchronize()
7233 #if defined(MA_HAS_SYNC_SWAP)
7234  #define ma_atomic_exchange_32(a, b) __sync_swap(a, b)
7235  #define ma_atomic_exchange_64(a, b) __sync_swap(a, b)
7236 #elif defined(MA_HAS_GNUC_ATOMICS)
7237  #define ma_atomic_exchange_32(a, b) (void)__atomic_exchange_n(a, b, __ATOMIC_ACQ_REL)
7238  #define ma_atomic_exchange_64(a, b) (void)__atomic_exchange_n(a, b, __ATOMIC_ACQ_REL)
7239 #else
7240  #define ma_atomic_exchange_32(a, b) __sync_synchronize(); (void)__sync_lock_test_and_set(a, b)
7241  #define ma_atomic_exchange_64(a, b) __sync_synchronize(); (void)__sync_lock_test_and_set(a, b)
7242 #endif
7243 #define ma_atomic_increment_32(a) __sync_add_and_fetch(a, 1)
7244 #define ma_atomic_decrement_32(a) __sync_sub_and_fetch(a, 1)
7245 #endif
7246 
7247 #ifdef MA_64BIT
7248 #define ma_atomic_exchange_ptr ma_atomic_exchange_64
7249 #endif
7250 #ifdef MA_32BIT
7251 #define ma_atomic_exchange_ptr ma_atomic_exchange_32
7252 #endif
7253 
7254 
7255 static void* ma__malloc_default(size_t sz, void* pUserData)
7256 {
7257  (void)pUserData;
7258  return MA_MALLOC(sz);
7259 }
7260 
7261 static void* ma__realloc_default(void* p, size_t sz, void* pUserData)
7262 {
7263  (void)pUserData;
7264  return MA_REALLOC(p, sz);
7265 }
7266 
7267 static void ma__free_default(void* p, void* pUserData)
7268 {
7269  (void)pUserData;
7270  MA_FREE(p);
7271 }
7272 
7273 
7274 static void* ma__malloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
7275 {
7276  if (pAllocationCallbacks == NULL) {
7277  return NULL;
7278  }
7279 
7280  if (pAllocationCallbacks->onMalloc != NULL) {
7281  return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
7282  }
7283 
7284  /* Try using realloc(). */
7285  if (pAllocationCallbacks->onRealloc != NULL) {
7286  return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
7287  }
7288 
7289  return NULL;
7290 }
7291 
7292 static void* ma__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const ma_allocation_callbacks* pAllocationCallbacks)
7293 {
7294  if (pAllocationCallbacks == NULL) {
7295  return NULL;
7296  }
7297 
7298  if (pAllocationCallbacks->onRealloc != NULL) {
7299  return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
7300  }
7301 
7302  /* Try emulating realloc() in terms of malloc()/free(). */
7303  if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
7304  void* p2;
7305 
7306  p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
7307  if (p2 == NULL) {
7308  return NULL;
7309  }
7310 
7311  if (p != NULL) {
7312  MA_COPY_MEMORY(p2, p, szOld);
7313  pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
7314  }
7315 
7316  return p2;
7317  }
7318 
7319  return NULL;
7320 }
7321 
7322 static MA_INLINE void* ma__calloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
7323 {
7324  void* p = ma__malloc_from_callbacks(sz, pAllocationCallbacks);
7325  if (p != NULL) {
7326  MA_ZERO_MEMORY(p, sz);
7327  }
7328 
7329  return p;
7330 }
7331 
7332 static void ma__free_from_callbacks(void* p, const ma_allocation_callbacks* pAllocationCallbacks)
7333 {
7334  if (p == NULL || pAllocationCallbacks == NULL) {
7335  return;
7336  }
7337 
7338  if (pAllocationCallbacks->onFree != NULL) {
7339  pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
7340  }
7341 }
7342 
7344 {
7345  ma_allocation_callbacks callbacks;
7346  callbacks.pUserData = NULL;
7347  callbacks.onMalloc = ma__malloc_default;
7348  callbacks.onRealloc = ma__realloc_default;
7349  callbacks.onFree = ma__free_default;
7350 
7351  return callbacks;
7352 }
7353 
7355 {
7356  if (pDst == NULL) {
7357  return MA_INVALID_ARGS;
7358  }
7359 
7360  if (pSrc == NULL) {
7362  } else {
7363  if (pSrc->pUserData == NULL && pSrc->onFree == NULL && pSrc->onMalloc == NULL && pSrc->onRealloc == NULL) {
7365  } else {
7366  if (pSrc->onFree == NULL || (pSrc->onMalloc == NULL && pSrc->onRealloc == NULL)) {
7367  return MA_INVALID_ARGS; /* Invalid allocation callbacks. */
7368  } else {
7369  *pDst = *pSrc;
7370  }
7371  }
7372  }
7373 
7374  return MA_SUCCESS;
7375 }
7376 
7377 
7378 ma_uint64 ma_calculate_frame_count_after_resampling(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 frameCountIn)
7379 {
7380  /* For robustness we're going to use a resampler object to calculate this since that already has a way of calculating this. */
7381  ma_result result;
7382  ma_uint64 frameCountOut;
7384  ma_resampler resampler;
7385 
7386  config = ma_resampler_config_init(ma_format_s16, 1, sampleRateIn, sampleRateOut, ma_resample_algorithm_linear);
7387  result = ma_resampler_init(&config, &resampler);
7388  if (result != MA_SUCCESS) {
7389  return 0;
7390  }
7391 
7392  frameCountOut = ma_resampler_get_expected_output_frame_count(&resampler, frameCountIn);
7393 
7394  ma_resampler_uninit(&resampler);
7395  return frameCountOut;
7396 }
7397 
7398 #ifndef MA_DATA_CONVERTER_STACK_BUFFER_SIZE
7399 #define MA_DATA_CONVERTER_STACK_BUFFER_SIZE 4096
7400 #endif
7401 
7402 /************************************************************************************************************************************************************
7403 *************************************************************************************************************************************************************
7404 
7405 DEVICE I/O
7406 ==========
7407 
7408 *************************************************************************************************************************************************************
7409 ************************************************************************************************************************************************************/
7410 #ifndef MA_NO_DEVICE_IO
7411 /*
7412 Unfortunately using runtime linking for pthreads causes problems. This has occurred for me when testing on FreeBSD. When
7413 using runtime linking, deadlocks can occur (for me it happens when loading data from fread()). It turns out that doing
7414 compile-time linking fixes this. I'm not sure why this happens, but the safest way I can think of to fix this is to simply
7415 disable runtime linking by default. To enable runtime linking, #define this before the implementation of this file. I am
7416 not officially supporting this, but I'm leaving it here in case it's useful for somebody, somewhere.
7417 */
7418 /*#define MA_USE_RUNTIME_LINKING_FOR_PTHREAD*/
7419 
7420 /* Disable run-time linking on certain backends. */
7421 #ifndef MA_NO_RUNTIME_LINKING
7422  #if defined(MA_ANDROID) || defined(MA_EMSCRIPTEN)
7423  #define MA_NO_RUNTIME_LINKING
7424  #endif
7425 #endif
7426 
7427 /*
7428 Check if we have the necessary development packages for each backend at the top so we can use this to determine whether or not
7429 certain unused functions and variables can be excluded from the build to avoid warnings.
7430 */
7431 #ifdef MA_ENABLE_WASAPI
7432  #define MA_HAS_WASAPI /* Every compiler should support WASAPI */
7433 #endif
7434 #ifdef MA_ENABLE_DSOUND
7435  #define MA_HAS_DSOUND /* Every compiler should support DirectSound. */
7436 #endif
7437 #ifdef MA_ENABLE_WINMM
7438  #define MA_HAS_WINMM /* Every compiler I'm aware of supports WinMM. */
7439 #endif
7440 #ifdef MA_ENABLE_ALSA
7441  #define MA_HAS_ALSA
7442  #ifdef MA_NO_RUNTIME_LINKING
7443  #ifdef __has_include
7444  #if !__has_include(<alsa/asoundlib.h>)
7445  #undef MA_HAS_ALSA
7446  #endif
7447  #endif
7448  #endif
7449 #endif
7450 #ifdef MA_ENABLE_PULSEAUDIO
7451  #define MA_HAS_PULSEAUDIO
7452  #ifdef MA_NO_RUNTIME_LINKING
7453  #ifdef __has_include
7454  #if !__has_include(<pulse/pulseaudio.h>)
7455  #undef MA_HAS_PULSEAUDIO
7456  #endif
7457  #endif
7458  #endif
7459 #endif
7460 #ifdef MA_ENABLE_JACK
7461  #define MA_HAS_JACK
7462  #ifdef MA_NO_RUNTIME_LINKING
7463  #ifdef __has_include
7464  #if !__has_include(<jack/jack.h>)
7465  #undef MA_HAS_JACK
7466  #endif
7467  #endif
7468  #endif
7469 #endif
7470 #ifdef MA_ENABLE_COREAUDIO
7471  #define MA_HAS_COREAUDIO
7472 #endif
7473 #ifdef MA_ENABLE_SNDIO
7474  #define MA_HAS_SNDIO
7475 #endif
7476 #ifdef MA_ENABLE_AUDIO4
7477  #define MA_HAS_AUDIO4
7478 #endif
7479 #ifdef MA_ENABLE_OSS
7480  #define MA_HAS_OSS
7481 #endif
7482 #ifdef MA_ENABLE_AAUDIO
7483  #define MA_HAS_AAUDIO
7484 #endif
7485 #ifdef MA_ENABLE_OPENSL
7486  #define MA_HAS_OPENSL
7487 #endif
7488 #ifdef MA_ENABLE_WEBAUDIO
7489  #define MA_HAS_WEBAUDIO
7490 #endif
7491 #ifdef MA_ENABLE_NULL
7492  #define MA_HAS_NULL /* Everything supports the null backend. */
7493 #endif
7494 
7495 const char* ma_get_backend_name(ma_backend backend)
7496 {
7497  switch (backend)
7498  {
7499  case ma_backend_wasapi: return "WASAPI";
7500  case ma_backend_dsound: return "DirectSound";
7501  case ma_backend_winmm: return "WinMM";
7502  case ma_backend_coreaudio: return "Core Audio";
7503  case ma_backend_sndio: return "sndio";
7504  case ma_backend_audio4: return "audio(4)";
7505  case ma_backend_oss: return "OSS";
7506  case ma_backend_pulseaudio: return "PulseAudio";
7507  case ma_backend_alsa: return "ALSA";
7508  case ma_backend_jack: return "JACK";
7509  case ma_backend_aaudio: return "AAudio";
7510  case ma_backend_opensl: return "OpenSL|ES";
7511  case ma_backend_webaudio: return "Web Audio";
7512  case ma_backend_null: return "Null";
7513  default: return "Unknown";
7514  }
7515 }
7516 
7518 {
7519  switch (backend)
7520  {
7521  case ma_backend_wasapi: return MA_TRUE;
7522  case ma_backend_dsound: return MA_FALSE;
7523  case ma_backend_winmm: return MA_FALSE;
7524  case ma_backend_coreaudio: return MA_FALSE;
7525  case ma_backend_sndio: return MA_FALSE;
7526  case ma_backend_audio4: return MA_FALSE;
7527  case ma_backend_oss: return MA_FALSE;
7528  case ma_backend_pulseaudio: return MA_FALSE;
7529  case ma_backend_alsa: return MA_FALSE;
7530  case ma_backend_jack: return MA_FALSE;
7531  case ma_backend_aaudio: return MA_FALSE;
7532  case ma_backend_opensl: return MA_FALSE;
7533  case ma_backend_webaudio: return MA_FALSE;
7534  case ma_backend_null: return MA_FALSE;
7535  default: return MA_FALSE;
7536  }
7537 }
7538 
7539 
7540 
7541 #ifdef MA_WIN32
7542  #define MA_THREADCALL WINAPI
7543  typedef unsigned long ma_thread_result;
7544 #else
7545  #define MA_THREADCALL
7546  typedef void* ma_thread_result;
7547 #endif
7548 typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData);
7549 
7550 #ifdef MA_WIN32
7551 static ma_result ma_result_from_GetLastError(DWORD error)
7552 {
7553  switch (error)
7554  {
7555  case ERROR_SUCCESS: return MA_SUCCESS;
7556  case ERROR_PATH_NOT_FOUND: return MA_DOES_NOT_EXIST;
7557  case ERROR_TOO_MANY_OPEN_FILES: return MA_TOO_MANY_OPEN_FILES;
7558  case ERROR_NOT_ENOUGH_MEMORY: return MA_OUT_OF_MEMORY;
7559  case ERROR_DISK_FULL: return MA_NO_SPACE;
7560  case ERROR_HANDLE_EOF: return MA_END_OF_FILE;
7561  case ERROR_NEGATIVE_SEEK: return MA_BAD_SEEK;
7562  case ERROR_INVALID_PARAMETER: return MA_INVALID_ARGS;
7563  case ERROR_ACCESS_DENIED: return MA_ACCESS_DENIED;
7564  case ERROR_SEM_TIMEOUT: return MA_TIMEOUT;
7565  case ERROR_FILE_NOT_FOUND: return MA_DOES_NOT_EXIST;
7566  default: break;
7567  }
7568 
7569  return MA_ERROR;
7570 }
7571 
7572 /* WASAPI error codes. */
7573 #define MA_AUDCLNT_E_NOT_INITIALIZED ((HRESULT)0x88890001)
7574 #define MA_AUDCLNT_E_ALREADY_INITIALIZED ((HRESULT)0x88890002)
7575 #define MA_AUDCLNT_E_WRONG_ENDPOINT_TYPE ((HRESULT)0x88890003)
7576 #define MA_AUDCLNT_E_DEVICE_INVALIDATED ((HRESULT)0x88890004)
7577 #define MA_AUDCLNT_E_NOT_STOPPED ((HRESULT)0x88890005)
7578 #define MA_AUDCLNT_E_BUFFER_TOO_LARGE ((HRESULT)0x88890006)
7579 #define MA_AUDCLNT_E_OUT_OF_ORDER ((HRESULT)0x88890007)
7580 #define MA_AUDCLNT_E_UNSUPPORTED_FORMAT ((HRESULT)0x88890008)
7581 #define MA_AUDCLNT_E_INVALID_SIZE ((HRESULT)0x88890009)
7582 #define MA_AUDCLNT_E_DEVICE_IN_USE ((HRESULT)0x8889000A)
7583 #define MA_AUDCLNT_E_BUFFER_OPERATION_PENDING ((HRESULT)0x8889000B)
7584 #define MA_AUDCLNT_E_THREAD_NOT_REGISTERED ((HRESULT)0x8889000C)
7585 #define MA_AUDCLNT_E_NO_SINGLE_PROCESS ((HRESULT)0x8889000D)
7586 #define MA_AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED ((HRESULT)0x8889000E)
7587 #define MA_AUDCLNT_E_ENDPOINT_CREATE_FAILED ((HRESULT)0x8889000F)
7588 #define MA_AUDCLNT_E_SERVICE_NOT_RUNNING ((HRESULT)0x88890010)
7589 #define MA_AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED ((HRESULT)0x88890011)
7590 #define MA_AUDCLNT_E_EXCLUSIVE_MODE_ONLY ((HRESULT)0x88890012)
7591 #define MA_AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL ((HRESULT)0x88890013)
7592 #define MA_AUDCLNT_E_EVENTHANDLE_NOT_SET ((HRESULT)0x88890014)
7593 #define MA_AUDCLNT_E_INCORRECT_BUFFER_SIZE ((HRESULT)0x88890015)
7594 #define MA_AUDCLNT_E_BUFFER_SIZE_ERROR ((HRESULT)0x88890016)
7595 #define MA_AUDCLNT_E_CPUUSAGE_EXCEEDED ((HRESULT)0x88890017)
7596 #define MA_AUDCLNT_E_BUFFER_ERROR ((HRESULT)0x88890018)
7597 #define MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED ((HRESULT)0x88890019)
7598 #define MA_AUDCLNT_E_INVALID_DEVICE_PERIOD ((HRESULT)0x88890020)
7599 #define MA_AUDCLNT_E_INVALID_STREAM_FLAG ((HRESULT)0x88890021)
7600 #define MA_AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE ((HRESULT)0x88890022)
7601 #define MA_AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES ((HRESULT)0x88890023)
7602 #define MA_AUDCLNT_E_OFFLOAD_MODE_ONLY ((HRESULT)0x88890024)
7603 #define MA_AUDCLNT_E_NONOFFLOAD_MODE_ONLY ((HRESULT)0x88890025)
7604 #define MA_AUDCLNT_E_RESOURCES_INVALIDATED ((HRESULT)0x88890026)
7605 #define MA_AUDCLNT_E_RAW_MODE_UNSUPPORTED ((HRESULT)0x88890027)
7606 #define MA_AUDCLNT_E_ENGINE_PERIODICITY_LOCKED ((HRESULT)0x88890028)
7607 #define MA_AUDCLNT_E_ENGINE_FORMAT_LOCKED ((HRESULT)0x88890029)
7608 #define MA_AUDCLNT_E_HEADTRACKING_ENABLED ((HRESULT)0x88890030)
7609 #define MA_AUDCLNT_E_HEADTRACKING_UNSUPPORTED ((HRESULT)0x88890040)
7610 #define MA_AUDCLNT_S_BUFFER_EMPTY ((HRESULT)0x08890001)
7611 #define MA_AUDCLNT_S_THREAD_ALREADY_REGISTERED ((HRESULT)0x08890002)
7612 #define MA_AUDCLNT_S_POSITION_STALLED ((HRESULT)0x08890003)
7613 
7614 #define MA_DS_OK ((HRESULT)0)
7615 #define MA_DS_NO_VIRTUALIZATION ((HRESULT)0x0878000A)
7616 #define MA_DSERR_ALLOCATED ((HRESULT)0x8878000A)
7617 #define MA_DSERR_CONTROLUNAVAIL ((HRESULT)0x8878001E)
7618 #define MA_DSERR_INVALIDPARAM ((HRESULT)0x80070057) /*E_INVALIDARG*/
7619 #define MA_DSERR_INVALIDCALL ((HRESULT)0x88780032)
7620 #define MA_DSERR_GENERIC ((HRESULT)0x80004005) /*E_FAIL*/
7621 #define MA_DSERR_PRIOLEVELNEEDED ((HRESULT)0x88780046)
7622 #define MA_DSERR_OUTOFMEMORY ((HRESULT)0x8007000E) /*E_OUTOFMEMORY*/
7623 #define MA_DSERR_BADFORMAT ((HRESULT)0x88780064)
7624 #define MA_DSERR_UNSUPPORTED ((HRESULT)0x80004001) /*E_NOTIMPL*/
7625 #define MA_DSERR_NODRIVER ((HRESULT)0x88780078)
7626 #define MA_DSERR_ALREADYINITIALIZED ((HRESULT)0x88780082)
7627 #define MA_DSERR_NOAGGREGATION ((HRESULT)0x80040110) /*CLASS_E_NOAGGREGATION*/
7628 #define MA_DSERR_BUFFERLOST ((HRESULT)0x88780096)
7629 #define MA_DSERR_OTHERAPPHASPRIO ((HRESULT)0x887800A0)
7630 #define MA_DSERR_UNINITIALIZED ((HRESULT)0x887800AA)
7631 #define MA_DSERR_NOINTERFACE ((HRESULT)0x80004002) /*E_NOINTERFACE*/
7632 #define MA_DSERR_ACCESSDENIED ((HRESULT)0x80070005) /*E_ACCESSDENIED*/
7633 #define MA_DSERR_BUFFERTOOSMALL ((HRESULT)0x887800B4)
7634 #define MA_DSERR_DS8_REQUIRED ((HRESULT)0x887800BE)
7635 #define MA_DSERR_SENDLOOP ((HRESULT)0x887800C8)
7636 #define MA_DSERR_BADSENDBUFFERGUID ((HRESULT)0x887800D2)
7637 #define MA_DSERR_OBJECTNOTFOUND ((HRESULT)0x88781161)
7638 #define MA_DSERR_FXUNAVAILABLE ((HRESULT)0x887800DC)
7639 
7640 static ma_result ma_result_from_HRESULT(HRESULT hr)
7641 {
7642  switch (hr)
7643  {
7644  case NOERROR: return MA_SUCCESS;
7645  /*case S_OK: return MA_SUCCESS;*/
7646 
7647  case E_POINTER: return MA_INVALID_ARGS;
7648  case E_UNEXPECTED: return MA_ERROR;
7649  case E_NOTIMPL: return MA_NOT_IMPLEMENTED;
7650  case E_OUTOFMEMORY: return MA_OUT_OF_MEMORY;
7651  case E_INVALIDARG: return MA_INVALID_ARGS;
7652  case E_NOINTERFACE: return MA_API_NOT_FOUND;
7653  case E_HANDLE: return MA_INVALID_ARGS;
7654  case E_ABORT: return MA_ERROR;
7655  case E_FAIL: return MA_ERROR;
7656  case E_ACCESSDENIED: return MA_ACCESS_DENIED;
7657 
7658  /* WASAPI */
7659  case MA_AUDCLNT_E_NOT_INITIALIZED: return MA_DEVICE_NOT_INITIALIZED;
7660  case MA_AUDCLNT_E_ALREADY_INITIALIZED: return MA_DEVICE_ALREADY_INITIALIZED;
7661  case MA_AUDCLNT_E_WRONG_ENDPOINT_TYPE: return MA_INVALID_ARGS;
7662  case MA_AUDCLNT_E_DEVICE_INVALIDATED: return MA_UNAVAILABLE;
7663  case MA_AUDCLNT_E_NOT_STOPPED: return MA_DEVICE_NOT_STOPPED;
7664  case MA_AUDCLNT_E_BUFFER_TOO_LARGE: return MA_TOO_BIG;
7665  case MA_AUDCLNT_E_OUT_OF_ORDER: return MA_INVALID_OPERATION;
7666  case MA_AUDCLNT_E_UNSUPPORTED_FORMAT: return MA_FORMAT_NOT_SUPPORTED;
7667  case MA_AUDCLNT_E_INVALID_SIZE: return MA_INVALID_ARGS;
7668  case MA_AUDCLNT_E_DEVICE_IN_USE: return MA_BUSY;
7669  case MA_AUDCLNT_E_BUFFER_OPERATION_PENDING: return MA_INVALID_OPERATION;
7670  case MA_AUDCLNT_E_THREAD_NOT_REGISTERED: return MA_DOES_NOT_EXIST;
7671  case MA_AUDCLNT_E_NO_SINGLE_PROCESS: return MA_INVALID_OPERATION;
7672  case MA_AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED: return MA_SHARE_MODE_NOT_SUPPORTED;
7673  case MA_AUDCLNT_E_ENDPOINT_CREATE_FAILED: return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
7674  case MA_AUDCLNT_E_SERVICE_NOT_RUNNING: return MA_NOT_CONNECTED;
7675  case MA_AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED: return MA_INVALID_ARGS;
7676  case MA_AUDCLNT_E_EXCLUSIVE_MODE_ONLY: return MA_SHARE_MODE_NOT_SUPPORTED;
7677  case MA_AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL: return MA_INVALID_ARGS;
7678  case MA_AUDCLNT_E_EVENTHANDLE_NOT_SET: return MA_INVALID_ARGS;
7679  case MA_AUDCLNT_E_INCORRECT_BUFFER_SIZE: return MA_INVALID_ARGS;
7680  case MA_AUDCLNT_E_BUFFER_SIZE_ERROR: return MA_INVALID_ARGS;
7681  case MA_AUDCLNT_E_CPUUSAGE_EXCEEDED: return MA_ERROR;
7682  case MA_AUDCLNT_E_BUFFER_ERROR: return MA_ERROR;
7683  case MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED: return MA_INVALID_ARGS;
7684  case MA_AUDCLNT_E_INVALID_DEVICE_PERIOD: return MA_INVALID_ARGS;
7685  case MA_AUDCLNT_E_INVALID_STREAM_FLAG: return MA_INVALID_ARGS;
7686  case MA_AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE: return MA_INVALID_OPERATION;
7687  case MA_AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES: return MA_OUT_OF_MEMORY;
7688  case MA_AUDCLNT_E_OFFLOAD_MODE_ONLY: return MA_INVALID_OPERATION;
7689  case MA_AUDCLNT_E_NONOFFLOAD_MODE_ONLY: return MA_INVALID_OPERATION;
7690  case MA_AUDCLNT_E_RESOURCES_INVALIDATED: return MA_INVALID_DATA;
7691  case MA_AUDCLNT_E_RAW_MODE_UNSUPPORTED: return MA_INVALID_OPERATION;
7692  case MA_AUDCLNT_E_ENGINE_PERIODICITY_LOCKED: return MA_INVALID_OPERATION;
7693  case MA_AUDCLNT_E_ENGINE_FORMAT_LOCKED: return MA_INVALID_OPERATION;
7694  case MA_AUDCLNT_E_HEADTRACKING_ENABLED: return MA_INVALID_OPERATION;
7695  case MA_AUDCLNT_E_HEADTRACKING_UNSUPPORTED: return MA_INVALID_OPERATION;
7696  case MA_AUDCLNT_S_BUFFER_EMPTY: return MA_NO_SPACE;
7697  case MA_AUDCLNT_S_THREAD_ALREADY_REGISTERED: return MA_ALREADY_EXISTS;
7698  case MA_AUDCLNT_S_POSITION_STALLED: return MA_ERROR;
7699 
7700  /* DirectSound */
7701  /*case MA_DS_OK: return MA_SUCCESS;*/ /* S_OK */
7702  case MA_DS_NO_VIRTUALIZATION: return MA_SUCCESS;
7703  case MA_DSERR_ALLOCATED: return MA_ALREADY_IN_USE;
7704  case MA_DSERR_CONTROLUNAVAIL: return MA_INVALID_OPERATION;
7705  /*case MA_DSERR_INVALIDPARAM: return MA_INVALID_ARGS;*/ /* E_INVALIDARG */
7706  case MA_DSERR_INVALIDCALL: return MA_INVALID_OPERATION;
7707  /*case MA_DSERR_GENERIC: return MA_ERROR;*/ /* E_FAIL */
7708  case MA_DSERR_PRIOLEVELNEEDED: return MA_INVALID_OPERATION;
7709  /*case MA_DSERR_OUTOFMEMORY: return MA_OUT_OF_MEMORY;*/ /* E_OUTOFMEMORY */
7710  case MA_DSERR_BADFORMAT: return MA_FORMAT_NOT_SUPPORTED;
7711  /*case MA_DSERR_UNSUPPORTED: return MA_NOT_IMPLEMENTED;*/ /* E_NOTIMPL */
7712  case MA_DSERR_NODRIVER: return MA_FAILED_TO_INIT_BACKEND;
7713  case MA_DSERR_ALREADYINITIALIZED: return MA_DEVICE_ALREADY_INITIALIZED;
7714  case MA_DSERR_NOAGGREGATION: return MA_ERROR;
7715  case MA_DSERR_BUFFERLOST: return MA_UNAVAILABLE;
7716  case MA_DSERR_OTHERAPPHASPRIO: return MA_ACCESS_DENIED;
7717  case MA_DSERR_UNINITIALIZED: return MA_DEVICE_NOT_INITIALIZED;
7718  /*case MA_DSERR_NOINTERFACE: return MA_API_NOT_FOUND;*/ /* E_NOINTERFACE */
7719  /*case MA_DSERR_ACCESSDENIED: return MA_ACCESS_DENIED;*/ /* E_ACCESSDENIED */
7720  case MA_DSERR_BUFFERTOOSMALL: return MA_NO_SPACE;
7721  case MA_DSERR_DS8_REQUIRED: return MA_INVALID_OPERATION;
7722  case MA_DSERR_SENDLOOP: return MA_DEADLOCK;
7723  case MA_DSERR_BADSENDBUFFERGUID: return MA_INVALID_ARGS;
7724  case MA_DSERR_OBJECTNOTFOUND: return MA_NO_DEVICE;
7725  case MA_DSERR_FXUNAVAILABLE: return MA_UNAVAILABLE;
7726 
7727  default: return MA_ERROR;
7728  }
7729 }
7730 
7731 typedef HRESULT (WINAPI * MA_PFN_CoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit);
7732 typedef void (WINAPI * MA_PFN_CoUninitialize)();
7733 typedef HRESULT (WINAPI * MA_PFN_CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv);
7734 typedef void (WINAPI * MA_PFN_CoTaskMemFree)(LPVOID pv);
7735 typedef HRESULT (WINAPI * MA_PFN_PropVariantClear)(PROPVARIANT *pvar);
7736 typedef int (WINAPI * MA_PFN_StringFromGUID2)(const GUID* const rguid, LPOLESTR lpsz, int cchMax);
7737 
7738 typedef HWND (WINAPI * MA_PFN_GetForegroundWindow)();
7739 typedef HWND (WINAPI * MA_PFN_GetDesktopWindow)();
7740 
7741 /* Microsoft documents these APIs as returning LSTATUS, but the Win32 API shipping with some compilers do not define it. It's just a LONG. */
7742 typedef LONG (WINAPI * MA_PFN_RegOpenKeyExA)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
7743 typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey);
7744 typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
7745 #endif
7746 
7747 
7748 #define MA_STATE_UNINITIALIZED 0
7749 #define MA_STATE_STOPPED 1 /* The device's default state after initialization. */
7750 #define MA_STATE_STARTED 2 /* The worker thread is in it's main loop waiting for the driver to request or deliver audio data. */
7751 #define MA_STATE_STARTING 3 /* Transitioning from a stopped state to started. */
7752 #define MA_STATE_STOPPING 4 /* Transitioning from a started state to stopped. */
7753 
7754 #define MA_DEFAULT_PLAYBACK_DEVICE_NAME "Default Playback Device"
7755 #define MA_DEFAULT_CAPTURE_DEVICE_NAME "Default Capture Device"
7756 
7757 
7758 const char* ma_log_level_to_string(ma_uint32 logLevel)
7759 {
7760  switch (logLevel)
7761  {
7762  case MA_LOG_LEVEL_VERBOSE: return "";
7763  case MA_LOG_LEVEL_INFO: return "INFO";
7764  case MA_LOG_LEVEL_WARNING: return "WARNING";
7765  case MA_LOG_LEVEL_ERROR: return "ERROR";
7766  default: return "ERROR";
7767  }
7768 }
7769 
7770 /* Posts a log message. */
7771 static void ma_post_log_message(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
7772 {
7773  if (pContext == NULL) {
7774  return;
7775  }
7776 
7777 #if defined(MA_LOG_LEVEL)
7778  if (logLevel <= MA_LOG_LEVEL) {
7779  ma_log_proc onLog;
7780 
7781  #if defined(MA_DEBUG_OUTPUT)
7782  if (logLevel <= MA_LOG_LEVEL) {
7783  printf("%s: %s\n", ma_log_level_to_string(logLevel), message);
7784  }
7785  #endif
7786 
7787  onLog = pContext->logCallback;
7788  if (onLog) {
7789  onLog(pContext, pDevice, logLevel, message);
7790  }
7791  }
7792 #endif
7793 }
7794 
7795 /* Posts an log message. Throw a breakpoint in here if you're needing to debug. The return value is always "resultCode". */
7796 static ma_result ma_context_post_error(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode)
7797 {
7798  /* Derive the context from the device if necessary. */
7799  if (pContext == NULL) {
7800  if (pDevice != NULL) {
7801  pContext = pDevice->pContext;
7802  }
7803  }
7804 
7805  ma_post_log_message(pContext, pDevice, logLevel, message);
7806  return resultCode;
7807 }
7808 
7809 static ma_result ma_post_error(ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode)
7810 {
7811  return ma_context_post_error(NULL, pDevice, logLevel, message, resultCode);
7812 }
7813 
7814 
7815 /*******************************************************************************
7816 
7817 Timing
7818 
7819 *******************************************************************************/
7820 #ifdef MA_WIN32
7821 LARGE_INTEGER g_ma_TimerFrequency = {{0}};
7822 static void ma_timer_init(ma_timer* pTimer)
7823 {
7824  LARGE_INTEGER counter;
7825 
7826  if (g_ma_TimerFrequency.QuadPart == 0) {
7827  QueryPerformanceFrequency(&g_ma_TimerFrequency);
7828  }
7829 
7830  QueryPerformanceCounter(&counter);
7831  pTimer->counter = counter.QuadPart;
7832 }
7833 
7834 static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
7835 {
7836  LARGE_INTEGER counter;
7837  if (!QueryPerformanceCounter(&counter)) {
7838  return 0;
7839  }
7840 
7841  return (double)(counter.QuadPart - pTimer->counter) / g_ma_TimerFrequency.QuadPart;
7842 }
7843 #elif defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
7844 ma_uint64 g_ma_TimerFrequency = 0;
7845 static void ma_timer_init(ma_timer* pTimer)
7846 {
7847  mach_timebase_info_data_t baseTime;
7848  mach_timebase_info(&baseTime);
7849  g_ma_TimerFrequency = (baseTime.denom * 1e9) / baseTime.numer;
7850 
7851  pTimer->counter = mach_absolute_time();
7852 }
7853 
7854 static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
7855 {
7856  ma_uint64 newTimeCounter = mach_absolute_time();
7857  ma_uint64 oldTimeCounter = pTimer->counter;
7858 
7859  return (newTimeCounter - oldTimeCounter) / g_ma_TimerFrequency;
7860 }
7861 #elif defined(MA_EMSCRIPTEN)
7862 static MA_INLINE void ma_timer_init(ma_timer* pTimer)
7863 {
7864  pTimer->counterD = emscripten_get_now();
7865 }
7866 
7867 static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer)
7868 {
7869  return (emscripten_get_now() - pTimer->counterD) / 1000; /* Emscripten is in milliseconds. */
7870 }
7871 #else
7872 #if _POSIX_C_SOURCE >= 199309L
7873 #if defined(CLOCK_MONOTONIC)
7874  #define MA_CLOCK_ID CLOCK_MONOTONIC
7875 #else
7876  #define MA_CLOCK_ID CLOCK_REALTIME
7877 #endif
7878 
7879 static void ma_timer_init(ma_timer* pTimer)
7880 {
7881  struct timespec newTime;
7882  clock_gettime(MA_CLOCK_ID, &newTime);
7883 
7884  pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec;
7885 }
7886 
7887 static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
7888 {
7889  ma_uint64 newTimeCounter;
7890  ma_uint64 oldTimeCounter;
7891 
7892  struct timespec newTime;
7893  clock_gettime(MA_CLOCK_ID, &newTime);
7894 
7895  newTimeCounter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec;
7896  oldTimeCounter = pTimer->counter;
7897 
7898  return (newTimeCounter - oldTimeCounter) / 1000000000.0;
7899 }
7900 #else
7901 static void ma_timer_init(ma_timer* pTimer)
7902 {
7903  struct timeval newTime;
7904  gettimeofday(&newTime, NULL);
7905 
7906  pTimer->counter = (newTime.tv_sec * 1000000) + newTime.tv_usec;
7907 }
7908 
7909 static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
7910 {
7911  ma_uint64 newTimeCounter;
7912  ma_uint64 oldTimeCounter;
7913 
7914  struct timeval newTime;
7915  gettimeofday(&newTime, NULL);
7916 
7917  newTimeCounter = (newTime.tv_sec * 1000000) + newTime.tv_usec;
7918  oldTimeCounter = pTimer->counter;
7919 
7920  return (newTimeCounter - oldTimeCounter) / 1000000.0;
7921 }
7922 #endif
7923 #endif
7924 
7925 
7926 /*******************************************************************************
7927 
7928 Dynamic Linking
7929 
7930 *******************************************************************************/
7931 ma_handle ma_dlopen(ma_context* pContext, const char* filename)
7932 {
7933  ma_handle handle;
7934 
7935 #if MA_LOG_LEVEL >= MA_LOG_LEVEL_VERBOSE
7936  if (pContext != NULL) {
7937  char message[256];
7938  ma_strappend(message, sizeof(message), "Loading library: ", filename);
7939  ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message);
7940  }
7941 #endif
7942 
7943 #ifdef _WIN32
7944 #ifdef MA_WIN32_DESKTOP
7945  handle = (ma_handle)LoadLibraryA(filename);
7946 #else
7947  /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */
7948  WCHAR filenameW[4096];
7949  if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) {
7950  handle = NULL;
7951  } else {
7952  handle = (ma_handle)LoadPackagedLibrary(filenameW, 0);
7953  }
7954 #endif
7955 #else
7956  handle = (ma_handle)dlopen(filename, RTLD_NOW);
7957 #endif
7958 
7959  /*
7960  I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority
7961  backend is a deliberate design choice. Instead I'm logging it as an informational message.
7962  */
7963 #if MA_LOG_LEVEL >= MA_LOG_LEVEL_INFO
7964  if (handle == NULL) {
7965  char message[256];
7966  ma_strappend(message, sizeof(message), "Failed to load library: ", filename);
7967  ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, message);
7968  }
7969 #endif
7970 
7971  (void)pContext; /* It's possible for pContext to be unused. */
7972  return handle;
7973 }
7974 
7975 void ma_dlclose(ma_context* pContext, ma_handle handle)
7976 {
7977 #ifdef _WIN32
7978  FreeLibrary((HMODULE)handle);
7979 #else
7980  dlclose((void*)handle);
7981 #endif
7982 
7983  (void)pContext;
7984 }
7985 
7986 ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symbol)
7987 {
7988  ma_proc proc;
7989 
7990 #if MA_LOG_LEVEL >= MA_LOG_LEVEL_VERBOSE
7991  if (pContext != NULL) {
7992  char message[256];
7993  ma_strappend(message, sizeof(message), "Loading symbol: ", symbol);
7994  ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message);
7995  }
7996 #endif
7997 
7998 #ifdef _WIN32
7999  proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol);
8000 #else
8001 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
8002  #pragma GCC diagnostic push
8003  #pragma GCC diagnostic ignored "-Wpedantic"
8004 #endif
8005  proc = (ma_proc)dlsym((void*)handle, symbol);
8006 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
8007  #pragma GCC diagnostic pop
8008 #endif
8009 #endif
8010 
8011 #if MA_LOG_LEVEL >= MA_LOG_LEVEL_WARNING
8012  if (handle == NULL) {
8013  char message[256];
8014  ma_strappend(message, sizeof(message), "Failed to load symbol: ", symbol);
8015  ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_WARNING, message);
8016  }
8017 #endif
8018 
8019  (void)pContext; /* It's possible for pContext to be unused. */
8020  return proc;
8021 }
8022 
8023 
8024 /*******************************************************************************
8025 
8026 Threading
8027 
8028 *******************************************************************************/
8029 #ifdef MA_WIN32
8030 static int ma_thread_priority_to_win32(ma_thread_priority priority)
8031 {
8032  switch (priority) {
8033  case ma_thread_priority_idle: return THREAD_PRIORITY_IDLE;
8034  case ma_thread_priority_lowest: return THREAD_PRIORITY_LOWEST;
8035  case ma_thread_priority_low: return THREAD_PRIORITY_BELOW_NORMAL;
8036  case ma_thread_priority_normal: return THREAD_PRIORITY_NORMAL;
8037  case ma_thread_priority_high: return THREAD_PRIORITY_ABOVE_NORMAL;
8038  case ma_thread_priority_highest: return THREAD_PRIORITY_HIGHEST;
8039  case ma_thread_priority_realtime: return THREAD_PRIORITY_TIME_CRITICAL;
8040  default: return THREAD_PRIORITY_NORMAL;
8041  }
8042 }
8043 
8044 static ma_result ma_thread_create__win32(ma_context* pContext, ma_thread* pThread, ma_thread_entry_proc entryProc, void* pData)
8045 {
8046  pThread->win32.hThread = CreateThread(NULL, 0, entryProc, pData, 0, NULL);
8047  if (pThread->win32.hThread == NULL) {
8048  return ma_result_from_GetLastError(GetLastError());
8049  }
8050 
8051  SetThreadPriority((HANDLE)pThread->win32.hThread, ma_thread_priority_to_win32(pContext->threadPriority));
8052 
8053  return MA_SUCCESS;
8054 }
8055 
8056 static void ma_thread_wait__win32(ma_thread* pThread)
8057 {
8058  WaitForSingleObject(pThread->win32.hThread, INFINITE);
8059 }
8060 
8061 static void ma_sleep__win32(ma_uint32 milliseconds)
8062 {
8063  Sleep((DWORD)milliseconds);
8064 }
8065 
8066 
8067 static ma_result ma_mutex_init__win32(ma_context* pContext, ma_mutex* pMutex)
8068 {
8069  (void)pContext;
8070 
8071  pMutex->win32.hMutex = CreateEventW(NULL, FALSE, TRUE, NULL);
8072  if (pMutex->win32.hMutex == NULL) {
8073  return ma_result_from_GetLastError(GetLastError());
8074  }
8075 
8076  return MA_SUCCESS;
8077 }
8078 
8079 static void ma_mutex_uninit__win32(ma_mutex* pMutex)
8080 {
8081  CloseHandle(pMutex->win32.hMutex);
8082 }
8083 
8084 static void ma_mutex_lock__win32(ma_mutex* pMutex)
8085 {
8086  WaitForSingleObject(pMutex->win32.hMutex, INFINITE);
8087 }
8088 
8089 static void ma_mutex_unlock__win32(ma_mutex* pMutex)
8090 {
8091  SetEvent(pMutex->win32.hMutex);
8092 }
8093 
8094 
8095 static ma_result ma_event_init__win32(ma_context* pContext, ma_event* pEvent)
8096 {
8097  (void)pContext;
8098 
8099  pEvent->win32.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
8100  if (pEvent->win32.hEvent == NULL) {
8101  return ma_result_from_GetLastError(GetLastError());
8102  }
8103 
8104  return MA_SUCCESS;
8105 }
8106 
8107 static void ma_event_uninit__win32(ma_event* pEvent)
8108 {
8109  CloseHandle(pEvent->win32.hEvent);
8110 }
8111 
8112 static ma_bool32 ma_event_wait__win32(ma_event* pEvent)
8113 {
8114  return WaitForSingleObject(pEvent->win32.hEvent, INFINITE) == WAIT_OBJECT_0;
8115 }
8116 
8117 static ma_bool32 ma_event_signal__win32(ma_event* pEvent)
8118 {
8119  return SetEvent(pEvent->win32.hEvent);
8120 }
8121 
8122 
8123 static ma_result ma_semaphore_init__win32(ma_context* pContext, int initialValue, ma_semaphore* pSemaphore)
8124 {
8125  (void)pContext;
8126 
8127  pSemaphore->win32.hSemaphore = CreateSemaphoreW(NULL, (LONG)initialValue, LONG_MAX, NULL);
8128  if (pSemaphore->win32.hSemaphore == NULL) {
8129  return ma_result_from_GetLastError(GetLastError());
8130  }
8131 
8132  return MA_SUCCESS;
8133 }
8134 
8135 static void ma_semaphore_uninit__win32(ma_semaphore* pSemaphore)
8136 {
8137  CloseHandle((HANDLE)pSemaphore->win32.hSemaphore);
8138 }
8139 
8140 static ma_bool32 ma_semaphore_wait__win32(ma_semaphore* pSemaphore)
8141 {
8142  return WaitForSingleObject((HANDLE)pSemaphore->win32.hSemaphore, INFINITE) == WAIT_OBJECT_0;
8143 }
8144 
8145 static ma_bool32 ma_semaphore_release__win32(ma_semaphore* pSemaphore)
8146 {
8147  return ReleaseSemaphore((HANDLE)pSemaphore->win32.hSemaphore, 1, NULL) != 0;
8148 }
8149 #endif
8150 
8151 
8152 #ifdef MA_POSIX
8153 #include <sched.h>
8154 
8155 typedef int (* ma_pthread_create_proc)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
8156 typedef int (* ma_pthread_join_proc)(pthread_t thread, void **retval);
8157 typedef int (* ma_pthread_mutex_init_proc)(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr);
8158 typedef int (* ma_pthread_mutex_destroy_proc)(pthread_mutex_t *__mutex);
8159 typedef int (* ma_pthread_mutex_lock_proc)(pthread_mutex_t *__mutex);
8160 typedef int (* ma_pthread_mutex_unlock_proc)(pthread_mutex_t *__mutex);
8161 typedef int (* ma_pthread_cond_init_proc)(pthread_cond_t *__restrict __cond, const pthread_condattr_t *__restrict __cond_attr);
8162 typedef int (* ma_pthread_cond_destroy_proc)(pthread_cond_t *__cond);
8163 typedef int (* ma_pthread_cond_signal_proc)(pthread_cond_t *__cond);
8164 typedef int (* ma_pthread_cond_wait_proc)(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex);
8165 typedef int (* ma_pthread_attr_init_proc)(pthread_attr_t *attr);
8166 typedef int (* ma_pthread_attr_destroy_proc)(pthread_attr_t *attr);
8167 typedef int (* ma_pthread_attr_setschedpolicy_proc)(pthread_attr_t *attr, int policy);
8168 typedef int (* ma_pthread_attr_getschedparam_proc)(const pthread_attr_t *attr, struct sched_param *param);
8169 typedef int (* ma_pthread_attr_setschedparam_proc)(pthread_attr_t *attr, const struct sched_param *param);
8170 
8171 static ma_result ma_thread_create__posix(ma_context* pContext, ma_thread* pThread, ma_thread_entry_proc entryProc, void* pData)
8172 {
8173  int result;
8174  pthread_attr_t* pAttr = NULL;
8175 
8176 #if !defined(__EMSCRIPTEN__)
8177  /* Try setting the thread priority. It's not critical if anything fails here. */
8178  pthread_attr_t attr;
8179  if (((ma_pthread_attr_init_proc)pContext->posix.pthread_attr_init)(&attr) == 0) {
8180  int scheduler = -1;
8181  if (pContext->threadPriority == ma_thread_priority_idle) {
8182 #ifdef SCHED_IDLE
8183  if (((ma_pthread_attr_setschedpolicy_proc)pContext->posix.pthread_attr_setschedpolicy)(&attr, SCHED_IDLE) == 0) {
8184  scheduler = SCHED_IDLE;
8185  }
8186 #endif
8187  } else if (pContext->threadPriority == ma_thread_priority_realtime) {
8188 #ifdef SCHED_FIFO
8189  if (((ma_pthread_attr_setschedpolicy_proc)pContext->posix.pthread_attr_setschedpolicy)(&attr, SCHED_FIFO) == 0) {
8190  scheduler = SCHED_FIFO;
8191  }
8192 #endif
8193 #ifdef MA_LINUX
8194  } else {
8195  scheduler = sched_getscheduler(0);
8196 #endif
8197  }
8198 
8199  if (scheduler != -1) {
8200  int priorityMin = sched_get_priority_min(scheduler);
8201  int priorityMax = sched_get_priority_max(scheduler);
8202  int priorityStep = (priorityMax - priorityMin) / 7; /* 7 = number of priorities supported by miniaudio. */
8203 
8204  struct sched_param sched;
8205  if (((ma_pthread_attr_getschedparam_proc)pContext->posix.pthread_attr_getschedparam)(&attr, &sched) == 0) {
8206  if (pContext->threadPriority == ma_thread_priority_idle) {
8207  sched.sched_priority = priorityMin;
8208  } else if (pContext->threadPriority == ma_thread_priority_realtime) {
8209  sched.sched_priority = priorityMax;
8210  } else {
8211  sched.sched_priority += ((int)pContext->threadPriority + 5) * priorityStep; /* +5 because the lowest priority is -5. */
8212  if (sched.sched_priority < priorityMin) {
8213  sched.sched_priority = priorityMin;
8214  }
8215  if (sched.sched_priority > priorityMax) {
8216  sched.sched_priority = priorityMax;
8217  }
8218  }
8219 
8220  if (((ma_pthread_attr_setschedparam_proc)pContext->posix.pthread_attr_setschedparam)(&attr, &sched) == 0) {
8221  pAttr = &attr;
8222  }
8223  }
8224  }
8225 
8226  ((ma_pthread_attr_destroy_proc)pContext->posix.pthread_attr_destroy)(&attr);
8227  }
8228 #endif
8229 
8230  result = ((ma_pthread_create_proc)pContext->posix.pthread_create)(&pThread->posix.thread, pAttr, entryProc, pData);
8231  if (result != 0) {
8232  return ma_result_from_errno(result);
8233  }
8234 
8235  return MA_SUCCESS;
8236 }
8237 
8238 static void ma_thread_wait__posix(ma_thread* pThread)
8239 {
8240  ((ma_pthread_join_proc)pThread->pContext->posix.pthread_join)(pThread->posix.thread, NULL);
8241 }
8242 
8243 #if !defined(MA_EMSCRIPTEN)
8244 static void ma_sleep__posix(ma_uint32 milliseconds)
8245 {
8246 #ifdef MA_EMSCRIPTEN
8247  (void)milliseconds;
8248  MA_ASSERT(MA_FALSE); /* The Emscripten build should never sleep. */
8249 #else
8250  #if _POSIX_C_SOURCE >= 199309L
8251  struct timespec ts;
8252  ts.tv_sec = milliseconds / 1000000;
8253  ts.tv_nsec = milliseconds % 1000000 * 1000000;
8254  nanosleep(&ts, NULL);
8255  #else
8256  struct timeval tv;
8257  tv.tv_sec = milliseconds / 1000;
8258  tv.tv_usec = milliseconds % 1000 * 1000;
8259  select(0, NULL, NULL, NULL, &tv);
8260  #endif
8261 #endif
8262 }
8263 #endif /* MA_EMSCRIPTEN */
8264 
8265 
8266 static ma_result ma_mutex_init__posix(ma_context* pContext, ma_mutex* pMutex)
8267 {
8268  int result = ((ma_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pMutex->posix.mutex, NULL);
8269  if (result != 0) {
8270  return ma_result_from_errno(result);
8271  }
8272 
8273  return MA_SUCCESS;
8274 }
8275 
8276 static void ma_mutex_uninit__posix(ma_mutex* pMutex)
8277 {
8278  ((ma_pthread_mutex_destroy_proc)pMutex->pContext->posix.pthread_mutex_destroy)(&pMutex->posix.mutex);
8279 }
8280 
8281 static void ma_mutex_lock__posix(ma_mutex* pMutex)
8282 {
8283  ((ma_pthread_mutex_lock_proc)pMutex->pContext->posix.pthread_mutex_lock)(&pMutex->posix.mutex);
8284 }
8285 
8286 static void ma_mutex_unlock__posix(ma_mutex* pMutex)
8287 {
8288  ((ma_pthread_mutex_unlock_proc)pMutex->pContext->posix.pthread_mutex_unlock)(&pMutex->posix.mutex);
8289 }
8290 
8291 
8292 static ma_result ma_event_init__posix(ma_context* pContext, ma_event* pEvent)
8293 {
8294  int result;
8295 
8296  result = ((ma_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pEvent->posix.mutex, NULL);
8297  if (result != 0) {
8298  return ma_result_from_errno(result);
8299  }
8300 
8301  result = ((ma_pthread_cond_init_proc)pContext->posix.pthread_cond_init)(&pEvent->posix.condition, NULL);
8302  if (result != 0) {
8303  ((ma_pthread_mutex_destroy_proc)pEvent->pContext->posix.pthread_mutex_destroy)(&pEvent->posix.mutex);
8304  return ma_result_from_errno(result);
8305  }
8306 
8307  pEvent->posix.value = 0;
8308  return MA_SUCCESS;
8309 }
8310 
8311 static void ma_event_uninit__posix(ma_event* pEvent)
8312 {
8313  ((ma_pthread_cond_destroy_proc)pEvent->pContext->posix.pthread_cond_destroy)(&pEvent->posix.condition);
8314  ((ma_pthread_mutex_destroy_proc)pEvent->pContext->posix.pthread_mutex_destroy)(&pEvent->posix.mutex);
8315 }
8316 
8317 static ma_bool32 ma_event_wait__posix(ma_event* pEvent)
8318 {
8319  ((ma_pthread_mutex_lock_proc)pEvent->pContext->posix.pthread_mutex_lock)(&pEvent->posix.mutex);
8320  {
8321  while (pEvent->posix.value == 0) {
8322  ((ma_pthread_cond_wait_proc)pEvent->pContext->posix.pthread_cond_wait)(&pEvent->posix.condition, &pEvent->posix.mutex);
8323  }
8324  pEvent->posix.value = 0; /* Auto-reset. */
8325  }
8326  ((ma_pthread_mutex_unlock_proc)pEvent->pContext->posix.pthread_mutex_unlock)(&pEvent->posix.mutex);
8327 
8328  return MA_TRUE;
8329 }
8330 
8332 {
8333  ((ma_pthread_mutex_lock_proc)pEvent->pContext->posix.pthread_mutex_lock)(&pEvent->posix.mutex);
8334  {
8335  pEvent->posix.value = 1;
8336  ((ma_pthread_cond_signal_proc)pEvent->pContext->posix.pthread_cond_signal)(&pEvent->posix.condition);
8337  }
8338  ((ma_pthread_mutex_unlock_proc)pEvent->pContext->posix.pthread_mutex_unlock)(&pEvent->posix.mutex);
8339 
8340  return MA_TRUE;
8341 }
8342 
8343 
8344 static ma_result ma_semaphore_init__posix(ma_context* pContext, int initialValue, ma_semaphore* pSemaphore)
8345 {
8346  (void)pContext;
8347 
8348 #if defined(MA_APPLE)
8349  /* Not yet implemented for Apple platforms since sem_init() is deprecated. Need to use a named semaphore via sem_open() instead. */
8350  return MA_INVALID_OPERATION;
8351 #else
8352  if (sem_init(&pSemaphore->posix.semaphore, 0, (unsigned int)initialValue) == 0) {
8353  return ma_result_from_errno(errno);
8354  }
8355 #endif
8356 
8357  return MA_SUCCESS;
8358 }
8359 
8360 static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore)
8361 {
8362  sem_close(&pSemaphore->posix.semaphore);
8363 }
8364 
8366 {
8367  return sem_wait(&pSemaphore->posix.semaphore) != -1;
8368 }
8369 
8371 {
8372  return sem_post(&pSemaphore->posix.semaphore) != -1;
8373 }
8374 #endif
8375 
8376 static ma_result ma_thread_create(ma_context* pContext, ma_thread* pThread, ma_thread_entry_proc entryProc, void* pData)
8377 {
8378  if (pContext == NULL || pThread == NULL || entryProc == NULL) {
8379  return MA_FALSE;
8380  }
8381 
8382  pThread->pContext = pContext;
8383 
8384 #ifdef MA_WIN32
8385  return ma_thread_create__win32(pContext, pThread, entryProc, pData);
8386 #endif
8387 #ifdef MA_POSIX
8388  return ma_thread_create__posix(pContext, pThread, entryProc, pData);
8389 #endif
8390 }
8391 
8392 static void ma_thread_wait(ma_thread* pThread)
8393 {
8394  if (pThread == NULL) {
8395  return;
8396  }
8397 
8398 #ifdef MA_WIN32
8399  ma_thread_wait__win32(pThread);
8400 #endif
8401 #ifdef MA_POSIX
8402  ma_thread_wait__posix(pThread);
8403 #endif
8404 }
8405 
8406 #if !defined(MA_EMSCRIPTEN)
8407 static void ma_sleep(ma_uint32 milliseconds)
8408 {
8409 #ifdef MA_WIN32
8410  ma_sleep__win32(milliseconds);
8411 #endif
8412 #ifdef MA_POSIX
8413  ma_sleep__posix(milliseconds);
8414 #endif
8415 }
8416 #endif
8417 
8418 
8419 ma_result ma_mutex_init(ma_context* pContext, ma_mutex* pMutex)
8420 {
8421  if (pContext == NULL || pMutex == NULL) {
8422  return MA_INVALID_ARGS;
8423  }
8424 
8425  pMutex->pContext = pContext;
8426 
8427 #ifdef MA_WIN32
8428  return ma_mutex_init__win32(pContext, pMutex);
8429 #endif
8430 #ifdef MA_POSIX
8431  return ma_mutex_init__posix(pContext, pMutex);
8432 #endif
8433 }
8434 
8435 void ma_mutex_uninit(ma_mutex* pMutex)
8436 {
8437  if (pMutex == NULL || pMutex->pContext == NULL) {
8438  return;
8439  }
8440 
8441 #ifdef MA_WIN32
8442  ma_mutex_uninit__win32(pMutex);
8443 #endif
8444 #ifdef MA_POSIX
8445  ma_mutex_uninit__posix(pMutex);
8446 #endif
8447 }
8448 
8449 void ma_mutex_lock(ma_mutex* pMutex)
8450 {
8451  if (pMutex == NULL || pMutex->pContext == NULL) {
8452  return;
8453  }
8454 
8455 #ifdef MA_WIN32
8456  ma_mutex_lock__win32(pMutex);
8457 #endif
8458 #ifdef MA_POSIX
8459  ma_mutex_lock__posix(pMutex);
8460 #endif
8461 }
8462 
8463 void ma_mutex_unlock(ma_mutex* pMutex)
8464 {
8465  if (pMutex == NULL || pMutex->pContext == NULL) {
8466  return;
8467 }
8468 
8469 #ifdef MA_WIN32
8470  ma_mutex_unlock__win32(pMutex);
8471 #endif
8472 #ifdef MA_POSIX
8473  ma_mutex_unlock__posix(pMutex);
8474 #endif
8475 }
8476 
8477 
8478 ma_result ma_event_init(ma_context* pContext, ma_event* pEvent)
8479 {
8480  if (pContext == NULL || pEvent == NULL) {
8481  return MA_FALSE;
8482  }
8483 
8484  pEvent->pContext = pContext;
8485 
8486 #ifdef MA_WIN32
8487  return ma_event_init__win32(pContext, pEvent);
8488 #endif
8489 #ifdef MA_POSIX
8490  return ma_event_init__posix(pContext, pEvent);
8491 #endif
8492 }
8493 
8494 void ma_event_uninit(ma_event* pEvent)
8495 {
8496  if (pEvent == NULL || pEvent->pContext == NULL) {
8497  return;
8498  }
8499 
8500 #ifdef MA_WIN32
8501  ma_event_uninit__win32(pEvent);
8502 #endif
8503 #ifdef MA_POSIX
8504  ma_event_uninit__posix(pEvent);
8505 #endif
8506 }
8507 
8509 {
8510  if (pEvent == NULL || pEvent->pContext == NULL) {
8511  return MA_FALSE;
8512  }
8513 
8514 #ifdef MA_WIN32
8515  return ma_event_wait__win32(pEvent);
8516 #endif
8517 #ifdef MA_POSIX
8518  return ma_event_wait__posix(pEvent);
8519 #endif
8520 }
8521 
8523 {
8524  if (pEvent == NULL || pEvent->pContext == NULL) {
8525  return MA_FALSE;
8526  }
8527 
8528 #ifdef MA_WIN32
8529  return ma_event_signal__win32(pEvent);
8530 #endif
8531 #ifdef MA_POSIX
8532  return ma_event_signal__posix(pEvent);
8533 #endif
8534 }
8535 
8536 
8537 ma_result ma_semaphore_init(ma_context* pContext, int initialValue, ma_semaphore* pSemaphore)
8538 {
8539  if (pContext == NULL || pSemaphore == NULL) {
8540  return MA_INVALID_ARGS;
8541  }
8542 
8543 #ifdef MA_WIN32
8544  return ma_semaphore_init__win32(pContext, initialValue, pSemaphore);
8545 #endif
8546 #ifdef MA_POSIX
8547  return ma_semaphore_init__posix(pContext, initialValue, pSemaphore);
8548 #endif
8549 }
8550 
8551 void ma_semaphore_uninit(ma_semaphore* pSemaphore)
8552 {
8553  if (pSemaphore == NULL) {
8554  return;
8555  }
8556 
8557 #ifdef MA_WIN32
8558  ma_semaphore_uninit__win32(pSemaphore);
8559 #endif
8560 #ifdef MA_POSIX
8561  ma_semaphore_uninit__posix(pSemaphore);
8562 #endif
8563 }
8564 
8566 {
8567  if (pSemaphore == NULL) {
8568  return MA_FALSE;
8569  }
8570 
8571 #ifdef MA_WIN32
8572  return ma_semaphore_wait__win32(pSemaphore);
8573 #endif
8574 #ifdef MA_POSIX
8575  return ma_semaphore_wait__posix(pSemaphore);
8576 #endif
8577 }
8578 
8580 {
8581  if (pSemaphore == NULL) {
8582  return MA_FALSE;
8583  }
8584 
8585 #ifdef MA_WIN32
8586  return ma_semaphore_release__win32(pSemaphore);
8587 #endif
8588 #ifdef MA_POSIX
8589  return ma_semaphore_release__posix(pSemaphore);
8590 #endif
8591 }
8592 
8593 
8594 #if 0
8595 ma_uint32 ma_get_closest_standard_sample_rate(ma_uint32 sampleRateIn)
8596 {
8597  ma_uint32 closestRate = 0;
8598  ma_uint32 closestDiff = 0xFFFFFFFF;
8599  size_t iStandardRate;
8600 
8601  for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) {
8602  ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate];
8603  ma_uint32 diff;
8604 
8605  if (sampleRateIn > standardRate) {
8606  diff = sampleRateIn - standardRate;
8607  } else {
8608  diff = standardRate - sampleRateIn;
8609  }
8610 
8611  if (diff == 0) {
8612  return standardRate; /* The input sample rate is a standard rate. */
8613  }
8614 
8615  if (closestDiff > diff) {
8616  closestDiff = diff;
8617  closestRate = standardRate;
8618  }
8619  }
8620 
8621  return closestRate;
8622 }
8623 #endif
8624 
8625 ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale)
8626 {
8627  return ma_max(1, (ma_uint32)(baseBufferSize*scale));
8628 }
8629 
8631 {
8632  return bufferSizeInFrames / (sampleRate/1000);
8633 }
8634 
8636 {
8637  return bufferSizeInMilliseconds * (sampleRate/1000);
8638 }
8639 
8640 void ma_zero_pcm_frames(void* p, ma_uint32 frameCount, ma_format format, ma_uint32 channels)
8641 {
8642  MA_ZERO_MEMORY(p, frameCount * ma_get_bytes_per_frame(format, channels));
8643 }
8644 
8645 void ma_clip_samples_f32(float* p, ma_uint32 sampleCount)
8646 {
8647  ma_uint32 iSample;
8648 
8649  /* TODO: Research a branchless SSE implementation. */
8650  for (iSample = 0; iSample < sampleCount; iSample += 1) {
8651  p[iSample] = ma_clip_f32(p[iSample]);
8652  }
8653 }
8654 
8655 
8656 void ma_copy_and_apply_volume_factor_u8(ma_uint8* pSamplesOut, const ma_uint8* pSamplesIn, ma_uint32 sampleCount, float factor)
8657 {
8658  ma_uint32 iSample;
8659 
8660  if (pSamplesOut == NULL || pSamplesIn == NULL) {
8661  return;
8662  }
8663 
8664  for (iSample = 0; iSample < sampleCount; iSample += 1) {
8665  pSamplesOut[iSample] = (ma_uint8)(pSamplesIn[iSample] * factor);
8666  }
8667 }
8668 
8669 void ma_copy_and_apply_volume_factor_s16(ma_int16* pSamplesOut, const ma_int16* pSamplesIn, ma_uint32 sampleCount, float factor)
8670 {
8671  ma_uint32 iSample;
8672 
8673  if (pSamplesOut == NULL || pSamplesIn == NULL) {
8674  return;
8675  }
8676 
8677  for (iSample = 0; iSample < sampleCount; iSample += 1) {
8678  pSamplesOut[iSample] = (ma_int16)(pSamplesIn[iSample] * factor);
8679  }
8680 }
8681 
8682 void ma_copy_and_apply_volume_factor_s24(void* pSamplesOut, const void* pSamplesIn, ma_uint32 sampleCount, float factor)
8683 {
8684  ma_uint32 iSample;
8685  ma_uint8* pSamplesOut8;
8686  ma_uint8* pSamplesIn8;
8687 
8688  if (pSamplesOut == NULL || pSamplesIn == NULL) {
8689  return;
8690  }
8691 
8692  pSamplesOut8 = (ma_uint8*)pSamplesOut;
8693  pSamplesIn8 = (ma_uint8*)pSamplesIn;
8694 
8695  for (iSample = 0; iSample < sampleCount; iSample += 1) {
8696  ma_int32 sampleS32;
8697 
8698  sampleS32 = (ma_int32)(((ma_uint32)(pSamplesIn8[iSample*3+0]) << 8) | ((ma_uint32)(pSamplesIn8[iSample*3+1]) << 16) | ((ma_uint32)(pSamplesIn8[iSample*3+2])) << 24);
8699  sampleS32 = (ma_int32)(sampleS32 * factor);
8700 
8701  pSamplesOut8[iSample*3+0] = (ma_uint8)(((ma_uint32)sampleS32 & 0x0000FF00) >> 8);
8702  pSamplesOut8[iSample*3+1] = (ma_uint8)(((ma_uint32)sampleS32 & 0x00FF0000) >> 16);
8703  pSamplesOut8[iSample*3+2] = (ma_uint8)(((ma_uint32)sampleS32 & 0xFF000000) >> 24);
8704  }
8705 }
8706 
8707 void ma_copy_and_apply_volume_factor_s32(ma_int32* pSamplesOut, const ma_int32* pSamplesIn, ma_uint32 sampleCount, float factor)
8708 {
8709  ma_uint32 iSample;
8710 
8711  if (pSamplesOut == NULL || pSamplesIn == NULL) {
8712  return;
8713  }
8714 
8715  for (iSample = 0; iSample < sampleCount; iSample += 1) {
8716  pSamplesOut[iSample] = (ma_int32)(pSamplesIn[iSample] * factor);
8717  }
8718 }
8719 
8720 void ma_copy_and_apply_volume_factor_f32(float* pSamplesOut, const float* pSamplesIn, ma_uint32 sampleCount, float factor)
8721 {
8722  ma_uint32 iSample;
8723 
8724  if (pSamplesOut == NULL || pSamplesIn == NULL) {
8725  return;
8726  }
8727 
8728  for (iSample = 0; iSample < sampleCount; iSample += 1) {
8729  pSamplesOut[iSample] = pSamplesIn[iSample] * factor;
8730  }
8731 }
8732 
8733 void ma_apply_volume_factor_u8(ma_uint8* pSamples, ma_uint32 sampleCount, float factor)
8734 {
8735  ma_copy_and_apply_volume_factor_u8(pSamples, pSamples, sampleCount, factor);
8736 }
8737 
8738 void ma_apply_volume_factor_s16(ma_int16* pSamples, ma_uint32 sampleCount, float factor)
8739 {
8740  ma_copy_and_apply_volume_factor_s16(pSamples, pSamples, sampleCount, factor);
8741 }
8742 
8743 void ma_apply_volume_factor_s24(void* pSamples, ma_uint32 sampleCount, float factor)
8744 {
8745  ma_copy_and_apply_volume_factor_s24(pSamples, pSamples, sampleCount, factor);
8746 }
8747 
8748 void ma_apply_volume_factor_s32(ma_int32* pSamples, ma_uint32 sampleCount, float factor)
8749 {
8750  ma_copy_and_apply_volume_factor_s32(pSamples, pSamples, sampleCount, factor);
8751 }
8752 
8753 void ma_apply_volume_factor_f32(float* pSamples, ma_uint32 sampleCount, float factor)
8754 {
8755  ma_copy_and_apply_volume_factor_f32(pSamples, pSamples, sampleCount, factor);
8756 }
8757 
8758 void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFramesOut, const ma_uint8* pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor)
8759 {
8760  ma_copy_and_apply_volume_factor_u8(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor);
8761 }
8762 
8763 void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFramesOut, const ma_int16* pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor)
8764 {
8765  ma_copy_and_apply_volume_factor_s16(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor);
8766 }
8767 
8768 void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor)
8769 {
8770  ma_copy_and_apply_volume_factor_s24(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor);
8771 }
8772 
8773 void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFramesOut, const ma_int32* pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor)
8774 {
8775  ma_copy_and_apply_volume_factor_s32(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor);
8776 }
8777 
8778 void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pPCMFramesOut, const float* pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor)
8779 {
8780  ma_copy_and_apply_volume_factor_f32(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor);
8781 }
8782 
8783 void ma_copy_and_apply_volume_factor_pcm_frames(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint32 frameCount, ma_format format, ma_uint32 channels, float factor)
8784 {
8785  switch (format)
8786  {
8787  case ma_format_u8: ma_copy_and_apply_volume_factor_pcm_frames_u8 ((ma_uint8*)pPCMFramesOut, (const ma_uint8*)pPCMFramesIn, frameCount, channels, factor); return;
8788  case ma_format_s16: ma_copy_and_apply_volume_factor_pcm_frames_s16((ma_int16*)pPCMFramesOut, (const ma_int16*)pPCMFramesIn, frameCount, channels, factor); return;
8789  case ma_format_s24: ma_copy_and_apply_volume_factor_pcm_frames_s24( pPCMFramesOut, pPCMFramesIn, frameCount, channels, factor); return;
8790  case ma_format_s32: ma_copy_and_apply_volume_factor_pcm_frames_s32((ma_int32*)pPCMFramesOut, (const ma_int32*)pPCMFramesIn, frameCount, channels, factor); return;
8791  case ma_format_f32: ma_copy_and_apply_volume_factor_pcm_frames_f32( (float*)pPCMFramesOut, (const float*)pPCMFramesIn, frameCount, channels, factor); return;
8792  default: return; /* Do nothing. */
8793  }
8794 }
8795 
8796 void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFrames, ma_uint32 frameCount, ma_uint32 channels, float factor)
8797 {
8798  ma_copy_and_apply_volume_factor_pcm_frames_u8(pPCMFrames, pPCMFrames, frameCount, channels, factor);
8799 }
8800 
8801 void ma_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFrames, ma_uint32 frameCount, ma_uint32 channels, float factor)
8802 {
8803  ma_copy_and_apply_volume_factor_pcm_frames_s16(pPCMFrames, pPCMFrames, frameCount, channels, factor);
8804 }
8805 
8806 void ma_apply_volume_factor_pcm_frames_s24(void* pPCMFrames, ma_uint32 frameCount, ma_uint32 channels, float factor)
8807 {
8808  ma_copy_and_apply_volume_factor_pcm_frames_s24(pPCMFrames, pPCMFrames, frameCount, channels, factor);
8809 }
8810 
8811 void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFrames, ma_uint32 frameCount, ma_uint32 channels, float factor)
8812 {
8813  ma_copy_and_apply_volume_factor_pcm_frames_s32(pPCMFrames, pPCMFrames, frameCount, channels, factor);
8814 }
8815 
8816 void ma_apply_volume_factor_pcm_frames_f32(float* pPCMFrames, ma_uint32 frameCount, ma_uint32 channels, float factor)
8817 {
8818  ma_copy_and_apply_volume_factor_pcm_frames_f32(pPCMFrames, pPCMFrames, frameCount, channels, factor);
8819 }
8820 
8821 void ma_apply_volume_factor_pcm_frames(void* pPCMFrames, ma_uint32 frameCount, ma_format format, ma_uint32 channels, float factor)
8822 {
8823  ma_copy_and_apply_volume_factor_pcm_frames(pPCMFrames, pPCMFrames, frameCount, format, channels, factor);
8824 }
8825 
8826 
8827 float ma_factor_to_gain_db(float factor)
8828 {
8829  return (float)(20*ma_log10f(factor));
8830 }
8831 
8832 float ma_gain_db_to_factor(float gain)
8833 {
8834  return (float)ma_powf(10, gain/20.0f);
8835 }
8836 
8837 
8838 static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
8839 {
8840  float masterVolumeFactor;
8841 
8842  masterVolumeFactor = pDevice->masterVolumeFactor;
8843 
8844  if (pDevice->onData) {
8845  if (!pDevice->noPreZeroedOutputBuffer && pFramesOut != NULL) {
8846  ma_zero_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels);
8847  }
8848 
8849  /* Volume control of input makes things a bit awkward because the input buffer is read-only. We'll need to use a temp buffer and loop in this case. */
8850  if (pFramesIn != NULL && masterVolumeFactor < 1) {
8852  ma_uint32 bpfCapture = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
8853  ma_uint32 bpfPlayback = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
8854  ma_uint32 totalFramesProcessed = 0;
8855  while (totalFramesProcessed < frameCount) {
8856  ma_uint32 framesToProcessThisIteration = frameCount - totalFramesProcessed;
8857  if (framesToProcessThisIteration > sizeof(tempFramesIn)/bpfCapture) {
8858  framesToProcessThisIteration = sizeof(tempFramesIn)/bpfCapture;
8859  }
8860 
8861  ma_copy_and_apply_volume_factor_pcm_frames(tempFramesIn, ma_offset_ptr(pFramesIn, totalFramesProcessed*bpfCapture), framesToProcessThisIteration, pDevice->capture.format, pDevice->capture.channels, masterVolumeFactor);
8862 
8863  pDevice->onData(pDevice, ma_offset_ptr(pFramesOut, totalFramesProcessed*bpfPlayback), tempFramesIn, framesToProcessThisIteration);
8864 
8865  totalFramesProcessed += framesToProcessThisIteration;
8866  }
8867  } else {
8868  pDevice->onData(pDevice, pFramesOut, pFramesIn, frameCount);
8869  }
8870 
8871  /* Volume control and clipping for playback devices. */
8872  if (pFramesOut != NULL) {
8873  if (masterVolumeFactor < 1) {
8874  if (pFramesIn == NULL) { /* <-- In full-duplex situations, the volume will have been applied to the input samples before the data callback. Applying it again post-callback will incorrectly compound it. */
8875  ma_apply_volume_factor_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels, masterVolumeFactor);
8876  }
8877  }
8878 
8879  if (!pDevice->noClip && pDevice->playback.format == ma_format_f32) {
8880  ma_clip_pcm_frames_f32((float*)pFramesOut, frameCount, pDevice->playback.channels);
8881  }
8882  }
8883  }
8884 }
8885 
8886 
8887 
8888 /* A helper function for reading sample data from the client. */
8889 static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 frameCount, void* pFramesOut)
8890 {
8891  MA_ASSERT(pDevice != NULL);
8892  MA_ASSERT(frameCount > 0);
8893  MA_ASSERT(pFramesOut != NULL);
8894 
8895  if (pDevice->playback.converter.isPassthrough) {
8896  ma_device__on_data(pDevice, pFramesOut, NULL, frameCount);
8897  } else {
8898  ma_result result;
8899  ma_uint64 totalFramesReadOut;
8900  ma_uint64 totalFramesReadIn;
8901  void* pRunningFramesOut;
8902 
8903  totalFramesReadOut = 0;
8904  totalFramesReadIn = 0;
8905  pRunningFramesOut = pFramesOut;
8906 
8907  while (totalFramesReadOut < frameCount) {
8908  ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In client format. */
8909  ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
8910  ma_uint64 framesToReadThisIterationIn;
8911  ma_uint64 framesReadThisIterationIn;
8912  ma_uint64 framesToReadThisIterationOut;
8913  ma_uint64 framesReadThisIterationOut;
8914  ma_uint64 requiredInputFrameCount;
8915 
8916  framesToReadThisIterationOut = (frameCount - totalFramesReadOut);
8917  framesToReadThisIterationIn = framesToReadThisIterationOut;
8918  if (framesToReadThisIterationIn > intermediaryBufferCap) {
8919  framesToReadThisIterationIn = intermediaryBufferCap;
8920  }
8921 
8922  requiredInputFrameCount = ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, frameCount);
8923  if (framesToReadThisIterationIn > requiredInputFrameCount) {
8924  framesToReadThisIterationIn = requiredInputFrameCount;
8925  }
8926 
8927  if (framesToReadThisIterationIn > 0) {
8928  ma_device__on_data(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn);
8929  totalFramesReadIn += framesToReadThisIterationIn;
8930  }
8931 
8932  /*
8933  At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any
8934  input frames, we still want to try processing frames because there may some output frames generated from cached input data.
8935  */
8936  framesReadThisIterationIn = framesToReadThisIterationIn;
8937  framesReadThisIterationOut = framesToReadThisIterationOut;
8938  result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut);
8939  if (result != MA_SUCCESS) {
8940  break;
8941  }
8942 
8943  totalFramesReadOut += framesReadThisIterationOut;
8944  pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
8945 
8946  if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) {
8947  break; /* We're done. */
8948  }
8949  }
8950  }
8951 }
8952 
8953 /* A helper for sending sample data to the client. */
8954 static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat)
8955 {
8956  MA_ASSERT(pDevice != NULL);
8957  MA_ASSERT(frameCountInDeviceFormat > 0);
8958  MA_ASSERT(pFramesInDeviceFormat != NULL);
8959 
8960  if (pDevice->capture.converter.isPassthrough) {
8961  ma_device__on_data(pDevice, NULL, pFramesInDeviceFormat, frameCountInDeviceFormat);
8962  } else {
8963  ma_result result;
8964  ma_uint8 pFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
8965  ma_uint64 framesInClientFormatCap = sizeof(pFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
8966  ma_uint64 totalDeviceFramesProcessed = 0;
8967  ma_uint64 totalClientFramesProcessed = 0;
8968  const void* pRunningFramesInDeviceFormat = pFramesInDeviceFormat;
8969 
8970  /* We just keep going until we've exhaused all of our input frames and cannot generate any more output frames. */
8971  for (;;) {
8972  ma_uint64 deviceFramesProcessedThisIteration;
8973  ma_uint64 clientFramesProcessedThisIteration;
8974 
8975  deviceFramesProcessedThisIteration = (frameCountInDeviceFormat - totalDeviceFramesProcessed);
8976  clientFramesProcessedThisIteration = framesInClientFormatCap;
8977 
8978  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningFramesInDeviceFormat, &deviceFramesProcessedThisIteration, pFramesInClientFormat, &clientFramesProcessedThisIteration);
8979  if (result != MA_SUCCESS) {
8980  break;
8981  }
8982 
8983  if (clientFramesProcessedThisIteration > 0) {
8984  ma_device__on_data(pDevice, NULL, pFramesInClientFormat, (ma_uint32)clientFramesProcessedThisIteration); /* Safe cast. */
8985  }
8986 
8987  pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, deviceFramesProcessedThisIteration * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
8988  totalDeviceFramesProcessed += deviceFramesProcessedThisIteration;
8989  totalClientFramesProcessed += clientFramesProcessedThisIteration;
8990 
8991  if (deviceFramesProcessedThisIteration == 0 && clientFramesProcessedThisIteration == 0) {
8992  break; /* We're done. */
8993  }
8994  }
8995  }
8996 }
8997 
8998 
8999 /* We only want to expose ma_device__handle_duplex_callback_capture() and ma_device__handle_duplex_callback_playback() if we have an asynchronous backend enabled. */
9000 #if defined(MA_HAS_JACK) || \
9001  defined(MA_HAS_COREAUDIO) || \
9002  defined(MA_HAS_AAUDIO) || \
9003  defined(MA_HAS_OPENSL) || \
9004  defined(MA_HAS_WEBAUDIO)
9005 static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat, ma_pcm_rb* pRB)
9006 {
9007  ma_result result;
9008  ma_uint32 totalDeviceFramesProcessed = 0;
9009  const void* pRunningFramesInDeviceFormat = pFramesInDeviceFormat;
9010 
9011  MA_ASSERT(pDevice != NULL);
9012  MA_ASSERT(frameCountInDeviceFormat > 0);
9013  MA_ASSERT(pFramesInDeviceFormat != NULL);
9014  MA_ASSERT(pRB != NULL);
9015 
9016  /* Write to the ring buffer. The ring buffer is in the client format which means we need to convert. */
9017  for (;;) {
9018  ma_uint32 framesToProcessInDeviceFormat = (frameCountInDeviceFormat - totalDeviceFramesProcessed);
9019  ma_uint32 framesToProcessInClientFormat = MA_DATA_CONVERTER_STACK_BUFFER_SIZE / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
9020  ma_uint64 framesProcessedInDeviceFormat;
9021  ma_uint64 framesProcessedInClientFormat;
9022  void* pFramesInClientFormat;
9023 
9024  result = ma_pcm_rb_acquire_write(pRB, &framesToProcessInClientFormat, &pFramesInClientFormat);
9025  if (result != MA_SUCCESS) {
9026  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer.", result);
9027  break;
9028  }
9029 
9030  if (framesToProcessInClientFormat == 0) {
9032  break; /* Overrun. Not enough room in the ring buffer for input frame. Excess frames are dropped. */
9033  }
9034  }
9035 
9036  /* Convert. */
9037  framesProcessedInDeviceFormat = framesToProcessInDeviceFormat;
9038  framesProcessedInClientFormat = framesToProcessInClientFormat;
9039  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningFramesInDeviceFormat, &framesProcessedInDeviceFormat, pFramesInClientFormat, &framesProcessedInClientFormat);
9040  if (result != MA_SUCCESS) {
9041  break;
9042  }
9043 
9044  result = ma_pcm_rb_commit_write(pRB, (ma_uint32)framesProcessedInDeviceFormat, pFramesInClientFormat); /* Safe cast. */
9045  if (result != MA_SUCCESS) {
9046  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer.", result);
9047  break;
9048  }
9049 
9050  pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, framesProcessedInDeviceFormat * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
9051  totalDeviceFramesProcessed += (ma_uint32)framesProcessedInDeviceFormat; /* Safe cast. */
9052 
9053  /* We're done when we're unable to process any client nor device frames. */
9054  if (framesProcessedInClientFormat == 0 && framesProcessedInDeviceFormat == 0) {
9055  break; /* Done. */
9056  }
9057  }
9058 
9059  return MA_SUCCESS;
9060 }
9061 
9062 static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, ma_uint32 frameCount, void* pFramesInInternalFormat, ma_pcm_rb* pRB)
9063 {
9064  ma_result result;
9065  ma_uint8 playbackFramesInExternalFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
9066  ma_uint8 silentInputFrames[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
9067  ma_uint32 totalFramesToReadFromClient;
9068  ma_uint32 totalFramesReadFromClient;
9069  ma_uint32 totalFramesReadOut = 0;
9070 
9071  MA_ASSERT(pDevice != NULL);
9072  MA_ASSERT(frameCount > 0);
9073  MA_ASSERT(pFramesInInternalFormat != NULL);
9074  MA_ASSERT(pRB != NULL);
9075 
9076  /*
9077  Sitting in the ring buffer should be captured data from the capture callback in external format. If there's not enough data in there for
9078  the whole frameCount frames we just use silence instead for the input data.
9079  */
9080  MA_ZERO_MEMORY(silentInputFrames, sizeof(silentInputFrames));
9081 
9082  /* We need to calculate how many output frames are required to be read from the client to completely fill frameCount internal frames. */
9083  totalFramesToReadFromClient = (ma_uint32)ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, frameCount);
9084  totalFramesReadFromClient = 0;
9085  while (totalFramesReadFromClient < totalFramesToReadFromClient && ma_device_is_started(pDevice)) {
9086  ma_uint32 framesRemainingFromClient;
9087  ma_uint32 framesToProcessFromClient;
9088  ma_uint32 inputFrameCount;
9089  void* pInputFrames;
9090 
9091  framesRemainingFromClient = (totalFramesToReadFromClient - totalFramesReadFromClient);
9092  framesToProcessFromClient = sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
9093  if (framesToProcessFromClient > framesRemainingFromClient) {
9094  framesToProcessFromClient = framesRemainingFromClient;
9095  }
9096 
9097  /* We need to grab captured samples before firing the callback. If there's not enough input samples we just pass silence. */
9098  inputFrameCount = framesToProcessFromClient;
9099  result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames);
9100  if (result == MA_SUCCESS) {
9101  if (inputFrameCount > 0) {
9102  /* Use actual input frames. */
9103  ma_device__on_data(pDevice, playbackFramesInExternalFormat, pInputFrames, inputFrameCount);
9104  } else {
9105  if (ma_pcm_rb_pointer_distance(pRB) == 0) {
9106  break; /* Underrun. */
9107  }
9108  }
9109 
9110  /* We're done with the captured samples. */
9111  result = ma_pcm_rb_commit_read(pRB, inputFrameCount, pInputFrames);
9112  if (result != MA_SUCCESS) {
9113  break; /* Don't know what to do here... Just abandon ship. */
9114  }
9115  } else {
9116  /* Use silent input frames. */
9117  inputFrameCount = ma_min(
9118  sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels),
9119  sizeof(silentInputFrames) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels)
9120  );
9121 
9122  ma_device__on_data(pDevice, playbackFramesInExternalFormat, silentInputFrames, inputFrameCount);
9123  }
9124 
9125  /* We have samples in external format so now we need to convert to internal format and output to the device. */
9126  {
9127  ma_uint64 framesConvertedIn = inputFrameCount;
9128  ma_uint64 framesConvertedOut = (frameCount - totalFramesReadOut);
9129  ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackFramesInExternalFormat, &framesConvertedIn, pFramesInInternalFormat, &framesConvertedOut);
9130 
9131  totalFramesReadFromClient += (ma_uint32)framesConvertedIn; /* Safe cast. */
9132  totalFramesReadOut += (ma_uint32)framesConvertedOut; /* Safe cast. */
9133  pFramesInInternalFormat = ma_offset_ptr(pFramesInInternalFormat, framesConvertedOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
9134  }
9135  }
9136 
9137  return MA_SUCCESS;
9138 }
9139 #endif /* Asynchronous backends. */
9140 
9141 /* A helper for changing the state of the device. */
9142 static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_uint32 newState)
9143 {
9144  ma_atomic_exchange_32(&pDevice->state, newState);
9145 }
9146 
9147 /* A helper for getting the state of the device. */
9148 static MA_INLINE ma_uint32 ma_device__get_state(ma_device* pDevice)
9149 {
9150  return pDevice->state;
9151 }
9152 
9153 
9154 #ifdef MA_WIN32
9155  GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
9156  GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
9157  /*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/
9158  /*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/
9159 #endif
9160 
9161 
9162 typedef struct
9163 {
9164  ma_device_type deviceType;
9165  const ma_device_id* pDeviceID;
9166  char* pName;
9167  size_t nameBufferSize;
9168  ma_bool32 foundDevice;
9169 } ma_context__try_get_device_name_by_id__enum_callback_data;
9170 
9171 static ma_bool32 ma_context__try_get_device_name_by_id__enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pDeviceInfo, void* pUserData)
9172 {
9173  ma_context__try_get_device_name_by_id__enum_callback_data* pData = (ma_context__try_get_device_name_by_id__enum_callback_data*)pUserData;
9174  MA_ASSERT(pData != NULL);
9175 
9176  if (pData->deviceType == deviceType) {
9177  if (pContext->onDeviceIDEqual(pContext, pData->pDeviceID, &pDeviceInfo->id)) {
9178  ma_strncpy_s(pData->pName, pData->nameBufferSize, pDeviceInfo->name, (size_t)-1);
9179  pData->foundDevice = MA_TRUE;
9180  }
9181  }
9182 
9183  return !pData->foundDevice;
9184 }
9185 
9186 /*
9187 Generic function for retrieving the name of a device by it's ID.
9188 
9189 This function simply enumerates every device and then retrieves the name of the first device that has the same ID.
9190 */
9191 static ma_result ma_context__try_get_device_name_by_id(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, char* pName, size_t nameBufferSize)
9192 {
9193  ma_result result;
9194  ma_context__try_get_device_name_by_id__enum_callback_data data;
9195 
9196  MA_ASSERT(pContext != NULL);
9197  MA_ASSERT(pName != NULL);
9198 
9199  if (pDeviceID == NULL) {
9200  return MA_NO_DEVICE;
9201  }
9202 
9203  data.deviceType = deviceType;
9204  data.pDeviceID = pDeviceID;
9205  data.pName = pName;
9206  data.nameBufferSize = nameBufferSize;
9207  data.foundDevice = MA_FALSE;
9208  result = ma_context_enumerate_devices(pContext, ma_context__try_get_device_name_by_id__enum_callback, &data);
9209  if (result != MA_SUCCESS) {
9210  return result;
9211  }
9212 
9213  if (!data.foundDevice) {
9214  return MA_NO_DEVICE;
9215  } else {
9216  return MA_SUCCESS;
9217  }
9218 }
9219 
9220 
9221 ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = better. */
9222 {
9223  ma_uint32 i;
9224  for (i = 0; i < ma_countof(g_maFormatPriorities); ++i) {
9225  if (g_maFormatPriorities[i] == format) {
9226  return i;
9227  }
9228  }
9229 
9230  /* Getting here means the format could not be found or is equal to ma_format_unknown. */
9231  return (ma_uint32)-1;
9232 }
9233 
9234 static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType);
9235 
9236 
9237 /*******************************************************************************
9238 
9239 Null Backend
9240 
9241 *******************************************************************************/
9242 #ifdef MA_HAS_NULL
9243 
9244 #define MA_DEVICE_OP_NONE__NULL 0
9245 #define MA_DEVICE_OP_START__NULL 1
9246 #define MA_DEVICE_OP_SUSPEND__NULL 2
9247 #define MA_DEVICE_OP_KILL__NULL 3
9248 
9250 {
9251  ma_device* pDevice = (ma_device*)pData;
9252  MA_ASSERT(pDevice != NULL);
9253 
9254  for (;;) { /* Keep the thread alive until the device is uninitialized. */
9255  /* Wait for an operation to be requested. */
9256  ma_event_wait(&pDevice->null_device.operationEvent);
9257 
9258  /* At this point an event should have been triggered. */
9259 
9260  /* Starting the device needs to put the thread into a loop. */
9261  if (pDevice->null_device.operation == MA_DEVICE_OP_START__NULL) {
9262  ma_atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL);
9263 
9264  /* Reset the timer just in case. */
9265  ma_timer_init(&pDevice->null_device.timer);
9266 
9267  /* Keep looping until an operation has been requested. */
9268  while (pDevice->null_device.operation != MA_DEVICE_OP_NONE__NULL && pDevice->null_device.operation != MA_DEVICE_OP_START__NULL) {
9269  ma_sleep(10); /* Don't hog the CPU. */
9270  }
9271 
9272  /* Getting here means a suspend or kill operation has been requested. */
9273  ma_atomic_exchange_32(&pDevice->null_device.operationResult, MA_SUCCESS);
9274  ma_event_signal(&pDevice->null_device.operationCompletionEvent);
9275  continue;
9276  }
9277 
9278  /* Suspending the device means we need to stop the timer and just continue the loop. */
9279  if (pDevice->null_device.operation == MA_DEVICE_OP_SUSPEND__NULL) {
9280  ma_atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL);
9281 
9282  /* We need to add the current run time to the prior run time, then reset the timer. */
9283  pDevice->null_device.priorRunTime += ma_timer_get_time_in_seconds(&pDevice->null_device.timer);
9284  ma_timer_init(&pDevice->null_device.timer);
9285 
9286  /* We're done. */
9287  ma_atomic_exchange_32(&pDevice->null_device.operationResult, MA_SUCCESS);
9288  ma_event_signal(&pDevice->null_device.operationCompletionEvent);
9289  continue;
9290  }
9291 
9292  /* Killing the device means we need to get out of this loop so that this thread can terminate. */
9293  if (pDevice->null_device.operation == MA_DEVICE_OP_KILL__NULL) {
9294  ma_atomic_exchange_32(&pDevice->null_device.operation, MA_DEVICE_OP_NONE__NULL);
9295  ma_atomic_exchange_32(&pDevice->null_device.operationResult, MA_SUCCESS);
9296  ma_event_signal(&pDevice->null_device.operationCompletionEvent);
9297  break;
9298  }
9299 
9300  /* Getting a signal on a "none" operation probably means an error. Return invalid operation. */
9301  if (pDevice->null_device.operation == MA_DEVICE_OP_NONE__NULL) {
9302  MA_ASSERT(MA_FALSE); /* <-- Trigger this in debug mode to ensure developers are aware they're doing something wrong (or there's a bug in a miniaudio). */
9303  ma_atomic_exchange_32(&pDevice->null_device.operationResult, MA_INVALID_OPERATION);
9304  ma_event_signal(&pDevice->null_device.operationCompletionEvent);
9305  continue; /* Continue the loop. Don't terminate. */
9306  }
9307  }
9308 
9309  return (ma_thread_result)0;
9310 }
9311 
9312 static ma_result ma_device_do_operation__null(ma_device* pDevice, ma_uint32 operation)
9313 {
9314  ma_atomic_exchange_32(&pDevice->null_device.operation, operation);
9315  if (!ma_event_signal(&pDevice->null_device.operationEvent)) {
9316  return MA_ERROR;
9317  }
9318 
9319  if (!ma_event_wait(&pDevice->null_device.operationCompletionEvent)) {
9320  return MA_ERROR;
9321  }
9322 
9323  return pDevice->null_device.operationResult;
9324 }
9325 
9327 {
9328  ma_uint32 internalSampleRate;
9329  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
9330  internalSampleRate = pDevice->capture.internalSampleRate;
9331  } else {
9332  internalSampleRate = pDevice->playback.internalSampleRate;
9333  }
9334 
9335 
9336  return (ma_uint64)((pDevice->null_device.priorRunTime + ma_timer_get_time_in_seconds(&pDevice->null_device.timer)) * internalSampleRate);
9337 }
9338 
9339 static ma_bool32 ma_context_is_device_id_equal__null(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
9340 {
9341  MA_ASSERT(pContext != NULL);
9342  MA_ASSERT(pID0 != NULL);
9343  MA_ASSERT(pID1 != NULL);
9344  (void)pContext;
9345 
9346  return pID0->nullbackend == pID1->nullbackend;
9347 }
9348 
9349 static ma_result ma_context_enumerate_devices__null(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
9350 {
9351  ma_bool32 cbResult = MA_TRUE;
9352 
9353  MA_ASSERT(pContext != NULL);
9354  MA_ASSERT(callback != NULL);
9355 
9356  /* Playback. */
9357  if (cbResult) {
9358  ma_device_info deviceInfo;
9359  MA_ZERO_OBJECT(&deviceInfo);
9360  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Playback Device", (size_t)-1);
9361  cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
9362  }
9363 
9364  /* Capture. */
9365  if (cbResult) {
9366  ma_device_info deviceInfo;
9367  MA_ZERO_OBJECT(&deviceInfo);
9368  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Capture Device", (size_t)-1);
9369  cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
9370  }
9371 
9372  return MA_SUCCESS;
9373 }
9374 
9375 static ma_result ma_context_get_device_info__null(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
9376 {
9377  ma_uint32 iFormat;
9378 
9379  MA_ASSERT(pContext != NULL);
9380 
9381  if (pDeviceID != NULL && pDeviceID->nullbackend != 0) {
9382  return MA_NO_DEVICE; /* Don't know the device. */
9383  }
9384 
9385  /* Name / Description */
9386  if (deviceType == ma_device_type_playback) {
9387  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Playback Device", (size_t)-1);
9388  } else {
9389  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Capture Device", (size_t)-1);
9390  }
9391 
9392  /* Support everything on the null backend. */
9393  pDeviceInfo->formatCount = ma_format_count - 1; /* Minus one because we don't want to include ma_format_unknown. */
9394  for (iFormat = 0; iFormat < pDeviceInfo->formatCount; ++iFormat) {
9395  pDeviceInfo->formats[iFormat] = (ma_format)(iFormat + 1); /* +1 to skip over ma_format_unknown. */
9396  }
9397 
9398  pDeviceInfo->minChannels = 1;
9399  pDeviceInfo->maxChannels = MA_MAX_CHANNELS;
9400  pDeviceInfo->minSampleRate = MA_SAMPLE_RATE_8000;
9401  pDeviceInfo->maxSampleRate = MA_SAMPLE_RATE_384000;
9402 
9403  (void)pContext;
9404  (void)shareMode;
9405  return MA_SUCCESS;
9406 }
9407 
9408 
9409 static void ma_device_uninit__null(ma_device* pDevice)
9410 {
9411  MA_ASSERT(pDevice != NULL);
9412 
9413  /* Keep it clean and wait for the device thread to finish before returning. */
9415 
9416  /* At this point the loop in the device thread is as good as terminated so we can uninitialize our events. */
9417  ma_event_uninit(&pDevice->null_device.operationCompletionEvent);
9418  ma_event_uninit(&pDevice->null_device.operationEvent);
9419 }
9420 
9421 static ma_result ma_device_init__null(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
9422 {
9423  ma_result result;
9424  ma_uint32 periodSizeInFrames;
9425 
9426  MA_ASSERT(pDevice != NULL);
9427 
9428  MA_ZERO_OBJECT(&pDevice->null_device);
9429 
9430  if (pConfig->deviceType == ma_device_type_loopback) {
9432  }
9433 
9434  periodSizeInFrames = pConfig->periodSizeInFrames;
9435  if (periodSizeInFrames == 0) {
9437  }
9438 
9439  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
9440  ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "NULL Capture Device", (size_t)-1);
9441  pDevice->capture.internalFormat = pConfig->capture.format;
9442  pDevice->capture.internalChannels = pConfig->capture.channels;
9444  pDevice->capture.internalPeriodSizeInFrames = periodSizeInFrames;
9445  pDevice->capture.internalPeriods = pConfig->periods;
9446  }
9447  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
9448  ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), "NULL Playback Device", (size_t)-1);
9449  pDevice->playback.internalFormat = pConfig->playback.format;
9450  pDevice->playback.internalChannels = pConfig->playback.channels;
9452  pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames;
9453  pDevice->playback.internalPeriods = pConfig->periods;
9454  }
9455 
9456  /*
9457  In order to get timing right, we need to create a thread that does nothing but keeps track of the timer. This timer is started when the
9458  first period is "written" to it, and then stopped in ma_device_stop__null().
9459  */
9460  result = ma_event_init(pContext, &pDevice->null_device.operationEvent);
9461  if (result != MA_SUCCESS) {
9462  return result;
9463  }
9464 
9465  result = ma_event_init(pContext, &pDevice->null_device.operationCompletionEvent);
9466  if (result != MA_SUCCESS) {
9467  return result;
9468  }
9469 
9470  result = ma_thread_create(pContext, &pDevice->thread, ma_device_thread__null, pDevice);
9471  if (result != MA_SUCCESS) {
9472  return result;
9473  }
9474 
9475  return MA_SUCCESS;
9476 }
9477 
9478 static ma_result ma_device_start__null(ma_device* pDevice)
9479 {
9480  MA_ASSERT(pDevice != NULL);
9481 
9483 
9484  ma_atomic_exchange_32(&pDevice->null_device.isStarted, MA_TRUE);
9485  return MA_SUCCESS;
9486 }
9487 
9488 static ma_result ma_device_stop__null(ma_device* pDevice)
9489 {
9490  MA_ASSERT(pDevice != NULL);
9491 
9493 
9494  ma_atomic_exchange_32(&pDevice->null_device.isStarted, MA_FALSE);
9495  return MA_SUCCESS;
9496 }
9497 
9498 static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
9499 {
9500  ma_result result = MA_SUCCESS;
9501  ma_uint32 totalPCMFramesProcessed;
9502  ma_bool32 wasStartedOnEntry;
9503 
9504  if (pFramesWritten != NULL) {
9505  *pFramesWritten = 0;
9506  }
9507 
9508  wasStartedOnEntry = pDevice->null_device.isStarted;
9509 
9510  /* Keep going until everything has been read. */
9511  totalPCMFramesProcessed = 0;
9512  while (totalPCMFramesProcessed < frameCount) {
9513  ma_uint64 targetFrame;
9514 
9515  /* If there are any frames remaining in the current period, consume those first. */
9516  if (pDevice->null_device.currentPeriodFramesRemainingPlayback > 0) {
9517  ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed);
9518  ma_uint32 framesToProcess = pDevice->null_device.currentPeriodFramesRemainingPlayback;
9519  if (framesToProcess > framesRemaining) {
9520  framesToProcess = framesRemaining;
9521  }
9522 
9523  /* We don't actually do anything with pPCMFrames, so just mark it as unused to prevent a warning. */
9524  (void)pPCMFrames;
9525 
9526  pDevice->null_device.currentPeriodFramesRemainingPlayback -= framesToProcess;
9527  totalPCMFramesProcessed += framesToProcess;
9528  }
9529 
9530  /* If we've consumed the current period we'll need to mark it as such an ensure the device is started if it's not already. */
9531  if (pDevice->null_device.currentPeriodFramesRemainingPlayback == 0) {
9532  pDevice->null_device.currentPeriodFramesRemainingPlayback = 0;
9533 
9534  if (!pDevice->null_device.isStarted && !wasStartedOnEntry) {
9535  result = ma_device_start__null(pDevice);
9536  if (result != MA_SUCCESS) {
9537  break;
9538  }
9539  }
9540  }
9541 
9542  /* If we've consumed the whole buffer we can return now. */
9543  MA_ASSERT(totalPCMFramesProcessed <= frameCount);
9544  if (totalPCMFramesProcessed == frameCount) {
9545  break;
9546  }
9547 
9548  /* Getting here means we've still got more frames to consume, we but need to wait for it to become available. */
9549  targetFrame = pDevice->null_device.lastProcessedFramePlayback;
9550  for (;;) {
9551  ma_uint64 currentFrame;
9552 
9553  /* Stop waiting if the device has been stopped. */
9554  if (!pDevice->null_device.isStarted) {
9555  break;
9556  }
9557 
9558  currentFrame = ma_device_get_total_run_time_in_frames__null(pDevice);
9559  if (currentFrame >= targetFrame) {
9560  break;
9561  }
9562 
9563  /* Getting here means we haven't yet reached the target sample, so continue waiting. */
9564  ma_sleep(10);
9565  }
9566 
9567  pDevice->null_device.lastProcessedFramePlayback += pDevice->playback.internalPeriodSizeInFrames;
9568  pDevice->null_device.currentPeriodFramesRemainingPlayback = pDevice->playback.internalPeriodSizeInFrames;
9569  }
9570 
9571  if (pFramesWritten != NULL) {
9572  *pFramesWritten = totalPCMFramesProcessed;
9573  }
9574 
9575  return result;
9576 }
9577 
9578 static ma_result ma_device_read__null(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
9579 {
9580  ma_result result = MA_SUCCESS;
9581  ma_uint32 totalPCMFramesProcessed;
9582 
9583  if (pFramesRead != NULL) {
9584  *pFramesRead = 0;
9585  }
9586 
9587  /* Keep going until everything has been read. */
9588  totalPCMFramesProcessed = 0;
9589  while (totalPCMFramesProcessed < frameCount) {
9590  ma_uint64 targetFrame;
9591 
9592  /* If there are any frames remaining in the current period, consume those first. */
9593  if (pDevice->null_device.currentPeriodFramesRemainingCapture > 0) {
9595  ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed);
9596  ma_uint32 framesToProcess = pDevice->null_device.currentPeriodFramesRemainingCapture;
9597  if (framesToProcess > framesRemaining) {
9598  framesToProcess = framesRemaining;
9599  }
9600 
9601  /* We need to ensured the output buffer is zeroed. */
9602  MA_ZERO_MEMORY(ma_offset_ptr(pPCMFrames, totalPCMFramesProcessed*bpf), framesToProcess*bpf);
9603 
9604  pDevice->null_device.currentPeriodFramesRemainingCapture -= framesToProcess;
9605  totalPCMFramesProcessed += framesToProcess;
9606  }
9607 
9608  /* If we've consumed the current period we'll need to mark it as such an ensure the device is started if it's not already. */
9609  if (pDevice->null_device.currentPeriodFramesRemainingCapture == 0) {
9610  pDevice->null_device.currentPeriodFramesRemainingCapture = 0;
9611  }
9612 
9613  /* If we've consumed the whole buffer we can return now. */
9614  MA_ASSERT(totalPCMFramesProcessed <= frameCount);
9615  if (totalPCMFramesProcessed == frameCount) {
9616  break;
9617  }
9618 
9619  /* Getting here means we've still got more frames to consume, we but need to wait for it to become available. */
9620  targetFrame = pDevice->null_device.lastProcessedFrameCapture + pDevice->capture.internalPeriodSizeInFrames;
9621  for (;;) {
9622  ma_uint64 currentFrame;
9623 
9624  /* Stop waiting if the device has been stopped. */
9625  if (!pDevice->null_device.isStarted) {
9626  break;
9627  }
9628 
9629  currentFrame = ma_device_get_total_run_time_in_frames__null(pDevice);
9630  if (currentFrame >= targetFrame) {
9631  break;
9632  }
9633 
9634  /* Getting here means we haven't yet reached the target sample, so continue waiting. */
9635  ma_sleep(10);
9636  }
9637 
9638  pDevice->null_device.lastProcessedFrameCapture += pDevice->capture.internalPeriodSizeInFrames;
9639  pDevice->null_device.currentPeriodFramesRemainingCapture = pDevice->capture.internalPeriodSizeInFrames;
9640  }
9641 
9642  if (pFramesRead != NULL) {
9643  *pFramesRead = totalPCMFramesProcessed;
9644  }
9645 
9646  return result;
9647 }
9648 
9649 static ma_result ma_device_main_loop__null(ma_device* pDevice)
9650 {
9651  ma_result result = MA_SUCCESS;
9652  ma_bool32 exitLoop = MA_FALSE;
9653 
9654  MA_ASSERT(pDevice != NULL);
9655 
9656  /* The capture device needs to be started immediately. */
9657  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
9658  result = ma_device_start__null(pDevice);
9659  if (result != MA_SUCCESS) {
9660  return result;
9661  }
9662  }
9663 
9664  while (ma_device__get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
9665  switch (pDevice->type)
9666  {
9667  case ma_device_type_duplex:
9668  {
9669  /* The process is: device_read -> convert -> callback -> convert -> device_write */
9670  ma_uint32 totalCapturedDeviceFramesProcessed = 0;
9671  ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
9672 
9673  while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
9674  ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
9675  ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
9676  ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
9677  ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
9678  ma_uint32 capturedDeviceFramesRemaining;
9679  ma_uint32 capturedDeviceFramesProcessed;
9680  ma_uint32 capturedDeviceFramesToProcess;
9681  ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed;
9682  if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) {
9683  capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames;
9684  }
9685 
9686  result = ma_device_read__null(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess);
9687  if (result != MA_SUCCESS) {
9688  exitLoop = MA_TRUE;
9689  break;
9690  }
9691 
9692  capturedDeviceFramesRemaining = capturedDeviceFramesToProcess;
9693  capturedDeviceFramesProcessed = 0;
9694 
9695  /* At this point we have our captured data in device format and we now need to convert it to client format. */
9696  for (;;) {
9697  ma_uint8 capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
9698  ma_uint8 playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
9699  ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
9700  ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
9701  ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames);
9702  ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining;
9703  ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
9704 
9705  /* Convert capture data from device format to client format. */
9706  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration);
9707  if (result != MA_SUCCESS) {
9708  break;
9709  }
9710 
9711  /*
9712  If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small
9713  which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
9714  */
9715  if (capturedClientFramesToProcessThisIteration == 0) {
9716  break;
9717  }
9718 
9719  ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/
9720 
9721  capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
9722  capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
9723 
9724  /* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */
9725  for (;;) {
9726  ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration;
9727  ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames;
9728  result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount);
9729  if (result != MA_SUCCESS) {
9730  break;
9731  }
9732 
9733  result = ma_device_write__null(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL); /* Safe cast. */
9734  if (result != MA_SUCCESS) {
9735  exitLoop = MA_TRUE;
9736  break;
9737  }
9738 
9739  capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount; /* Safe cast. */
9740  if (capturedClientFramesToProcessThisIteration == 0) {
9741  break;
9742  }
9743  }
9744 
9745  /* In case an error happened from ma_device_write__null()... */
9746  if (result != MA_SUCCESS) {
9747  exitLoop = MA_TRUE;
9748  break;
9749  }
9750  }
9751 
9752  totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed;
9753  }
9754  } break;
9755 
9757  {
9758  /* We read in chunks of the period size, but use a stack allocated buffer for the intermediary. */
9759  ma_uint8 intermediaryBuffer[8192];
9760  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
9761  ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
9762  ma_uint32 framesReadThisPeriod = 0;
9763  while (framesReadThisPeriod < periodSizeInFrames) {
9764  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
9765  ma_uint32 framesProcessed;
9766  ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
9767  if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
9768  framesToReadThisIteration = intermediaryBufferSizeInFrames;
9769  }
9770 
9771  result = ma_device_read__null(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
9772  if (result != MA_SUCCESS) {
9773  exitLoop = MA_TRUE;
9774  break;
9775  }
9776 
9777  ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
9778 
9779  framesReadThisPeriod += framesProcessed;
9780  }
9781  } break;
9782 
9784  {
9785  /* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
9786  ma_uint8 intermediaryBuffer[8192];
9787  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
9788  ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
9789  ma_uint32 framesWrittenThisPeriod = 0;
9790  while (framesWrittenThisPeriod < periodSizeInFrames) {
9791  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
9792  ma_uint32 framesProcessed;
9793  ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
9794  if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
9795  framesToWriteThisIteration = intermediaryBufferSizeInFrames;
9796  }
9797 
9798  ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
9799 
9800  result = ma_device_write__null(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
9801  if (result != MA_SUCCESS) {
9802  exitLoop = MA_TRUE;
9803  break;
9804  }
9805 
9806  framesWrittenThisPeriod += framesProcessed;
9807  }
9808  } break;
9809 
9810  /* To silence a warning. Will never hit this. */
9812  default: break;
9813  }
9814  }
9815 
9816 
9817  /* Here is where the device is started. */
9818  ma_device_stop__null(pDevice);
9819 
9820  return result;
9821 }
9822 
9824 {
9825  MA_ASSERT(pContext != NULL);
9826  MA_ASSERT(pContext->backend == ma_backend_null);
9827 
9828  (void)pContext;
9829  return MA_SUCCESS;
9830 }
9831 
9832 static ma_result ma_context_init__null(const ma_context_config* pConfig, ma_context* pContext)
9833 {
9834  MA_ASSERT(pContext != NULL);
9835 
9836  (void)pConfig;
9837 
9838  pContext->onUninit = ma_context_uninit__null;
9839  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__null;
9842  pContext->onDeviceInit = ma_device_init__null;
9844  pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */
9845  pContext->onDeviceStop = NULL; /* Not required for synchronous backends. */
9846  pContext->onDeviceMainLoop = ma_device_main_loop__null;
9847 
9848  /* The null backend always works. */
9849  return MA_SUCCESS;
9850 }
9851 #endif
9852 
9853 
9854 /*******************************************************************************
9855 
9856 WIN32 COMMON
9857 
9858 *******************************************************************************/
9859 #if defined(MA_WIN32)
9860 #if defined(MA_WIN32_DESKTOP)
9861  #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit)
9862  #define ma_CoUninitialize(pContext) ((MA_PFN_CoUninitialize)pContext->win32.CoUninitialize)()
9863  #define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) ((MA_PFN_CoCreateInstance)pContext->win32.CoCreateInstance)(rclsid, pUnkOuter, dwClsContext, riid, ppv)
9864  #define ma_CoTaskMemFree(pContext, pv) ((MA_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(pv)
9865  #define ma_PropVariantClear(pContext, pvar) ((MA_PFN_PropVariantClear)pContext->win32.PropVariantClear)(pvar)
9866 #else
9867  #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit) CoInitializeEx(pvReserved, dwCoInit)
9868  #define ma_CoUninitialize(pContext) CoUninitialize()
9869  #define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv) CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv)
9870  #define ma_CoTaskMemFree(pContext, pv) CoTaskMemFree(pv)
9871  #define ma_PropVariantClear(pContext, pvar) PropVariantClear(pvar)
9872 #endif
9873 
9874 #if !defined(MAXULONG_PTR)
9875 typedef size_t DWORD_PTR;
9876 #endif
9877 
9878 #if !defined(WAVE_FORMAT_44M08)
9879 #define WAVE_FORMAT_44M08 0x00000100
9880 #define WAVE_FORMAT_44S08 0x00000200
9881 #define WAVE_FORMAT_44M16 0x00000400
9882 #define WAVE_FORMAT_44S16 0x00000800
9883 #define WAVE_FORMAT_48M08 0x00001000
9884 #define WAVE_FORMAT_48S08 0x00002000
9885 #define WAVE_FORMAT_48M16 0x00004000
9886 #define WAVE_FORMAT_48S16 0x00008000
9887 #define WAVE_FORMAT_96M08 0x00010000
9888 #define WAVE_FORMAT_96S08 0x00020000
9889 #define WAVE_FORMAT_96M16 0x00040000
9890 #define WAVE_FORMAT_96S16 0x00080000
9891 #endif
9892 
9893 #ifndef SPEAKER_FRONT_LEFT
9894 #define SPEAKER_FRONT_LEFT 0x1
9895 #define SPEAKER_FRONT_RIGHT 0x2
9896 #define SPEAKER_FRONT_CENTER 0x4
9897 #define SPEAKER_LOW_FREQUENCY 0x8
9898 #define SPEAKER_BACK_LEFT 0x10
9899 #define SPEAKER_BACK_RIGHT 0x20
9900 #define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
9901 #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
9902 #define SPEAKER_BACK_CENTER 0x100
9903 #define SPEAKER_SIDE_LEFT 0x200
9904 #define SPEAKER_SIDE_RIGHT 0x400
9905 #define SPEAKER_TOP_CENTER 0x800
9906 #define SPEAKER_TOP_FRONT_LEFT 0x1000
9907 #define SPEAKER_TOP_FRONT_CENTER 0x2000
9908 #define SPEAKER_TOP_FRONT_RIGHT 0x4000
9909 #define SPEAKER_TOP_BACK_LEFT 0x8000
9910 #define SPEAKER_TOP_BACK_CENTER 0x10000
9911 #define SPEAKER_TOP_BACK_RIGHT 0x20000
9912 #endif
9913 
9914 /*
9915 The SDK that comes with old versions of MSVC (VC6, for example) does not appear to define WAVEFORMATEXTENSIBLE. We
9916 define our own implementation in this case.
9917 */
9918 #if (defined(_MSC_VER) && !defined(_WAVEFORMATEXTENSIBLE_)) || defined(__DMC__)
9919 typedef struct
9920 {
9921  WAVEFORMATEX Format;
9922  union
9923  {
9924  WORD wValidBitsPerSample;
9925  WORD wSamplesPerBlock;
9926  WORD wReserved;
9927  } Samples;
9928  DWORD dwChannelMask;
9929  GUID SubFormat;
9930 } WAVEFORMATEXTENSIBLE;
9931 #endif
9932 
9933 #ifndef WAVE_FORMAT_EXTENSIBLE
9934 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
9935 #endif
9936 
9937 #ifndef WAVE_FORMAT_IEEE_FLOAT
9938 #define WAVE_FORMAT_IEEE_FLOAT 0x0003
9939 #endif
9940 
9941 static GUID MA_GUID_NULL = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
9942 
9943 /* Converts an individual Win32-style channel identifier (SPEAKER_FRONT_LEFT, etc.) to miniaudio. */
9944 static ma_uint8 ma_channel_id_to_ma__win32(DWORD id)
9945 {
9946  switch (id)
9947  {
9948  case SPEAKER_FRONT_LEFT: return MA_CHANNEL_FRONT_LEFT;
9949  case SPEAKER_FRONT_RIGHT: return MA_CHANNEL_FRONT_RIGHT;
9950  case SPEAKER_FRONT_CENTER: return MA_CHANNEL_FRONT_CENTER;
9951  case SPEAKER_LOW_FREQUENCY: return MA_CHANNEL_LFE;
9952  case SPEAKER_BACK_LEFT: return MA_CHANNEL_BACK_LEFT;
9953  case SPEAKER_BACK_RIGHT: return MA_CHANNEL_BACK_RIGHT;
9954  case SPEAKER_FRONT_LEFT_OF_CENTER: return MA_CHANNEL_FRONT_LEFT_CENTER;
9955  case SPEAKER_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER;
9956  case SPEAKER_BACK_CENTER: return MA_CHANNEL_BACK_CENTER;
9957  case SPEAKER_SIDE_LEFT: return MA_CHANNEL_SIDE_LEFT;
9958  case SPEAKER_SIDE_RIGHT: return MA_CHANNEL_SIDE_RIGHT;
9959  case SPEAKER_TOP_CENTER: return MA_CHANNEL_TOP_CENTER;
9960  case SPEAKER_TOP_FRONT_LEFT: return MA_CHANNEL_TOP_FRONT_LEFT;
9961  case SPEAKER_TOP_FRONT_CENTER: return MA_CHANNEL_TOP_FRONT_CENTER;
9962  case SPEAKER_TOP_FRONT_RIGHT: return MA_CHANNEL_TOP_FRONT_RIGHT;
9963  case SPEAKER_TOP_BACK_LEFT: return MA_CHANNEL_TOP_BACK_LEFT;
9964  case SPEAKER_TOP_BACK_CENTER: return MA_CHANNEL_TOP_BACK_CENTER;
9965  case SPEAKER_TOP_BACK_RIGHT: return MA_CHANNEL_TOP_BACK_RIGHT;
9966  default: return 0;
9967  }
9968 }
9969 
9970 /* Converts an individual miniaudio channel identifier (MA_CHANNEL_FRONT_LEFT, etc.) to Win32-style. */
9971 static DWORD ma_channel_id_to_win32(DWORD id)
9972 {
9973  switch (id)
9974  {
9975  case MA_CHANNEL_MONO: return SPEAKER_FRONT_CENTER;
9976  case MA_CHANNEL_FRONT_LEFT: return SPEAKER_FRONT_LEFT;
9977  case MA_CHANNEL_FRONT_RIGHT: return SPEAKER_FRONT_RIGHT;
9978  case MA_CHANNEL_FRONT_CENTER: return SPEAKER_FRONT_CENTER;
9979  case MA_CHANNEL_LFE: return SPEAKER_LOW_FREQUENCY;
9980  case MA_CHANNEL_BACK_LEFT: return SPEAKER_BACK_LEFT;
9981  case MA_CHANNEL_BACK_RIGHT: return SPEAKER_BACK_RIGHT;
9982  case MA_CHANNEL_FRONT_LEFT_CENTER: return SPEAKER_FRONT_LEFT_OF_CENTER;
9983  case MA_CHANNEL_FRONT_RIGHT_CENTER: return SPEAKER_FRONT_RIGHT_OF_CENTER;
9984  case MA_CHANNEL_BACK_CENTER: return SPEAKER_BACK_CENTER;
9985  case MA_CHANNEL_SIDE_LEFT: return SPEAKER_SIDE_LEFT;
9986  case MA_CHANNEL_SIDE_RIGHT: return SPEAKER_SIDE_RIGHT;
9987  case MA_CHANNEL_TOP_CENTER: return SPEAKER_TOP_CENTER;
9988  case MA_CHANNEL_TOP_FRONT_LEFT: return SPEAKER_TOP_FRONT_LEFT;
9989  case MA_CHANNEL_TOP_FRONT_CENTER: return SPEAKER_TOP_FRONT_CENTER;
9990  case MA_CHANNEL_TOP_FRONT_RIGHT: return SPEAKER_TOP_FRONT_RIGHT;
9991  case MA_CHANNEL_TOP_BACK_LEFT: return SPEAKER_TOP_BACK_LEFT;
9992  case MA_CHANNEL_TOP_BACK_CENTER: return SPEAKER_TOP_BACK_CENTER;
9993  case MA_CHANNEL_TOP_BACK_RIGHT: return SPEAKER_TOP_BACK_RIGHT;
9994  default: return 0;
9995  }
9996 }
9997 
9998 /* Converts a channel mapping to a Win32-style channel mask. */
9999 static DWORD ma_channel_map_to_channel_mask__win32(const ma_channel channelMap[MA_MAX_CHANNELS], ma_uint32 channels)
10000 {
10001  DWORD dwChannelMask = 0;
10002  ma_uint32 iChannel;
10003 
10004  for (iChannel = 0; iChannel < channels; ++iChannel) {
10005  dwChannelMask |= ma_channel_id_to_win32(channelMap[iChannel]);
10006  }
10007 
10008  return dwChannelMask;
10009 }
10010 
10011 /* Converts a Win32-style channel mask to a miniaudio channel map. */
10012 static void ma_channel_mask_to_channel_map__win32(DWORD dwChannelMask, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS])
10013 {
10014  if (channels == 1 && dwChannelMask == 0) {
10015  channelMap[0] = MA_CHANNEL_MONO;
10016  } else if (channels == 2 && dwChannelMask == 0) {
10017  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
10018  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
10019  } else {
10020  if (channels == 1 && (dwChannelMask & SPEAKER_FRONT_CENTER) != 0) {
10021  channelMap[0] = MA_CHANNEL_MONO;
10022  } else {
10023  /* Just iterate over each bit. */
10024  ma_uint32 iChannel = 0;
10025  ma_uint32 iBit;
10026 
10027  for (iBit = 0; iBit < 32; ++iBit) {
10028  DWORD bitValue = (dwChannelMask & (1UL << iBit));
10029  if (bitValue != 0) {
10030  /* The bit is set. */
10031  channelMap[iChannel] = ma_channel_id_to_ma__win32(bitValue);
10032  iChannel += 1;
10033  }
10034  }
10035  }
10036  }
10037 }
10038 
10039 #ifdef __cplusplus
10040 static ma_bool32 ma_is_guid_equal(const void* a, const void* b)
10041 {
10042  return IsEqualGUID(*(const GUID*)a, *(const GUID*)b);
10043 }
10044 #else
10045 #define ma_is_guid_equal(a, b) IsEqualGUID((const GUID*)a, (const GUID*)b)
10046 #endif
10047 
10048 static ma_format ma_format_from_WAVEFORMATEX(const WAVEFORMATEX* pWF)
10049 {
10050  MA_ASSERT(pWF != NULL);
10051 
10052  if (pWF->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
10053  const WAVEFORMATEXTENSIBLE* pWFEX = (const WAVEFORMATEXTENSIBLE*)pWF;
10054  if (ma_is_guid_equal(&pWFEX->SubFormat, &MA_GUID_KSDATAFORMAT_SUBTYPE_PCM)) {
10055  if (pWFEX->Samples.wValidBitsPerSample == 32) {
10056  return ma_format_s32;
10057  }
10058  if (pWFEX->Samples.wValidBitsPerSample == 24) {
10059  if (pWFEX->Format.wBitsPerSample == 32) {
10060  /*return ma_format_s24_32;*/
10061  }
10062  if (pWFEX->Format.wBitsPerSample == 24) {
10063  return ma_format_s24;
10064  }
10065  }
10066  if (pWFEX->Samples.wValidBitsPerSample == 16) {
10067  return ma_format_s16;
10068  }
10069  if (pWFEX->Samples.wValidBitsPerSample == 8) {
10070  return ma_format_u8;
10071  }
10072  }
10073  if (ma_is_guid_equal(&pWFEX->SubFormat, &MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
10074  if (pWFEX->Samples.wValidBitsPerSample == 32) {
10075  return ma_format_f32;
10076  }
10077  /*
10078  if (pWFEX->Samples.wValidBitsPerSample == 64) {
10079  return ma_format_f64;
10080  }
10081  */
10082  }
10083  } else {
10084  if (pWF->wFormatTag == WAVE_FORMAT_PCM) {
10085  if (pWF->wBitsPerSample == 32) {
10086  return ma_format_s32;
10087  }
10088  if (pWF->wBitsPerSample == 24) {
10089  return ma_format_s24;
10090  }
10091  if (pWF->wBitsPerSample == 16) {
10092  return ma_format_s16;
10093  }
10094  if (pWF->wBitsPerSample == 8) {
10095  return ma_format_u8;
10096  }
10097  }
10098  if (pWF->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
10099  if (pWF->wBitsPerSample == 32) {
10100  return ma_format_f32;
10101  }
10102  if (pWF->wBitsPerSample == 64) {
10103  /*return ma_format_f64;*/
10104  }
10105  }
10106  }
10107 
10108  return ma_format_unknown;
10109 }
10110 #endif
10111 
10112 
10113 /*******************************************************************************
10114 
10115 WASAPI Backend
10116 
10117 *******************************************************************************/
10118 #ifdef MA_HAS_WASAPI
10119 #if 0
10120 #if defined(_MSC_VER)
10121  #pragma warning(push)
10122  #pragma warning(disable:4091) /* 'typedef ': ignored on left of '' when no variable is declared */
10123 #endif
10124 #include <audioclient.h>
10125 #include <mmdeviceapi.h>
10126 #if defined(_MSC_VER)
10127  #pragma warning(pop)
10128 #endif
10129 #endif /* 0 */
10130 
10131 /* Some compilers don't define VerifyVersionInfoW. Need to write this ourselves. */
10132 #define MA_WIN32_WINNT_VISTA 0x0600
10133 #define MA_VER_MINORVERSION 0x01
10134 #define MA_VER_MAJORVERSION 0x02
10135 #define MA_VER_SERVICEPACKMAJOR 0x20
10136 #define MA_VER_GREATER_EQUAL 0x03
10137 
10138 typedef struct {
10139  DWORD dwOSVersionInfoSize;
10140  DWORD dwMajorVersion;
10141  DWORD dwMinorVersion;
10142  DWORD dwBuildNumber;
10143  DWORD dwPlatformId;
10144  WCHAR szCSDVersion[128];
10145  WORD wServicePackMajor;
10146  WORD wServicePackMinor;
10147  WORD wSuiteMask;
10148  BYTE wProductType;
10149  BYTE wReserved;
10150 } ma_OSVERSIONINFOEXW;
10151 
10152 typedef BOOL (WINAPI * ma_PFNVerifyVersionInfoW) (ma_OSVERSIONINFOEXW* lpVersionInfo, DWORD dwTypeMask, DWORDLONG dwlConditionMask);
10153 typedef ULONGLONG (WINAPI * ma_PFNVerSetConditionMask)(ULONGLONG dwlConditionMask, DWORD dwTypeBitMask, BYTE dwConditionMask);
10154 
10155 
10156 #ifndef PROPERTYKEY_DEFINED
10157 #define PROPERTYKEY_DEFINED
10158 typedef struct
10159 {
10160  GUID fmtid;
10161  DWORD pid;
10162 } PROPERTYKEY;
10163 #endif
10164 
10165 /* Some compilers don't define PropVariantInit(). We just do this ourselves since it's just a memset(). */
10166 static MA_INLINE void ma_PropVariantInit(PROPVARIANT* pProp)
10167 {
10168  MA_ZERO_OBJECT(pProp);
10169 }
10170 
10171 
10172 static const PROPERTYKEY MA_PKEY_Device_FriendlyName = {{0xA45C254E, 0xDF1C, 0x4EFD, {0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0}}, 14};
10173 static const PROPERTYKEY MA_PKEY_AudioEngine_DeviceFormat = {{0xF19F064D, 0x82C, 0x4E27, {0xBC, 0x73, 0x68, 0x82, 0xA1, 0xBB, 0x8E, 0x4C}}, 0};
10174 
10175 static const IID MA_IID_IUnknown = {0x00000000, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; /* 00000000-0000-0000-C000-000000000046 */
10176 static const IID MA_IID_IAgileObject = {0x94EA2B94, 0xE9CC, 0x49E0, {0xC0, 0xFF, 0xEE, 0x64, 0xCA, 0x8F, 0x5B, 0x90}}; /* 94EA2B94-E9CC-49E0-C0FF-EE64CA8F5B90 */
10177 
10178 static const IID MA_IID_IAudioClient = {0x1CB9AD4C, 0xDBFA, 0x4C32, {0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2}}; /* 1CB9AD4C-DBFA-4C32-B178-C2F568A703B2 = __uuidof(IAudioClient) */
10179 static const IID MA_IID_IAudioClient2 = {0x726778CD, 0xF60A, 0x4EDA, {0x82, 0xDE, 0xE4, 0x76, 0x10, 0xCD, 0x78, 0xAA}}; /* 726778CD-F60A-4EDA-82DE-E47610CD78AA = __uuidof(IAudioClient2) */
10180 static const IID MA_IID_IAudioClient3 = {0x7ED4EE07, 0x8E67, 0x4CD4, {0x8C, 0x1A, 0x2B, 0x7A, 0x59, 0x87, 0xAD, 0x42}}; /* 7ED4EE07-8E67-4CD4-8C1A-2B7A5987AD42 = __uuidof(IAudioClient3) */
10181 static const IID MA_IID_IAudioRenderClient = {0xF294ACFC, 0x3146, 0x4483, {0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2}}; /* F294ACFC-3146-4483-A7BF-ADDCA7C260E2 = __uuidof(IAudioRenderClient) */
10182 static const IID MA_IID_IAudioCaptureClient = {0xC8ADBD64, 0xE71E, 0x48A0, {0xA4, 0xDE, 0x18, 0x5C, 0x39, 0x5C, 0xD3, 0x17}}; /* C8ADBD64-E71E-48A0-A4DE-185C395CD317 = __uuidof(IAudioCaptureClient) */
10183 static const IID MA_IID_IMMNotificationClient = {0x7991EEC9, 0x7E89, 0x4D85, {0x83, 0x90, 0x6C, 0x70, 0x3C, 0xEC, 0x60, 0xC0}}; /* 7991EEC9-7E89-4D85-8390-6C703CEC60C0 = __uuidof(IMMNotificationClient) */
10184 #ifndef MA_WIN32_DESKTOP
10185 static const IID MA_IID_DEVINTERFACE_AUDIO_RENDER = {0xE6327CAD, 0xDCEC, 0x4949, {0xAE, 0x8A, 0x99, 0x1E, 0x97, 0x6A, 0x79, 0xD2}}; /* E6327CAD-DCEC-4949-AE8A-991E976A79D2 */
10186 static const IID MA_IID_DEVINTERFACE_AUDIO_CAPTURE = {0x2EEF81BE, 0x33FA, 0x4800, {0x96, 0x70, 0x1C, 0xD4, 0x74, 0x97, 0x2C, 0x3F}}; /* 2EEF81BE-33FA-4800-9670-1CD474972C3F */
10187 static const IID MA_IID_IActivateAudioInterfaceCompletionHandler = {0x41D949AB, 0x9862, 0x444A, {0x80, 0xF6, 0xC2, 0x61, 0x33, 0x4D, 0xA5, 0xEB}}; /* 41D949AB-9862-444A-80F6-C261334DA5EB */
10188 #endif
10189 
10190 static const IID MA_CLSID_MMDeviceEnumerator_Instance = {0xBCDE0395, 0xE52F, 0x467C, {0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E}}; /* BCDE0395-E52F-467C-8E3D-C4579291692E = __uuidof(MMDeviceEnumerator) */
10191 static const IID MA_IID_IMMDeviceEnumerator_Instance = {0xA95664D2, 0x9614, 0x4F35, {0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6}}; /* A95664D2-9614-4F35-A746-DE8DB63617E6 = __uuidof(IMMDeviceEnumerator) */
10192 #ifdef __cplusplus
10193 #define MA_CLSID_MMDeviceEnumerator MA_CLSID_MMDeviceEnumerator_Instance
10194 #define MA_IID_IMMDeviceEnumerator MA_IID_IMMDeviceEnumerator_Instance
10195 #else
10196 #define MA_CLSID_MMDeviceEnumerator &MA_CLSID_MMDeviceEnumerator_Instance
10197 #define MA_IID_IMMDeviceEnumerator &MA_IID_IMMDeviceEnumerator_Instance
10198 #endif
10199 
10200 typedef struct ma_IUnknown ma_IUnknown;
10201 #ifdef MA_WIN32_DESKTOP
10202 #define MA_MM_DEVICE_STATE_ACTIVE 1
10203 #define MA_MM_DEVICE_STATE_DISABLED 2
10204 #define MA_MM_DEVICE_STATE_NOTPRESENT 4
10205 #define MA_MM_DEVICE_STATE_UNPLUGGED 8
10206 
10207 typedef struct ma_IMMDeviceEnumerator ma_IMMDeviceEnumerator;
10208 typedef struct ma_IMMDeviceCollection ma_IMMDeviceCollection;
10209 typedef struct ma_IMMDevice ma_IMMDevice;
10210 #else
10211 typedef struct ma_IActivateAudioInterfaceCompletionHandler ma_IActivateAudioInterfaceCompletionHandler;
10212 typedef struct ma_IActivateAudioInterfaceAsyncOperation ma_IActivateAudioInterfaceAsyncOperation;
10213 #endif
10214 typedef struct ma_IPropertyStore ma_IPropertyStore;
10215 typedef struct ma_IAudioClient ma_IAudioClient;
10216 typedef struct ma_IAudioClient2 ma_IAudioClient2;
10217 typedef struct ma_IAudioClient3 ma_IAudioClient3;
10218 typedef struct ma_IAudioRenderClient ma_IAudioRenderClient;
10219 typedef struct ma_IAudioCaptureClient ma_IAudioCaptureClient;
10220 
10221 typedef ma_int64 MA_REFERENCE_TIME;
10222 
10223 #define MA_AUDCLNT_STREAMFLAGS_CROSSPROCESS 0x00010000
10224 #define MA_AUDCLNT_STREAMFLAGS_LOOPBACK 0x00020000
10225 #define MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK 0x00040000
10226 #define MA_AUDCLNT_STREAMFLAGS_NOPERSIST 0x00080000
10227 #define MA_AUDCLNT_STREAMFLAGS_RATEADJUST 0x00100000
10228 #define MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000
10229 #define MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
10230 #define MA_AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED 0x10000000
10231 #define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE 0x20000000
10232 #define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED 0x40000000
10233 
10234 /* Buffer flags. */
10235 #define MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY 1
10236 #define MA_AUDCLNT_BUFFERFLAGS_SILENT 2
10237 #define MA_AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR 4
10238 
10239 typedef enum
10240 {
10241  ma_eRender = 0,
10242  ma_eCapture = 1,
10243  ma_eAll = 2
10244 } ma_EDataFlow;
10245 
10246 typedef enum
10247 {
10248  ma_eConsole = 0,
10249  ma_eMultimedia = 1,
10250  ma_eCommunications = 2
10251 } ma_ERole;
10252 
10253 typedef enum
10254 {
10255  MA_AUDCLNT_SHAREMODE_SHARED,
10256  MA_AUDCLNT_SHAREMODE_EXCLUSIVE
10257 } MA_AUDCLNT_SHAREMODE;
10258 
10259 typedef enum
10260 {
10261  MA_AudioCategory_Other = 0 /* <-- miniaudio is only caring about Other. */
10262 } MA_AUDIO_STREAM_CATEGORY;
10263 
10264 typedef struct
10265 {
10266  UINT32 cbSize;
10267  BOOL bIsOffload;
10268  MA_AUDIO_STREAM_CATEGORY eCategory;
10269 } ma_AudioClientProperties;
10270 
10271 /* IUnknown */
10272 typedef struct
10273 {
10274  /* IUnknown */
10275  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IUnknown* pThis, const IID* const riid, void** ppObject);
10276  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IUnknown* pThis);
10277  ULONG (STDMETHODCALLTYPE * Release) (ma_IUnknown* pThis);
10278 } ma_IUnknownVtbl;
10279 struct ma_IUnknown
10280 {
10281  ma_IUnknownVtbl* lpVtbl;
10282 };
10283 static MA_INLINE HRESULT ma_IUnknown_QueryInterface(ma_IUnknown* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
10284 static MA_INLINE ULONG ma_IUnknown_AddRef(ma_IUnknown* pThis) { return pThis->lpVtbl->AddRef(pThis); }
10285 static MA_INLINE ULONG ma_IUnknown_Release(ma_IUnknown* pThis) { return pThis->lpVtbl->Release(pThis); }
10286 
10287 #ifdef MA_WIN32_DESKTOP
10288  /* IMMNotificationClient */
10289  typedef struct
10290  {
10291  /* IUnknown */
10292  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject);
10293  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMNotificationClient* pThis);
10294  ULONG (STDMETHODCALLTYPE * Release) (ma_IMMNotificationClient* pThis);
10295 
10296  /* IMMNotificationClient */
10297  HRESULT (STDMETHODCALLTYPE * OnDeviceStateChanged) (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState);
10298  HRESULT (STDMETHODCALLTYPE * OnDeviceAdded) (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID);
10299  HRESULT (STDMETHODCALLTYPE * OnDeviceRemoved) (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID);
10300  HRESULT (STDMETHODCALLTYPE * OnDefaultDeviceChanged)(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, LPCWSTR pDefaultDeviceID);
10301  HRESULT (STDMETHODCALLTYPE * OnPropertyValueChanged)(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key);
10302  } ma_IMMNotificationClientVtbl;
10303 
10304  /* IMMDeviceEnumerator */
10305  typedef struct
10306  {
10307  /* IUnknown */
10308  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDeviceEnumerator* pThis, const IID* const riid, void** ppObject);
10309  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMDeviceEnumerator* pThis);
10310  ULONG (STDMETHODCALLTYPE * Release) (ma_IMMDeviceEnumerator* pThis);
10311 
10312  /* IMMDeviceEnumerator */
10313  HRESULT (STDMETHODCALLTYPE * EnumAudioEndpoints) (ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, DWORD dwStateMask, ma_IMMDeviceCollection** ppDevices);
10314  HRESULT (STDMETHODCALLTYPE * GetDefaultAudioEndpoint) (ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, ma_ERole role, ma_IMMDevice** ppEndpoint);
10315  HRESULT (STDMETHODCALLTYPE * GetDevice) (ma_IMMDeviceEnumerator* pThis, LPCWSTR pID, ma_IMMDevice** ppDevice);
10316  HRESULT (STDMETHODCALLTYPE * RegisterEndpointNotificationCallback) (ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient);
10317  HRESULT (STDMETHODCALLTYPE * UnregisterEndpointNotificationCallback)(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient);
10318  } ma_IMMDeviceEnumeratorVtbl;
10319  struct ma_IMMDeviceEnumerator
10320  {
10321  ma_IMMDeviceEnumeratorVtbl* lpVtbl;
10322  };
10323  static MA_INLINE HRESULT ma_IMMDeviceEnumerator_QueryInterface(ma_IMMDeviceEnumerator* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
10324  static MA_INLINE ULONG ma_IMMDeviceEnumerator_AddRef(ma_IMMDeviceEnumerator* pThis) { return pThis->lpVtbl->AddRef(pThis); }
10325  static MA_INLINE ULONG ma_IMMDeviceEnumerator_Release(ma_IMMDeviceEnumerator* pThis) { return pThis->lpVtbl->Release(pThis); }
10326  static MA_INLINE HRESULT ma_IMMDeviceEnumerator_EnumAudioEndpoints(ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, DWORD dwStateMask, ma_IMMDeviceCollection** ppDevices) { return pThis->lpVtbl->EnumAudioEndpoints(pThis, dataFlow, dwStateMask, ppDevices); }
10327  static MA_INLINE HRESULT ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, ma_ERole role, ma_IMMDevice** ppEndpoint) { return pThis->lpVtbl->GetDefaultAudioEndpoint(pThis, dataFlow, role, ppEndpoint); }
10328  static MA_INLINE HRESULT ma_IMMDeviceEnumerator_GetDevice(ma_IMMDeviceEnumerator* pThis, LPCWSTR pID, ma_IMMDevice** ppDevice) { return pThis->lpVtbl->GetDevice(pThis, pID, ppDevice); }
10329  static MA_INLINE HRESULT ma_IMMDeviceEnumerator_RegisterEndpointNotificationCallback(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient) { return pThis->lpVtbl->RegisterEndpointNotificationCallback(pThis, pClient); }
10330  static MA_INLINE HRESULT ma_IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient) { return pThis->lpVtbl->UnregisterEndpointNotificationCallback(pThis, pClient); }
10331 
10332 
10333  /* IMMDeviceCollection */
10334  typedef struct
10335  {
10336  /* IUnknown */
10337  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDeviceCollection* pThis, const IID* const riid, void** ppObject);
10338  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMDeviceCollection* pThis);
10339  ULONG (STDMETHODCALLTYPE * Release) (ma_IMMDeviceCollection* pThis);
10340 
10341  /* IMMDeviceCollection */
10342  HRESULT (STDMETHODCALLTYPE * GetCount)(ma_IMMDeviceCollection* pThis, UINT* pDevices);
10343  HRESULT (STDMETHODCALLTYPE * Item) (ma_IMMDeviceCollection* pThis, UINT nDevice, ma_IMMDevice** ppDevice);
10344  } ma_IMMDeviceCollectionVtbl;
10345  struct ma_IMMDeviceCollection
10346  {
10347  ma_IMMDeviceCollectionVtbl* lpVtbl;
10348  };
10349  static MA_INLINE HRESULT ma_IMMDeviceCollection_QueryInterface(ma_IMMDeviceCollection* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
10350  static MA_INLINE ULONG ma_IMMDeviceCollection_AddRef(ma_IMMDeviceCollection* pThis) { return pThis->lpVtbl->AddRef(pThis); }
10351  static MA_INLINE ULONG ma_IMMDeviceCollection_Release(ma_IMMDeviceCollection* pThis) { return pThis->lpVtbl->Release(pThis); }
10352  static MA_INLINE HRESULT ma_IMMDeviceCollection_GetCount(ma_IMMDeviceCollection* pThis, UINT* pDevices) { return pThis->lpVtbl->GetCount(pThis, pDevices); }
10353  static MA_INLINE HRESULT ma_IMMDeviceCollection_Item(ma_IMMDeviceCollection* pThis, UINT nDevice, ma_IMMDevice** ppDevice) { return pThis->lpVtbl->Item(pThis, nDevice, ppDevice); }
10354 
10355 
10356  /* IMMDevice */
10357  typedef struct
10358  {
10359  /* IUnknown */
10360  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDevice* pThis, const IID* const riid, void** ppObject);
10361  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IMMDevice* pThis);
10362  ULONG (STDMETHODCALLTYPE * Release) (ma_IMMDevice* pThis);
10363 
10364  /* IMMDevice */
10365  HRESULT (STDMETHODCALLTYPE * Activate) (ma_IMMDevice* pThis, const IID* const iid, DWORD dwClsCtx, PROPVARIANT* pActivationParams, void** ppInterface);
10366  HRESULT (STDMETHODCALLTYPE * OpenPropertyStore)(ma_IMMDevice* pThis, DWORD stgmAccess, ma_IPropertyStore** ppProperties);
10367  HRESULT (STDMETHODCALLTYPE * GetId) (ma_IMMDevice* pThis, LPWSTR *pID);
10368  HRESULT (STDMETHODCALLTYPE * GetState) (ma_IMMDevice* pThis, DWORD *pState);
10369  } ma_IMMDeviceVtbl;
10370  struct ma_IMMDevice
10371  {
10372  ma_IMMDeviceVtbl* lpVtbl;
10373  };
10374  static MA_INLINE HRESULT ma_IMMDevice_QueryInterface(ma_IMMDevice* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
10375  static MA_INLINE ULONG ma_IMMDevice_AddRef(ma_IMMDevice* pThis) { return pThis->lpVtbl->AddRef(pThis); }
10376  static MA_INLINE ULONG ma_IMMDevice_Release(ma_IMMDevice* pThis) { return pThis->lpVtbl->Release(pThis); }
10377  static MA_INLINE HRESULT ma_IMMDevice_Activate(ma_IMMDevice* pThis, const IID* const iid, DWORD dwClsCtx, PROPVARIANT* pActivationParams, void** ppInterface) { return pThis->lpVtbl->Activate(pThis, iid, dwClsCtx, pActivationParams, ppInterface); }
10378  static MA_INLINE HRESULT ma_IMMDevice_OpenPropertyStore(ma_IMMDevice* pThis, DWORD stgmAccess, ma_IPropertyStore** ppProperties) { return pThis->lpVtbl->OpenPropertyStore(pThis, stgmAccess, ppProperties); }
10379  static MA_INLINE HRESULT ma_IMMDevice_GetId(ma_IMMDevice* pThis, LPWSTR *pID) { return pThis->lpVtbl->GetId(pThis, pID); }
10380  static MA_INLINE HRESULT ma_IMMDevice_GetState(ma_IMMDevice* pThis, DWORD *pState) { return pThis->lpVtbl->GetState(pThis, pState); }
10381 #else
10382  /* IActivateAudioInterfaceAsyncOperation */
10383  typedef struct
10384  {
10385  /* IUnknown */
10386  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IActivateAudioInterfaceAsyncOperation* pThis, const IID* const riid, void** ppObject);
10387  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IActivateAudioInterfaceAsyncOperation* pThis);
10388  ULONG (STDMETHODCALLTYPE * Release) (ma_IActivateAudioInterfaceAsyncOperation* pThis);
10389 
10390  /* IActivateAudioInterfaceAsyncOperation */
10391  HRESULT (STDMETHODCALLTYPE * GetActivateResult)(ma_IActivateAudioInterfaceAsyncOperation* pThis, HRESULT *pActivateResult, ma_IUnknown** ppActivatedInterface);
10392  } ma_IActivateAudioInterfaceAsyncOperationVtbl;
10393  struct ma_IActivateAudioInterfaceAsyncOperation
10394  {
10395  ma_IActivateAudioInterfaceAsyncOperationVtbl* lpVtbl;
10396  };
10397  static MA_INLINE HRESULT ma_IActivateAudioInterfaceAsyncOperation_QueryInterface(ma_IActivateAudioInterfaceAsyncOperation* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
10398  static MA_INLINE ULONG ma_IActivateAudioInterfaceAsyncOperation_AddRef(ma_IActivateAudioInterfaceAsyncOperation* pThis) { return pThis->lpVtbl->AddRef(pThis); }
10399  static MA_INLINE ULONG ma_IActivateAudioInterfaceAsyncOperation_Release(ma_IActivateAudioInterfaceAsyncOperation* pThis) { return pThis->lpVtbl->Release(pThis); }
10400  static MA_INLINE HRESULT ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(ma_IActivateAudioInterfaceAsyncOperation* pThis, HRESULT *pActivateResult, ma_IUnknown** ppActivatedInterface) { return pThis->lpVtbl->GetActivateResult(pThis, pActivateResult, ppActivatedInterface); }
10401 #endif
10402 
10403 /* IPropertyStore */
10404 typedef struct
10405 {
10406  /* IUnknown */
10407  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IPropertyStore* pThis, const IID* const riid, void** ppObject);
10408  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IPropertyStore* pThis);
10409  ULONG (STDMETHODCALLTYPE * Release) (ma_IPropertyStore* pThis);
10410 
10411  /* IPropertyStore */
10412  HRESULT (STDMETHODCALLTYPE * GetCount)(ma_IPropertyStore* pThis, DWORD* pPropCount);
10413  HRESULT (STDMETHODCALLTYPE * GetAt) (ma_IPropertyStore* pThis, DWORD propIndex, PROPERTYKEY* pPropKey);
10414  HRESULT (STDMETHODCALLTYPE * GetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, PROPVARIANT* pPropVar);
10415  HRESULT (STDMETHODCALLTYPE * SetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, const PROPVARIANT* const pPropVar);
10416  HRESULT (STDMETHODCALLTYPE * Commit) (ma_IPropertyStore* pThis);
10417 } ma_IPropertyStoreVtbl;
10418 struct ma_IPropertyStore
10419 {
10420  ma_IPropertyStoreVtbl* lpVtbl;
10421 };
10422 static MA_INLINE HRESULT ma_IPropertyStore_QueryInterface(ma_IPropertyStore* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
10423 static MA_INLINE ULONG ma_IPropertyStore_AddRef(ma_IPropertyStore* pThis) { return pThis->lpVtbl->AddRef(pThis); }
10424 static MA_INLINE ULONG ma_IPropertyStore_Release(ma_IPropertyStore* pThis) { return pThis->lpVtbl->Release(pThis); }
10425 static MA_INLINE HRESULT ma_IPropertyStore_GetCount(ma_IPropertyStore* pThis, DWORD* pPropCount) { return pThis->lpVtbl->GetCount(pThis, pPropCount); }
10426 static MA_INLINE HRESULT ma_IPropertyStore_GetAt(ma_IPropertyStore* pThis, DWORD propIndex, PROPERTYKEY* pPropKey) { return pThis->lpVtbl->GetAt(pThis, propIndex, pPropKey); }
10427 static MA_INLINE HRESULT ma_IPropertyStore_GetValue(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, PROPVARIANT* pPropVar) { return pThis->lpVtbl->GetValue(pThis, pKey, pPropVar); }
10428 static MA_INLINE HRESULT ma_IPropertyStore_SetValue(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, const PROPVARIANT* const pPropVar) { return pThis->lpVtbl->SetValue(pThis, pKey, pPropVar); }
10429 static MA_INLINE HRESULT ma_IPropertyStore_Commit(ma_IPropertyStore* pThis) { return pThis->lpVtbl->Commit(pThis); }
10430 
10431 
10432 /* IAudioClient */
10433 typedef struct
10434 {
10435  /* IUnknown */
10436  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient* pThis, const IID* const riid, void** ppObject);
10437  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioClient* pThis);
10438  ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioClient* pThis);
10439 
10440  /* IAudioClient */
10441  HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid);
10442  HRESULT (STDMETHODCALLTYPE * GetBufferSize) (ma_IAudioClient* pThis, ma_uint32* pNumBufferFrames);
10443  HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient* pThis, MA_REFERENCE_TIME* pLatency);
10444  HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient* pThis, ma_uint32* pNumPaddingFrames);
10445  HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch);
10446  HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient* pThis, WAVEFORMATEX** ppDeviceFormat);
10447  HRESULT (STDMETHODCALLTYPE * GetDevicePeriod) (ma_IAudioClient* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod);
10448  HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient* pThis);
10449  HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient* pThis);
10450  HRESULT (STDMETHODCALLTYPE * Reset) (ma_IAudioClient* pThis);
10451  HRESULT (STDMETHODCALLTYPE * SetEventHandle) (ma_IAudioClient* pThis, HANDLE eventHandle);
10452  HRESULT (STDMETHODCALLTYPE * GetService) (ma_IAudioClient* pThis, const IID* const riid, void** pp);
10453 } ma_IAudioClientVtbl;
10454 struct ma_IAudioClient
10455 {
10456  ma_IAudioClientVtbl* lpVtbl;
10457 };
10458 static MA_INLINE HRESULT ma_IAudioClient_QueryInterface(ma_IAudioClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
10459 static MA_INLINE ULONG ma_IAudioClient_AddRef(ma_IAudioClient* pThis) { return pThis->lpVtbl->AddRef(pThis); }
10460 static MA_INLINE ULONG ma_IAudioClient_Release(ma_IAudioClient* pThis) { return pThis->lpVtbl->Release(pThis); }
10461 static MA_INLINE HRESULT ma_IAudioClient_Initialize(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); }
10462 static MA_INLINE HRESULT ma_IAudioClient_GetBufferSize(ma_IAudioClient* pThis, ma_uint32* pNumBufferFrames) { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); }
10463 static MA_INLINE HRESULT ma_IAudioClient_GetStreamLatency(ma_IAudioClient* pThis, MA_REFERENCE_TIME* pLatency) { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); }
10464 static MA_INLINE HRESULT ma_IAudioClient_GetCurrentPadding(ma_IAudioClient* pThis, ma_uint32* pNumPaddingFrames) { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); }
10465 static MA_INLINE HRESULT ma_IAudioClient_IsFormatSupported(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); }
10466 static MA_INLINE HRESULT ma_IAudioClient_GetMixFormat(ma_IAudioClient* pThis, WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); }
10467 static MA_INLINE HRESULT ma_IAudioClient_GetDevicePeriod(ma_IAudioClient* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod) { return pThis->lpVtbl->GetDevicePeriod(pThis, pDefaultDevicePeriod, pMinimumDevicePeriod); }
10468 static MA_INLINE HRESULT ma_IAudioClient_Start(ma_IAudioClient* pThis) { return pThis->lpVtbl->Start(pThis); }
10469 static MA_INLINE HRESULT ma_IAudioClient_Stop(ma_IAudioClient* pThis) { return pThis->lpVtbl->Stop(pThis); }
10470 static MA_INLINE HRESULT ma_IAudioClient_Reset(ma_IAudioClient* pThis) { return pThis->lpVtbl->Reset(pThis); }
10471 static MA_INLINE HRESULT ma_IAudioClient_SetEventHandle(ma_IAudioClient* pThis, HANDLE eventHandle) { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); }
10472 static MA_INLINE HRESULT ma_IAudioClient_GetService(ma_IAudioClient* pThis, const IID* const riid, void** pp) { return pThis->lpVtbl->GetService(pThis, riid, pp); }
10473 
10474 /* IAudioClient2 */
10475 typedef struct
10476 {
10477  /* IUnknown */
10478  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient2* pThis, const IID* const riid, void** ppObject);
10479  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioClient2* pThis);
10480  ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioClient2* pThis);
10481 
10482  /* IAudioClient */
10483  HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid);
10484  HRESULT (STDMETHODCALLTYPE * GetBufferSize) (ma_IAudioClient2* pThis, ma_uint32* pNumBufferFrames);
10485  HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pLatency);
10486  HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient2* pThis, ma_uint32* pNumPaddingFrames);
10487  HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch);
10488  HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient2* pThis, WAVEFORMATEX** ppDeviceFormat);
10489  HRESULT (STDMETHODCALLTYPE * GetDevicePeriod) (ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod);
10490  HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient2* pThis);
10491  HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient2* pThis);
10492  HRESULT (STDMETHODCALLTYPE * Reset) (ma_IAudioClient2* pThis);
10493  HRESULT (STDMETHODCALLTYPE * SetEventHandle) (ma_IAudioClient2* pThis, HANDLE eventHandle);
10494  HRESULT (STDMETHODCALLTYPE * GetService) (ma_IAudioClient2* pThis, const IID* const riid, void** pp);
10495 
10496  /* IAudioClient2 */
10497  HRESULT (STDMETHODCALLTYPE * IsOffloadCapable) (ma_IAudioClient2* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable);
10498  HRESULT (STDMETHODCALLTYPE * SetClientProperties)(ma_IAudioClient2* pThis, const ma_AudioClientProperties* pProperties);
10499  HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient2* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration);
10500 } ma_IAudioClient2Vtbl;
10501 struct ma_IAudioClient2
10502 {
10503  ma_IAudioClient2Vtbl* lpVtbl;
10504 };
10505 static MA_INLINE HRESULT ma_IAudioClient2_QueryInterface(ma_IAudioClient2* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
10506 static MA_INLINE ULONG ma_IAudioClient2_AddRef(ma_IAudioClient2* pThis) { return pThis->lpVtbl->AddRef(pThis); }
10507 static MA_INLINE ULONG ma_IAudioClient2_Release(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Release(pThis); }
10508 static MA_INLINE HRESULT ma_IAudioClient2_Initialize(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); }
10509 static MA_INLINE HRESULT ma_IAudioClient2_GetBufferSize(ma_IAudioClient2* pThis, ma_uint32* pNumBufferFrames) { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); }
10510 static MA_INLINE HRESULT ma_IAudioClient2_GetStreamLatency(ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pLatency) { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); }
10511 static MA_INLINE HRESULT ma_IAudioClient2_GetCurrentPadding(ma_IAudioClient2* pThis, ma_uint32* pNumPaddingFrames) { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); }
10512 static MA_INLINE HRESULT ma_IAudioClient2_IsFormatSupported(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); }
10513 static MA_INLINE HRESULT ma_IAudioClient2_GetMixFormat(ma_IAudioClient2* pThis, WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); }
10514 static MA_INLINE HRESULT ma_IAudioClient2_GetDevicePeriod(ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod) { return pThis->lpVtbl->GetDevicePeriod(pThis, pDefaultDevicePeriod, pMinimumDevicePeriod); }
10515 static MA_INLINE HRESULT ma_IAudioClient2_Start(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Start(pThis); }
10516 static MA_INLINE HRESULT ma_IAudioClient2_Stop(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Stop(pThis); }
10517 static MA_INLINE HRESULT ma_IAudioClient2_Reset(ma_IAudioClient2* pThis) { return pThis->lpVtbl->Reset(pThis); }
10518 static MA_INLINE HRESULT ma_IAudioClient2_SetEventHandle(ma_IAudioClient2* pThis, HANDLE eventHandle) { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); }
10519 static MA_INLINE HRESULT ma_IAudioClient2_GetService(ma_IAudioClient2* pThis, const IID* const riid, void** pp) { return pThis->lpVtbl->GetService(pThis, riid, pp); }
10520 static MA_INLINE HRESULT ma_IAudioClient2_IsOffloadCapable(ma_IAudioClient2* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable) { return pThis->lpVtbl->IsOffloadCapable(pThis, category, pOffloadCapable); }
10521 static MA_INLINE HRESULT ma_IAudioClient2_SetClientProperties(ma_IAudioClient2* pThis, const ma_AudioClientProperties* pProperties) { return pThis->lpVtbl->SetClientProperties(pThis, pProperties); }
10522 static MA_INLINE HRESULT ma_IAudioClient2_GetBufferSizeLimits(ma_IAudioClient2* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration) { return pThis->lpVtbl->GetBufferSizeLimits(pThis, pFormat, eventDriven, pMinBufferDuration, pMaxBufferDuration); }
10523 
10524 
10525 /* IAudioClient3 */
10526 typedef struct
10527 {
10528  /* IUnknown */
10529  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient3* pThis, const IID* const riid, void** ppObject);
10530  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioClient3* pThis);
10531  ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioClient3* pThis);
10532 
10533  /* IAudioClient */
10534  HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid);
10535  HRESULT (STDMETHODCALLTYPE * GetBufferSize) (ma_IAudioClient3* pThis, ma_uint32* pNumBufferFrames);
10536  HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pLatency);
10537  HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient3* pThis, ma_uint32* pNumPaddingFrames);
10538  HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch);
10539  HRESULT (STDMETHODCALLTYPE * GetMixFormat) (ma_IAudioClient3* pThis, WAVEFORMATEX** ppDeviceFormat);
10540  HRESULT (STDMETHODCALLTYPE * GetDevicePeriod) (ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod);
10541  HRESULT (STDMETHODCALLTYPE * Start) (ma_IAudioClient3* pThis);
10542  HRESULT (STDMETHODCALLTYPE * Stop) (ma_IAudioClient3* pThis);
10543  HRESULT (STDMETHODCALLTYPE * Reset) (ma_IAudioClient3* pThis);
10544  HRESULT (STDMETHODCALLTYPE * SetEventHandle) (ma_IAudioClient3* pThis, HANDLE eventHandle);
10545  HRESULT (STDMETHODCALLTYPE * GetService) (ma_IAudioClient3* pThis, const IID* const riid, void** pp);
10546 
10547  /* IAudioClient2 */
10548  HRESULT (STDMETHODCALLTYPE * IsOffloadCapable) (ma_IAudioClient3* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable);
10549  HRESULT (STDMETHODCALLTYPE * SetClientProperties)(ma_IAudioClient3* pThis, const ma_AudioClientProperties* pProperties);
10550  HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration);
10551 
10552  /* IAudioClient3 */
10553  HRESULT (STDMETHODCALLTYPE * GetSharedModeEnginePeriod) (ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, UINT32* pDefaultPeriodInFrames, UINT32* pFundamentalPeriodInFrames, UINT32* pMinPeriodInFrames, UINT32* pMaxPeriodInFrames);
10554  HRESULT (STDMETHODCALLTYPE * GetCurrentSharedModeEnginePeriod)(ma_IAudioClient3* pThis, WAVEFORMATEX** ppFormat, UINT32* pCurrentPeriodInFrames);
10555  HRESULT (STDMETHODCALLTYPE * InitializeSharedAudioStream) (ma_IAudioClient3* pThis, DWORD streamFlags, UINT32 periodInFrames, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid);
10556 } ma_IAudioClient3Vtbl;
10557 struct ma_IAudioClient3
10558 {
10559  ma_IAudioClient3Vtbl* lpVtbl;
10560 };
10561 static MA_INLINE HRESULT ma_IAudioClient3_QueryInterface(ma_IAudioClient3* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
10562 static MA_INLINE ULONG ma_IAudioClient3_AddRef(ma_IAudioClient3* pThis) { return pThis->lpVtbl->AddRef(pThis); }
10563 static MA_INLINE ULONG ma_IAudioClient3_Release(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Release(pThis); }
10564 static MA_INLINE HRESULT ma_IAudioClient3_Initialize(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, DWORD streamFlags, MA_REFERENCE_TIME bufferDuration, MA_REFERENCE_TIME periodicity, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid) { return pThis->lpVtbl->Initialize(pThis, shareMode, streamFlags, bufferDuration, periodicity, pFormat, pAudioSessionGuid); }
10565 static MA_INLINE HRESULT ma_IAudioClient3_GetBufferSize(ma_IAudioClient3* pThis, ma_uint32* pNumBufferFrames) { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); }
10566 static MA_INLINE HRESULT ma_IAudioClient3_GetStreamLatency(ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pLatency) { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); }
10567 static MA_INLINE HRESULT ma_IAudioClient3_GetCurrentPadding(ma_IAudioClient3* pThis, ma_uint32* pNumPaddingFrames) { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); }
10568 static MA_INLINE HRESULT ma_IAudioClient3_IsFormatSupported(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch) { return pThis->lpVtbl->IsFormatSupported(pThis, shareMode, pFormat, ppClosestMatch); }
10569 static MA_INLINE HRESULT ma_IAudioClient3_GetMixFormat(ma_IAudioClient3* pThis, WAVEFORMATEX** ppDeviceFormat) { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); }
10570 static MA_INLINE HRESULT ma_IAudioClient3_GetDevicePeriod(ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod) { return pThis->lpVtbl->GetDevicePeriod(pThis, pDefaultDevicePeriod, pMinimumDevicePeriod); }
10571 static MA_INLINE HRESULT ma_IAudioClient3_Start(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Start(pThis); }
10572 static MA_INLINE HRESULT ma_IAudioClient3_Stop(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Stop(pThis); }
10573 static MA_INLINE HRESULT ma_IAudioClient3_Reset(ma_IAudioClient3* pThis) { return pThis->lpVtbl->Reset(pThis); }
10574 static MA_INLINE HRESULT ma_IAudioClient3_SetEventHandle(ma_IAudioClient3* pThis, HANDLE eventHandle) { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); }
10575 static MA_INLINE HRESULT ma_IAudioClient3_GetService(ma_IAudioClient3* pThis, const IID* const riid, void** pp) { return pThis->lpVtbl->GetService(pThis, riid, pp); }
10576 static MA_INLINE HRESULT ma_IAudioClient3_IsOffloadCapable(ma_IAudioClient3* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable) { return pThis->lpVtbl->IsOffloadCapable(pThis, category, pOffloadCapable); }
10577 static MA_INLINE HRESULT ma_IAudioClient3_SetClientProperties(ma_IAudioClient3* pThis, const ma_AudioClientProperties* pProperties) { return pThis->lpVtbl->SetClientProperties(pThis, pProperties); }
10578 static MA_INLINE HRESULT ma_IAudioClient3_GetBufferSizeLimits(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration) { return pThis->lpVtbl->GetBufferSizeLimits(pThis, pFormat, eventDriven, pMinBufferDuration, pMaxBufferDuration); }
10579 static MA_INLINE HRESULT ma_IAudioClient3_GetSharedModeEnginePeriod(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, UINT32* pDefaultPeriodInFrames, UINT32* pFundamentalPeriodInFrames, UINT32* pMinPeriodInFrames, UINT32* pMaxPeriodInFrames) { return pThis->lpVtbl->GetSharedModeEnginePeriod(pThis, pFormat, pDefaultPeriodInFrames, pFundamentalPeriodInFrames, pMinPeriodInFrames, pMaxPeriodInFrames); }
10580 static MA_INLINE HRESULT ma_IAudioClient3_GetCurrentSharedModeEnginePeriod(ma_IAudioClient3* pThis, WAVEFORMATEX** ppFormat, UINT32* pCurrentPeriodInFrames) { return pThis->lpVtbl->GetCurrentSharedModeEnginePeriod(pThis, ppFormat, pCurrentPeriodInFrames); }
10581 static MA_INLINE HRESULT ma_IAudioClient3_InitializeSharedAudioStream(ma_IAudioClient3* pThis, DWORD streamFlags, UINT32 periodInFrames, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGUID) { return pThis->lpVtbl->InitializeSharedAudioStream(pThis, streamFlags, periodInFrames, pFormat, pAudioSessionGUID); }
10582 
10583 
10584 /* IAudioRenderClient */
10585 typedef struct
10586 {
10587  /* IUnknown */
10588  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioRenderClient* pThis, const IID* const riid, void** ppObject);
10589  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioRenderClient* pThis);
10590  ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioRenderClient* pThis);
10591 
10592  /* IAudioRenderClient */
10593  HRESULT (STDMETHODCALLTYPE * GetBuffer) (ma_IAudioRenderClient* pThis, ma_uint32 numFramesRequested, BYTE** ppData);
10594  HRESULT (STDMETHODCALLTYPE * ReleaseBuffer)(ma_IAudioRenderClient* pThis, ma_uint32 numFramesWritten, DWORD dwFlags);
10595 } ma_IAudioRenderClientVtbl;
10596 struct ma_IAudioRenderClient
10597 {
10598  ma_IAudioRenderClientVtbl* lpVtbl;
10599 };
10600 static MA_INLINE HRESULT ma_IAudioRenderClient_QueryInterface(ma_IAudioRenderClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
10601 static MA_INLINE ULONG ma_IAudioRenderClient_AddRef(ma_IAudioRenderClient* pThis) { return pThis->lpVtbl->AddRef(pThis); }
10602 static MA_INLINE ULONG ma_IAudioRenderClient_Release(ma_IAudioRenderClient* pThis) { return pThis->lpVtbl->Release(pThis); }
10603 static MA_INLINE HRESULT ma_IAudioRenderClient_GetBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesRequested, BYTE** ppData) { return pThis->lpVtbl->GetBuffer(pThis, numFramesRequested, ppData); }
10604 static MA_INLINE HRESULT ma_IAudioRenderClient_ReleaseBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesWritten, DWORD dwFlags) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesWritten, dwFlags); }
10605 
10606 
10607 /* IAudioCaptureClient */
10608 typedef struct
10609 {
10610  /* IUnknown */
10611  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject);
10612  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioCaptureClient* pThis);
10613  ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioCaptureClient* pThis);
10614 
10615  /* IAudioRenderClient */
10616  HRESULT (STDMETHODCALLTYPE * GetBuffer) (ma_IAudioCaptureClient* pThis, BYTE** ppData, ma_uint32* pNumFramesToRead, DWORD* pFlags, ma_uint64* pDevicePosition, ma_uint64* pQPCPosition);
10617  HRESULT (STDMETHODCALLTYPE * ReleaseBuffer) (ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead);
10618  HRESULT (STDMETHODCALLTYPE * GetNextPacketSize)(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket);
10619 } ma_IAudioCaptureClientVtbl;
10620 struct ma_IAudioCaptureClient
10621 {
10622  ma_IAudioCaptureClientVtbl* lpVtbl;
10623 };
10624 static MA_INLINE HRESULT ma_IAudioCaptureClient_QueryInterface(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
10625 static MA_INLINE ULONG ma_IAudioCaptureClient_AddRef(ma_IAudioCaptureClient* pThis) { return pThis->lpVtbl->AddRef(pThis); }
10626 static MA_INLINE ULONG ma_IAudioCaptureClient_Release(ma_IAudioCaptureClient* pThis) { return pThis->lpVtbl->Release(pThis); }
10627 static MA_INLINE HRESULT ma_IAudioCaptureClient_GetBuffer(ma_IAudioCaptureClient* pThis, BYTE** ppData, ma_uint32* pNumFramesToRead, DWORD* pFlags, ma_uint64* pDevicePosition, ma_uint64* pQPCPosition) { return pThis->lpVtbl->GetBuffer(pThis, ppData, pNumFramesToRead, pFlags, pDevicePosition, pQPCPosition); }
10628 static MA_INLINE HRESULT ma_IAudioCaptureClient_ReleaseBuffer(ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesRead); }
10629 static MA_INLINE HRESULT ma_IAudioCaptureClient_GetNextPacketSize(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket) { return pThis->lpVtbl->GetNextPacketSize(pThis, pNumFramesInNextPacket); }
10630 
10631 #ifndef MA_WIN32_DESKTOP
10632 #include <mmdeviceapi.h>
10633 typedef struct ma_completion_handler_uwp ma_completion_handler_uwp;
10634 
10635 typedef struct
10636 {
10637  /* IUnknown */
10638  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject);
10639  ULONG (STDMETHODCALLTYPE * AddRef) (ma_completion_handler_uwp* pThis);
10640  ULONG (STDMETHODCALLTYPE * Release) (ma_completion_handler_uwp* pThis);
10641 
10642  /* IActivateAudioInterfaceCompletionHandler */
10643  HRESULT (STDMETHODCALLTYPE * ActivateCompleted)(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation);
10644 } ma_completion_handler_uwp_vtbl;
10645 struct ma_completion_handler_uwp
10646 {
10647  ma_completion_handler_uwp_vtbl* lpVtbl;
10648  ma_uint32 counter;
10649  HANDLE hEvent;
10650 };
10651 
10652 static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_QueryInterface(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject)
10653 {
10654  /*
10655  We need to "implement" IAgileObject which is just an indicator that's used internally by WASAPI for some multithreading management. To
10656  "implement" this, we just make sure we return pThis when the IAgileObject is requested.
10657  */
10658  if (!ma_is_guid_equal(riid, &MA_IID_IUnknown) && !ma_is_guid_equal(riid, &MA_IID_IActivateAudioInterfaceCompletionHandler) && !ma_is_guid_equal(riid, &MA_IID_IAgileObject)) {
10659  *ppObject = NULL;
10660  return E_NOINTERFACE;
10661  }
10662 
10663  /* Getting here means the IID is IUnknown or IMMNotificationClient. */
10664  *ppObject = (void*)pThis;
10665  ((ma_completion_handler_uwp_vtbl*)pThis->lpVtbl)->AddRef(pThis);
10666  return S_OK;
10667 }
10668 
10669 static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_AddRef(ma_completion_handler_uwp* pThis)
10670 {
10671  return (ULONG)ma_atomic_increment_32(&pThis->counter);
10672 }
10673 
10674 static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_Release(ma_completion_handler_uwp* pThis)
10675 {
10676  ma_uint32 newRefCount = ma_atomic_decrement_32(&pThis->counter);
10677  if (newRefCount == 0) {
10678  return 0; /* We don't free anything here because we never allocate the object on the heap. */
10679  }
10680 
10681  return (ULONG)newRefCount;
10682 }
10683 
10684 static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_ActivateCompleted(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation)
10685 {
10686  (void)pActivateOperation;
10687  SetEvent(pThis->hEvent);
10688  return S_OK;
10689 }
10690 
10691 
10692 static ma_completion_handler_uwp_vtbl g_maCompletionHandlerVtblInstance = {
10693  ma_completion_handler_uwp_QueryInterface,
10694  ma_completion_handler_uwp_AddRef,
10695  ma_completion_handler_uwp_Release,
10696  ma_completion_handler_uwp_ActivateCompleted
10697 };
10698 
10699 static ma_result ma_completion_handler_uwp_init(ma_completion_handler_uwp* pHandler)
10700 {
10701  MA_ASSERT(pHandler != NULL);
10702  MA_ZERO_OBJECT(pHandler);
10703 
10704  pHandler->lpVtbl = &g_maCompletionHandlerVtblInstance;
10705  pHandler->counter = 1;
10706  pHandler->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
10707  if (pHandler->hEvent == NULL) {
10708  return ma_result_from_GetLastError(GetLastError());
10709  }
10710 
10711  return MA_SUCCESS;
10712 }
10713 
10714 static void ma_completion_handler_uwp_uninit(ma_completion_handler_uwp* pHandler)
10715 {
10716  if (pHandler->hEvent != NULL) {
10717  CloseHandle(pHandler->hEvent);
10718  }
10719 }
10720 
10721 static void ma_completion_handler_uwp_wait(ma_completion_handler_uwp* pHandler)
10722 {
10723  WaitForSingleObject(pHandler->hEvent, INFINITE);
10724 }
10725 #endif /* !MA_WIN32_DESKTOP */
10726 
10727 /* We need a virtual table for our notification client object that's used for detecting changes to the default device. */
10728 #ifdef MA_WIN32_DESKTOP
10729 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_QueryInterface(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject)
10730 {
10731  /*
10732  We care about two interfaces - IUnknown and IMMNotificationClient. If the requested IID is something else
10733  we just return E_NOINTERFACE. Otherwise we need to increment the reference counter and return S_OK.
10734  */
10735  if (!ma_is_guid_equal(riid, &MA_IID_IUnknown) && !ma_is_guid_equal(riid, &MA_IID_IMMNotificationClient)) {
10736  *ppObject = NULL;
10737  return E_NOINTERFACE;
10738  }
10739 
10740  /* Getting here means the IID is IUnknown or IMMNotificationClient. */
10741  *ppObject = (void*)pThis;
10742  ((ma_IMMNotificationClientVtbl*)pThis->lpVtbl)->AddRef(pThis);
10743  return S_OK;
10744 }
10745 
10746 static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_AddRef(ma_IMMNotificationClient* pThis)
10747 {
10748  return (ULONG)ma_atomic_increment_32(&pThis->counter);
10749 }
10750 
10751 static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_Release(ma_IMMNotificationClient* pThis)
10752 {
10753  ma_uint32 newRefCount = ma_atomic_decrement_32(&pThis->counter);
10754  if (newRefCount == 0) {
10755  return 0; /* We don't free anything here because we never allocate the object on the heap. */
10756  }
10757 
10758  return (ULONG)newRefCount;
10759 }
10760 
10761 
10762 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState)
10763 {
10764 #ifdef MA_DEBUG_OUTPUT
10765  printf("IMMNotificationClient_OnDeviceStateChanged(pDeviceID=%S, dwNewState=%u)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)", (unsigned int)dwNewState);
10766 #endif
10767 
10768  (void)pThis;
10769  (void)pDeviceID;
10770  (void)dwNewState;
10771  return S_OK;
10772 }
10773 
10774 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceAdded(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
10775 {
10776 #ifdef MA_DEBUG_OUTPUT
10777  printf("IMMNotificationClient_OnDeviceAdded(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");
10778 #endif
10779 
10780  /* We don't need to worry about this event for our purposes. */
10781  (void)pThis;
10782  (void)pDeviceID;
10783  return S_OK;
10784 }
10785 
10786 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceRemoved(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
10787 {
10788 #ifdef MA_DEBUG_OUTPUT
10789  printf("IMMNotificationClient_OnDeviceRemoved(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");
10790 #endif
10791 
10792  /* We don't need to worry about this event for our purposes. */
10793  (void)pThis;
10794  (void)pDeviceID;
10795  return S_OK;
10796 }
10797 
10798 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, LPCWSTR pDefaultDeviceID)
10799 {
10800 #ifdef MA_DEBUG_OUTPUT
10801  printf("IMMNotificationClient_OnDefaultDeviceChanged(dataFlow=%d, role=%d, pDefaultDeviceID=%S)\n", dataFlow, role, (pDefaultDeviceID != NULL) ? pDefaultDeviceID : L"(NULL)");
10802 #endif
10803 
10804  /* We only ever use the eConsole role in miniaudio. */
10805  if (role != ma_eConsole) {
10806  return S_OK;
10807  }
10808 
10809  /* We only care about devices with the same data flow and role as the current device. */
10810  if ((pThis->pDevice->type == ma_device_type_playback && dataFlow != ma_eRender) ||
10811  (pThis->pDevice->type == ma_device_type_capture && dataFlow != ma_eCapture)) {
10812  return S_OK;
10813  }
10814 
10815  /* Don't do automatic stream routing if we're not allowed. */
10816  if ((dataFlow == ma_eRender && pThis->pDevice->wasapi.allowPlaybackAutoStreamRouting == MA_FALSE) ||
10817  (dataFlow == ma_eCapture && pThis->pDevice->wasapi.allowCaptureAutoStreamRouting == MA_FALSE)) {
10818  return S_OK;
10819  }
10820 
10821  /*
10822  Not currently supporting automatic stream routing in exclusive mode. This is not working correctly on my machine due to
10823  AUDCLNT_E_DEVICE_IN_USE errors when reinitializing the device. If this is a bug in miniaudio, we can try re-enabling this once
10824  it's fixed.
10825  */
10826  if ((dataFlow == ma_eRender && pThis->pDevice->playback.shareMode == ma_share_mode_exclusive) ||
10827  (dataFlow == ma_eCapture && pThis->pDevice->capture.shareMode == ma_share_mode_exclusive)) {
10828  return S_OK;
10829  }
10830 
10831  /*
10832  We don't change the device here - we change it in the worker thread to keep synchronization simple. To do this I'm just setting a flag to
10833  indicate that the default device has changed. Loopback devices are treated as capture devices so we need to do a bit of a dance to handle
10834  that properly.
10835  */
10836  if (dataFlow == ma_eRender && pThis->pDevice->type != ma_device_type_loopback) {
10837  ma_atomic_exchange_32(&pThis->pDevice->wasapi.hasDefaultPlaybackDeviceChanged, MA_TRUE);
10838  }
10839  if (dataFlow == ma_eCapture || pThis->pDevice->type == ma_device_type_loopback) {
10840  ma_atomic_exchange_32(&pThis->pDevice->wasapi.hasDefaultCaptureDeviceChanged, MA_TRUE);
10841  }
10842 
10843  (void)pDefaultDeviceID;
10844  return S_OK;
10845 }
10846 
10847 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnPropertyValueChanged(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key)
10848 {
10849 #ifdef MA_DEBUG_OUTPUT
10850  printf("IMMNotificationClient_OnPropertyValueChanged(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");
10851 #endif
10852 
10853  (void)pThis;
10854  (void)pDeviceID;
10855  (void)key;
10856  return S_OK;
10857 }
10858 
10859 static ma_IMMNotificationClientVtbl g_maNotificationCientVtbl = {
10860  ma_IMMNotificationClient_QueryInterface,
10861  ma_IMMNotificationClient_AddRef,
10862  ma_IMMNotificationClient_Release,
10863  ma_IMMNotificationClient_OnDeviceStateChanged,
10864  ma_IMMNotificationClient_OnDeviceAdded,
10865  ma_IMMNotificationClient_OnDeviceRemoved,
10866  ma_IMMNotificationClient_OnDefaultDeviceChanged,
10867  ma_IMMNotificationClient_OnPropertyValueChanged
10868 };
10869 #endif /* MA_WIN32_DESKTOP */
10870 
10871 #ifdef MA_WIN32_DESKTOP
10872 typedef ma_IMMDevice ma_WASAPIDeviceInterface;
10873 #else
10874 typedef ma_IUnknown ma_WASAPIDeviceInterface;
10875 #endif
10876 
10877 
10878 
10879 static ma_bool32 ma_context_is_device_id_equal__wasapi(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
10880 {
10881  MA_ASSERT(pContext != NULL);
10882  MA_ASSERT(pID0 != NULL);
10883  MA_ASSERT(pID1 != NULL);
10884  (void)pContext;
10885 
10886  return memcmp(pID0->wasapi, pID1->wasapi, sizeof(pID0->wasapi)) == 0;
10887 }
10888 
10889 static void ma_set_device_info_from_WAVEFORMATEX(const WAVEFORMATEX* pWF, ma_device_info* pInfo)
10890 {
10891  MA_ASSERT(pWF != NULL);
10892  MA_ASSERT(pInfo != NULL);
10893 
10894  pInfo->formatCount = 1;
10895  pInfo->formats[0] = ma_format_from_WAVEFORMATEX(pWF);
10896  pInfo->minChannels = pWF->nChannels;
10897  pInfo->maxChannels = pWF->nChannels;
10898  pInfo->minSampleRate = pWF->nSamplesPerSec;
10899  pInfo->maxSampleRate = pWF->nSamplesPerSec;
10900 }
10901 
10902 static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context* pContext, /*ma_IMMDevice**/void* pMMDevice, ma_IAudioClient* pAudioClient, ma_share_mode shareMode, ma_device_info* pInfo)
10903 {
10904  MA_ASSERT(pAudioClient != NULL);
10905  MA_ASSERT(pInfo != NULL);
10906 
10907  /* We use a different technique to retrieve the device information depending on whether or not we are using shared or exclusive mode. */
10908  if (shareMode == ma_share_mode_shared) {
10909  /* Shared Mode. We use GetMixFormat() here. */
10910  WAVEFORMATEX* pWF = NULL;
10911  HRESULT hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pAudioClient, (WAVEFORMATEX**)&pWF);
10912  if (SUCCEEDED(hr)) {
10913  ma_set_device_info_from_WAVEFORMATEX(pWF, pInfo);
10914  return MA_SUCCESS;
10915  } else {
10916  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve mix format for device info retrieval.", ma_result_from_HRESULT(hr));
10917  }
10918  } else {
10919  /* Exlcusive Mode. We repeatedly call IsFormatSupported() here. This is not currently support on UWP. */
10920 #ifdef MA_WIN32_DESKTOP
10921  /*
10922  The first thing to do is get the format from PKEY_AudioEngine_DeviceFormat. This should give us a channel count we assume is
10923  correct which will simplify our searching.
10924  */
10925  ma_IPropertyStore *pProperties;
10926  HRESULT hr = ma_IMMDevice_OpenPropertyStore((ma_IMMDevice*)pMMDevice, STGM_READ, &pProperties);
10927  if (SUCCEEDED(hr)) {
10928  PROPVARIANT var;
10929  ma_PropVariantInit(&var);
10930 
10931  hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_AudioEngine_DeviceFormat, &var);
10932  if (SUCCEEDED(hr)) {
10933  WAVEFORMATEX* pWF = (WAVEFORMATEX*)var.blob.pBlobData;
10934  ma_set_device_info_from_WAVEFORMATEX(pWF, pInfo);
10935 
10936  /*
10937  In my testing, the format returned by PKEY_AudioEngine_DeviceFormat is suitable for exclusive mode so we check this format
10938  first. If this fails, fall back to a search.
10939  */
10940  hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pWF, NULL);
10941  ma_PropVariantClear(pContext, &var);
10942 
10943  if (FAILED(hr)) {
10944  /*
10945  The format returned by PKEY_AudioEngine_DeviceFormat is not supported, so fall back to a search. We assume the channel
10946  count returned by MA_PKEY_AudioEngine_DeviceFormat is valid and correct. For simplicity we're only returning one format.
10947  */
10948  ma_uint32 channels = pInfo->minChannels;
10949  ma_format formatsToSearch[] = {
10950  ma_format_s16,
10951  ma_format_s24,
10952  /*ma_format_s24_32,*/
10953  ma_format_f32,
10954  ma_format_s32,
10955  ma_format_u8
10956  };
10957  ma_channel defaultChannelMap[MA_MAX_CHANNELS];
10958  WAVEFORMATEXTENSIBLE wf;
10959  ma_bool32 found;
10960  ma_uint32 iFormat;
10961 
10962  ma_get_standard_channel_map(ma_standard_channel_map_microsoft, channels, defaultChannelMap);
10963 
10964  MA_ZERO_OBJECT(&wf);
10965  wf.Format.cbSize = sizeof(wf);
10966  wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
10967  wf.Format.nChannels = (WORD)channels;
10968  wf.dwChannelMask = ma_channel_map_to_channel_mask__win32(defaultChannelMap, channels);
10969 
10970  found = MA_FALSE;
10971  for (iFormat = 0; iFormat < ma_countof(formatsToSearch); ++iFormat) {
10972  ma_format format = formatsToSearch[iFormat];
10973  ma_uint32 iSampleRate;
10974 
10975  wf.Format.wBitsPerSample = (WORD)ma_get_bytes_per_sample(format)*8;
10976  wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8;
10977  wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
10978  wf.Samples.wValidBitsPerSample = /*(format == ma_format_s24_32) ? 24 :*/ wf.Format.wBitsPerSample;
10979  if (format == ma_format_f32) {
10980  wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
10981  } else {
10982  wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
10983  }
10984 
10985  for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); ++iSampleRate) {
10986  wf.Format.nSamplesPerSec = g_maStandardSampleRatePriorities[iSampleRate];
10987 
10988  hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wf, NULL);
10989  if (SUCCEEDED(hr)) {
10990  ma_set_device_info_from_WAVEFORMATEX((WAVEFORMATEX*)&wf, pInfo);
10991  found = MA_TRUE;
10992  break;
10993  }
10994  }
10995 
10996  if (found) {
10997  break;
10998  }
10999  }
11000 
11001  if (!found) {
11002  ma_IPropertyStore_Release(pProperties);
11003  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to find suitable device format for device info retrieval.", MA_FORMAT_NOT_SUPPORTED);
11004  }
11005  }
11006  } else {
11007  ma_IPropertyStore_Release(pProperties);
11008  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve device format for device info retrieval.", ma_result_from_HRESULT(hr));
11009  }
11010 
11011  ma_IPropertyStore_Release(pProperties);
11012  } else {
11013  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to open property store for device info retrieval.", ma_result_from_HRESULT(hr));
11014  }
11015 
11016  return MA_SUCCESS;
11017 #else
11018  /* Exclusive mode not fully supported in UWP right now. */
11019  return MA_ERROR;
11020 #endif
11021  }
11022 }
11023 
11024 #ifdef MA_WIN32_DESKTOP
11025 static ma_EDataFlow ma_device_type_to_EDataFlow(ma_device_type deviceType)
11026 {
11027  if (deviceType == ma_device_type_playback) {
11028  return ma_eRender;
11029  } else if (deviceType == ma_device_type_capture) {
11030  return ma_eCapture;
11031  } else {
11033  return ma_eRender; /* Should never hit this. */
11034  }
11035 }
11036 
11037 static ma_result ma_context_create_IMMDeviceEnumerator__wasapi(ma_context* pContext, ma_IMMDeviceEnumerator** ppDeviceEnumerator)
11038 {
11039  HRESULT hr;
11040  ma_IMMDeviceEnumerator* pDeviceEnumerator;
11041 
11042  MA_ASSERT(pContext != NULL);
11043  MA_ASSERT(ppDeviceEnumerator != NULL);
11044 
11045  hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
11046  if (FAILED(hr)) {
11047  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr));
11048  }
11049 
11050  *ppDeviceEnumerator = pDeviceEnumerator;
11051 
11052  return MA_SUCCESS;
11053 }
11054 
11055 static LPWSTR ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(ma_context* pContext, ma_IMMDeviceEnumerator* pDeviceEnumerator, ma_device_type deviceType)
11056 {
11057  HRESULT hr;
11058  ma_IMMDevice* pMMDefaultDevice = NULL;
11059  LPWSTR pDefaultDeviceID = NULL;
11060  ma_EDataFlow dataFlow;
11061  ma_ERole role;
11062 
11063  MA_ASSERT(pContext != NULL);
11064  MA_ASSERT(pDeviceEnumerator != NULL);
11065 
11066  /* Grab the EDataFlow type from the device type. */
11067  dataFlow = ma_device_type_to_EDataFlow(deviceType);
11068 
11069  /* The role is always eConsole, but we may make this configurable later. */
11070  role = ma_eConsole;
11071 
11072  hr = ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator, dataFlow, role, &pMMDefaultDevice);
11073  if (FAILED(hr)) {
11074  return NULL;
11075  }
11076 
11077  hr = ma_IMMDevice_GetId(pMMDefaultDevice, &pDefaultDeviceID);
11078 
11079  ma_IMMDevice_Release(pMMDefaultDevice);
11080  pMMDefaultDevice = NULL;
11081 
11082  if (FAILED(hr)) {
11083  return NULL;
11084  }
11085 
11086  return pDefaultDeviceID;
11087 }
11088 
11089 static LPWSTR ma_context_get_default_device_id__wasapi(ma_context* pContext, ma_device_type deviceType) /* Free the returned pointer with ma_CoTaskMemFree() */
11090 {
11091  ma_result result;
11092  ma_IMMDeviceEnumerator* pDeviceEnumerator;
11093  LPWSTR pDefaultDeviceID = NULL;
11094 
11095  MA_ASSERT(pContext != NULL);
11096 
11097  result = ma_context_create_IMMDeviceEnumerator__wasapi(pContext, &pDeviceEnumerator);
11098  if (result != MA_SUCCESS) {
11099  return NULL;
11100  }
11101 
11102  pDefaultDeviceID = ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(pContext, pDeviceEnumerator, deviceType);
11103 
11104  ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
11105  return pDefaultDeviceID;
11106 }
11107 
11108 static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IMMDevice** ppMMDevice)
11109 {
11110  ma_IMMDeviceEnumerator* pDeviceEnumerator;
11111  HRESULT hr;
11112 
11113  MA_ASSERT(pContext != NULL);
11114  MA_ASSERT(ppMMDevice != NULL);
11115 
11116  hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
11117  if (FAILED(hr)) {
11118  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.", ma_result_from_HRESULT(hr));
11119  }
11120 
11121  if (pDeviceID == NULL) {
11122  hr = ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator, (deviceType == ma_device_type_capture) ? ma_eCapture : ma_eRender, ma_eConsole, ppMMDevice);
11123  } else {
11124  hr = ma_IMMDeviceEnumerator_GetDevice(pDeviceEnumerator, pDeviceID->wasapi, ppMMDevice);
11125  }
11126 
11127  ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
11128  if (FAILED(hr)) {
11129  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve IMMDevice.", ma_result_from_HRESULT(hr));
11130  }
11131 
11132  return MA_SUCCESS;
11133 }
11134 
11135 static ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pContext, ma_IMMDevice* pMMDevice, ma_share_mode shareMode, LPWSTR pDefaultDeviceID, ma_bool32 onlySimpleInfo, ma_device_info* pInfo)
11136 {
11137  LPWSTR pDeviceID;
11138  HRESULT hr;
11139 
11140  MA_ASSERT(pContext != NULL);
11141  MA_ASSERT(pMMDevice != NULL);
11142  MA_ASSERT(pInfo != NULL);
11143 
11144  /* ID. */
11145  hr = ma_IMMDevice_GetId(pMMDevice, &pDeviceID);
11146  if (SUCCEEDED(hr)) {
11147  size_t idlen = wcslen(pDeviceID);
11148  if (idlen+1 > ma_countof(pInfo->id.wasapi)) {
11149  ma_CoTaskMemFree(pContext, pDeviceID);
11150  MA_ASSERT(MA_FALSE); /* NOTE: If this is triggered, please report it. It means the format of the ID must haved change and is too long to fit in our fixed sized buffer. */
11151  return MA_ERROR;
11152  }
11153 
11154  MA_COPY_MEMORY(pInfo->id.wasapi, pDeviceID, idlen * sizeof(wchar_t));
11155  pInfo->id.wasapi[idlen] = '\0';
11156 
11157  if (pDefaultDeviceID != NULL) {
11158  if (wcscmp(pDeviceID, pDefaultDeviceID) == 0) {
11159  /* It's a default device. */
11160  pInfo->_private.isDefault = MA_TRUE;
11161  }
11162  }
11163 
11164  ma_CoTaskMemFree(pContext, pDeviceID);
11165  }
11166 
11167  {
11168  ma_IPropertyStore *pProperties;
11169  hr = ma_IMMDevice_OpenPropertyStore(pMMDevice, STGM_READ, &pProperties);
11170  if (SUCCEEDED(hr)) {
11171  PROPVARIANT var;
11172 
11173  /* Description / Friendly Name */
11174  ma_PropVariantInit(&var);
11175  hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &var);
11176  if (SUCCEEDED(hr)) {
11177  WideCharToMultiByte(CP_UTF8, 0, var.pwszVal, -1, pInfo->name, sizeof(pInfo->name), 0, FALSE);
11178  ma_PropVariantClear(pContext, &var);
11179  }
11180 
11181  ma_IPropertyStore_Release(pProperties);
11182  }
11183  }
11184 
11185  /* Format */
11186  if (!onlySimpleInfo) {
11187  ma_IAudioClient* pAudioClient;
11188  hr = ma_IMMDevice_Activate(pMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);
11189  if (SUCCEEDED(hr)) {
11190  ma_result result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, pMMDevice, pAudioClient, shareMode, pInfo);
11191 
11192  ma_IAudioClient_Release(pAudioClient);
11193  return result;
11194  } else {
11195  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate audio client for device info retrieval.", ma_result_from_HRESULT(hr));
11196  }
11197  }
11198 
11199  return MA_SUCCESS;
11200 }
11201 
11202 static ma_result ma_context_enumerate_devices_by_type__wasapi(ma_context* pContext, ma_IMMDeviceEnumerator* pDeviceEnumerator, ma_device_type deviceType, ma_enum_devices_callback_proc callback, void* pUserData)
11203 {
11204  ma_result result = MA_SUCCESS;
11205  UINT deviceCount;
11206  HRESULT hr;
11207  ma_uint32 iDevice;
11208  LPWSTR pDefaultDeviceID = NULL;
11209  ma_IMMDeviceCollection* pDeviceCollection = NULL;
11210 
11211  MA_ASSERT(pContext != NULL);
11212  MA_ASSERT(callback != NULL);
11213 
11214  /* Grab the default device. We use this to know whether or not flag the returned device info as being the default. */
11215  pDefaultDeviceID = ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(pContext, pDeviceEnumerator, deviceType);
11216 
11217  /* We need to enumerate the devices which returns a device collection. */
11218  hr = ma_IMMDeviceEnumerator_EnumAudioEndpoints(pDeviceEnumerator, ma_device_type_to_EDataFlow(deviceType), MA_MM_DEVICE_STATE_ACTIVE, &pDeviceCollection);
11219  if (SUCCEEDED(hr)) {
11220  hr = ma_IMMDeviceCollection_GetCount(pDeviceCollection, &deviceCount);
11221  if (FAILED(hr)) {
11222  result = ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to get device count.", ma_result_from_HRESULT(hr));
11223  goto done;
11224  }
11225 
11226  for (iDevice = 0; iDevice < deviceCount; ++iDevice) {
11227  ma_device_info deviceInfo;
11228  ma_IMMDevice* pMMDevice;
11229 
11230  MA_ZERO_OBJECT(&deviceInfo);
11231 
11232  hr = ma_IMMDeviceCollection_Item(pDeviceCollection, iDevice, &pMMDevice);
11233  if (SUCCEEDED(hr)) {
11234  result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, ma_share_mode_shared, pDefaultDeviceID, MA_TRUE, &deviceInfo); /* MA_TRUE = onlySimpleInfo. */
11235 
11236  ma_IMMDevice_Release(pMMDevice);
11237  if (result == MA_SUCCESS) {
11238  ma_bool32 cbResult = callback(pContext, deviceType, &deviceInfo, pUserData);
11239  if (cbResult == MA_FALSE) {
11240  break;
11241  }
11242  }
11243  }
11244  }
11245  }
11246 
11247 done:
11248  if (pDefaultDeviceID != NULL) {
11249  ma_CoTaskMemFree(pContext, pDefaultDeviceID);
11250  pDefaultDeviceID = NULL;
11251  }
11252 
11253  if (pDeviceCollection != NULL) {
11254  ma_IMMDeviceCollection_Release(pDeviceCollection);
11255  pDeviceCollection = NULL;
11256  }
11257 
11258  return result;
11259 }
11260 
11261 static ma_result ma_context_get_IAudioClient_Desktop__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IAudioClient** ppAudioClient, ma_IMMDevice** ppMMDevice)
11262 {
11263  ma_result result;
11264  HRESULT hr;
11265 
11266  MA_ASSERT(pContext != NULL);
11267  MA_ASSERT(ppAudioClient != NULL);
11268  MA_ASSERT(ppMMDevice != NULL);
11269 
11270  result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, ppMMDevice);
11271  if (result != MA_SUCCESS) {
11272  return result;
11273  }
11274 
11275  hr = ma_IMMDevice_Activate(*ppMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)ppAudioClient);
11276  if (FAILED(hr)) {
11277  return ma_result_from_HRESULT(hr);
11278  }
11279 
11280  return MA_SUCCESS;
11281 }
11282 #else
11283 static ma_result ma_context_get_IAudioClient_UWP__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IAudioClient** ppAudioClient, ma_IUnknown** ppActivatedInterface)
11284 {
11285  ma_IActivateAudioInterfaceAsyncOperation *pAsyncOp = NULL;
11286  ma_completion_handler_uwp completionHandler;
11287  IID iid;
11288  LPOLESTR iidStr;
11289  HRESULT hr;
11290  ma_result result;
11291  HRESULT activateResult;
11292  ma_IUnknown* pActivatedInterface;
11293 
11294  MA_ASSERT(pContext != NULL);
11295  MA_ASSERT(ppAudioClient != NULL);
11296 
11297  if (pDeviceID != NULL) {
11298  MA_COPY_MEMORY(&iid, pDeviceID->wasapi, sizeof(iid));
11299  } else {
11300  if (deviceType == ma_device_type_playback) {
11301  iid = MA_IID_DEVINTERFACE_AUDIO_RENDER;
11302  } else {
11303  iid = MA_IID_DEVINTERFACE_AUDIO_CAPTURE;
11304  }
11305  }
11306 
11307 #if defined(__cplusplus)
11308  hr = StringFromIID(iid, &iidStr);
11309 #else
11310  hr = StringFromIID(&iid, &iidStr);
11311 #endif
11312  if (FAILED(hr)) {
11313  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.", ma_result_from_HRESULT(hr));
11314  }
11315 
11316  result = ma_completion_handler_uwp_init(&completionHandler);
11317  if (result != MA_SUCCESS) {
11318  ma_CoTaskMemFree(pContext, iidStr);
11319  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().", result);
11320  }
11321 
11322 #if defined(__cplusplus)
11323  hr = ActivateAudioInterfaceAsync(iidStr, MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
11324 #else
11325  hr = ActivateAudioInterfaceAsync(iidStr, &MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
11326 #endif
11327  if (FAILED(hr)) {
11328  ma_completion_handler_uwp_uninit(&completionHandler);
11329  ma_CoTaskMemFree(pContext, iidStr);
11330  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed.", ma_result_from_HRESULT(hr));
11331  }
11332 
11333  ma_CoTaskMemFree(pContext, iidStr);
11334 
11335  /* Wait for the async operation for finish. */
11336  ma_completion_handler_uwp_wait(&completionHandler);
11337  ma_completion_handler_uwp_uninit(&completionHandler);
11338 
11339  hr = ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(pAsyncOp, &activateResult, &pActivatedInterface);
11340  ma_IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp);
11341 
11342  if (FAILED(hr) || FAILED(activateResult)) {
11343  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device.", FAILED(hr) ? ma_result_from_HRESULT(hr) : ma_result_from_HRESULT(activateResult));
11344  }
11345 
11346  /* Here is where we grab the IAudioClient interface. */
11347  hr = ma_IUnknown_QueryInterface(pActivatedInterface, &MA_IID_IAudioClient, (void**)ppAudioClient);
11348  if (FAILED(hr)) {
11349  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface.", ma_result_from_HRESULT(hr));
11350  }
11351 
11352  if (ppActivatedInterface) {
11353  *ppActivatedInterface = pActivatedInterface;
11354  } else {
11355  ma_IUnknown_Release(pActivatedInterface);
11356  }
11357 
11358  return MA_SUCCESS;
11359 }
11360 #endif
11361 
11362 static ma_result ma_context_get_IAudioClient__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IAudioClient** ppAudioClient, ma_WASAPIDeviceInterface** ppDeviceInterface)
11363 {
11364 #ifdef MA_WIN32_DESKTOP
11365  return ma_context_get_IAudioClient_Desktop__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface);
11366 #else
11367  return ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface);
11368 #endif
11369 }
11370 
11371 
11372 static ma_result ma_context_enumerate_devices__wasapi(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
11373 {
11374  /* Different enumeration for desktop and UWP. */
11375 #ifdef MA_WIN32_DESKTOP
11376  /* Desktop */
11377  HRESULT hr;
11378  ma_IMMDeviceEnumerator* pDeviceEnumerator;
11379 
11380  hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
11381  if (FAILED(hr)) {
11382  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr));
11383  }
11384 
11385  ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_playback, callback, pUserData);
11386  ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_capture, callback, pUserData);
11387 
11388  ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
11389 #else
11390  /*
11391  UWP
11392 
11393  The MMDevice API is only supported on desktop applications. For now, while I'm still figuring out how to properly enumerate
11394  over devices without using MMDevice, I'm restricting devices to defaults.
11395 
11396  Hint: DeviceInformation::FindAllAsync() with DeviceClass.AudioCapture/AudioRender. https://blogs.windows.com/buildingapps/2014/05/15/real-time-audio-in-windows-store-and-windows-phone-apps/
11397  */
11398  if (callback) {
11399  ma_bool32 cbResult = MA_TRUE;
11400 
11401  /* Playback. */
11402  if (cbResult) {
11403  ma_device_info deviceInfo;
11404  MA_ZERO_OBJECT(&deviceInfo);
11405  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
11406  deviceInfo._private.isDefault = MA_TRUE;
11407  cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
11408  }
11409 
11410  /* Capture. */
11411  if (cbResult) {
11412  ma_device_info deviceInfo;
11413  MA_ZERO_OBJECT(&deviceInfo);
11414  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
11415  deviceInfo._private.isDefault = MA_TRUE;
11416  cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
11417  }
11418  }
11419 #endif
11420 
11421  return MA_SUCCESS;
11422 }
11423 
11424 static ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
11425 {
11426 #ifdef MA_WIN32_DESKTOP
11427  ma_result result;
11428  ma_IMMDevice* pMMDevice = NULL;
11429  LPWSTR pDefaultDeviceID = NULL;
11430 
11431  result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, &pMMDevice);
11432  if (result != MA_SUCCESS) {
11433  return result;
11434  }
11435 
11436  /* We need the default device ID so we can set the isDefault flag in the device info. */
11437  pDefaultDeviceID = ma_context_get_default_device_id__wasapi(pContext, deviceType);
11438 
11439  result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, shareMode, pDefaultDeviceID, MA_FALSE, pDeviceInfo); /* MA_FALSE = !onlySimpleInfo. */
11440 
11441  if (pDefaultDeviceID != NULL) {
11442  ma_CoTaskMemFree(pContext, pDefaultDeviceID);
11443  pDefaultDeviceID = NULL;
11444  }
11445 
11446  ma_IMMDevice_Release(pMMDevice);
11447 
11448  return result;
11449 #else
11450  ma_IAudioClient* pAudioClient;
11451  ma_result result;
11452 
11453  /* UWP currently only uses default devices. */
11454  if (deviceType == ma_device_type_playback) {
11455  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
11456  } else {
11457  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
11458  }
11459 
11460  /* Not currently supporting exclusive mode on UWP. */
11461  if (shareMode == ma_share_mode_exclusive) {
11462  return MA_ERROR;
11463  }
11464 
11465  result = ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, &pAudioClient, NULL);
11466  if (result != MA_SUCCESS) {
11467  return result;
11468  }
11469 
11470  result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, NULL, pAudioClient, shareMode, pDeviceInfo);
11471 
11472  pDeviceInfo->_private.isDefault = MA_TRUE; /* UWP only supports default devices. */
11473 
11474  ma_IAudioClient_Release(pAudioClient);
11475  return result;
11476 #endif
11477 }
11478 
11479 static void ma_device_uninit__wasapi(ma_device* pDevice)
11480 {
11481  MA_ASSERT(pDevice != NULL);
11482 
11483 #ifdef MA_WIN32_DESKTOP
11484  if (pDevice->wasapi.pDeviceEnumerator) {
11485  ((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator)->lpVtbl->UnregisterEndpointNotificationCallback((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator, &pDevice->wasapi.notificationClient);
11486  ma_IMMDeviceEnumerator_Release((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator);
11487  }
11488 #endif
11489 
11490  if (pDevice->wasapi.pRenderClient) {
11491  ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient);
11492  }
11493  if (pDevice->wasapi.pCaptureClient) {
11494  ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
11495  }
11496 
11497  if (pDevice->wasapi.pAudioClientPlayback) {
11498  ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
11499  }
11500  if (pDevice->wasapi.pAudioClientCapture) {
11501  ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
11502  }
11503 
11504  if (pDevice->wasapi.hEventPlayback) {
11505  CloseHandle(pDevice->wasapi.hEventPlayback);
11506  }
11507  if (pDevice->wasapi.hEventCapture) {
11508  CloseHandle(pDevice->wasapi.hEventCapture);
11509  }
11510 }
11511 
11512 
11513 typedef struct
11514 {
11515  /* Input. */
11516  ma_format formatIn;
11517  ma_uint32 channelsIn;
11518  ma_uint32 sampleRateIn;
11519  ma_channel channelMapIn[MA_MAX_CHANNELS];
11520  ma_uint32 periodSizeInFramesIn;
11521  ma_uint32 periodSizeInMillisecondsIn;
11522  ma_uint32 periodsIn;
11523  ma_bool32 usingDefaultFormat;
11524  ma_bool32 usingDefaultChannels;
11525  ma_bool32 usingDefaultSampleRate;
11526  ma_bool32 usingDefaultChannelMap;
11527  ma_share_mode shareMode;
11528  ma_bool32 noAutoConvertSRC;
11529  ma_bool32 noDefaultQualitySRC;
11530  ma_bool32 noHardwareOffloading;
11531 
11532  /* Output. */
11533  ma_IAudioClient* pAudioClient;
11534  ma_IAudioRenderClient* pRenderClient;
11535  ma_IAudioCaptureClient* pCaptureClient;
11536  ma_format formatOut;
11537  ma_uint32 channelsOut;
11538  ma_uint32 sampleRateOut;
11539  ma_channel channelMapOut[MA_MAX_CHANNELS];
11540  ma_uint32 periodSizeInFramesOut;
11541  ma_uint32 periodsOut;
11542  ma_bool32 usingAudioClient3;
11543  char deviceName[256];
11544 } ma_device_init_internal_data__wasapi;
11545 
11546 static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_init_internal_data__wasapi* pData)
11547 {
11548  HRESULT hr;
11549  ma_result result = MA_SUCCESS;
11550  const char* errorMsg = "";
11551  MA_AUDCLNT_SHAREMODE shareMode = MA_AUDCLNT_SHAREMODE_SHARED;
11552  DWORD streamFlags = 0;
11553  MA_REFERENCE_TIME periodDurationInMicroseconds;
11554  ma_bool32 wasInitializedUsingIAudioClient3 = MA_FALSE;
11555  WAVEFORMATEXTENSIBLE wf = {0};
11556  ma_WASAPIDeviceInterface* pDeviceInterface = NULL;
11557  ma_IAudioClient2* pAudioClient2;
11558  ma_uint32 nativeSampleRate;
11559 
11560  MA_ASSERT(pContext != NULL);
11561  MA_ASSERT(pData != NULL);
11562 
11563  /* This function is only used to initialize one device type: either playback, capture or loopback. Never full-duplex. */
11564  if (deviceType == ma_device_type_duplex) {
11565  return MA_INVALID_ARGS;
11566  }
11567 
11568  pData->pAudioClient = NULL;
11569  pData->pRenderClient = NULL;
11570  pData->pCaptureClient = NULL;
11571 
11572  streamFlags = MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
11573  if (!pData->noAutoConvertSRC && !pData->usingDefaultSampleRate && pData->shareMode != ma_share_mode_exclusive) { /* <-- Exclusive streams must use the native sample rate. */
11574  streamFlags |= MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM;
11575  }
11576  if (!pData->noDefaultQualitySRC && !pData->usingDefaultSampleRate && (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) != 0) {
11577  streamFlags |= MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
11578  }
11579  if (deviceType == ma_device_type_loopback) {
11580  streamFlags |= MA_AUDCLNT_STREAMFLAGS_LOOPBACK;
11581  }
11582 
11583  result = ma_context_get_IAudioClient__wasapi(pContext, deviceType, pDeviceID, &pData->pAudioClient, &pDeviceInterface);
11584  if (result != MA_SUCCESS) {
11585  goto done;
11586  }
11587 
11588 
11589  /* Try enabling hardware offloading. */
11590  if (!pData->noHardwareOffloading) {
11591  hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient2, (void**)&pAudioClient2);
11592  if (SUCCEEDED(hr)) {
11593  BOOL isHardwareOffloadingSupported = 0;
11594  hr = ma_IAudioClient2_IsOffloadCapable(pAudioClient2, MA_AudioCategory_Other, &isHardwareOffloadingSupported);
11595  if (SUCCEEDED(hr) && isHardwareOffloadingSupported) {
11596  ma_AudioClientProperties clientProperties;
11597  MA_ZERO_OBJECT(&clientProperties);
11598  clientProperties.cbSize = sizeof(clientProperties);
11599  clientProperties.bIsOffload = 1;
11600  clientProperties.eCategory = MA_AudioCategory_Other;
11601  ma_IAudioClient2_SetClientProperties(pAudioClient2, &clientProperties);
11602  }
11603 
11604  pAudioClient2->lpVtbl->Release(pAudioClient2);
11605  }
11606  }
11607 
11608  /* Here is where we try to determine the best format to use with the device. If the client if wanting exclusive mode, first try finding the best format for that. If this fails, fall back to shared mode. */
11609  result = MA_FORMAT_NOT_SUPPORTED;
11610  if (pData->shareMode == ma_share_mode_exclusive) {
11611  #ifdef MA_WIN32_DESKTOP
11612  /* In exclusive mode on desktop we always use the backend's native format. */
11613  ma_IPropertyStore* pStore = NULL;
11614  hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pStore);
11615  if (SUCCEEDED(hr)) {
11616  PROPVARIANT prop;
11617  ma_PropVariantInit(&prop);
11618  hr = ma_IPropertyStore_GetValue(pStore, &MA_PKEY_AudioEngine_DeviceFormat, &prop);
11619  if (SUCCEEDED(hr)) {
11620  WAVEFORMATEX* pActualFormat = (WAVEFORMATEX*)prop.blob.pBlobData;
11621  hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pData->pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pActualFormat, NULL);
11622  if (SUCCEEDED(hr)) {
11623  MA_COPY_MEMORY(&wf, pActualFormat, sizeof(WAVEFORMATEXTENSIBLE));
11624  }
11625 
11626  ma_PropVariantClear(pContext, &prop);
11627  }
11628 
11629  ma_IPropertyStore_Release(pStore);
11630  }
11631  #else
11632  /*
11633  I do not know how to query the device's native format on UWP so for now I'm just disabling support for
11634  exclusive mode. The alternative is to enumerate over different formats and check IsFormatSupported()
11635  until you find one that works.
11636 
11637  TODO: Add support for exclusive mode to UWP.
11638  */
11639  hr = S_FALSE;
11640  #endif
11641 
11642  if (hr == S_OK) {
11643  shareMode = MA_AUDCLNT_SHAREMODE_EXCLUSIVE;
11644  result = MA_SUCCESS;
11645  } else {
11646  result = MA_SHARE_MODE_NOT_SUPPORTED;
11647  }
11648  } else {
11649  /* In shared mode we are always using the format reported by the operating system. */
11650  WAVEFORMATEXTENSIBLE* pNativeFormat = NULL;
11651  hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pData->pAudioClient, (WAVEFORMATEX**)&pNativeFormat);
11652  if (hr != S_OK) {
11653  result = MA_FORMAT_NOT_SUPPORTED;
11654  } else {
11655  MA_COPY_MEMORY(&wf, pNativeFormat, sizeof(wf));
11656  result = MA_SUCCESS;
11657  }
11658 
11659  ma_CoTaskMemFree(pContext, pNativeFormat);
11660 
11661  shareMode = MA_AUDCLNT_SHAREMODE_SHARED;
11662  }
11663 
11664  /* Return an error if we still haven't found a format. */
11665  if (result != MA_SUCCESS) {
11666  errorMsg = "[WASAPI] Failed to find best device mix format.";
11667  goto done;
11668  }
11669 
11670  /*
11671  Override the native sample rate with the one requested by the caller, but only if we're not using the default sample rate. We'll use
11672  WASAPI to perform the sample rate conversion.
11673  */
11674  nativeSampleRate = wf.Format.nSamplesPerSec;
11675  if (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) {
11676  wf.Format.nSamplesPerSec = pData->sampleRateIn;
11677  wf.Format.nAvgBytesPerSec = wf.Format.nSamplesPerSec * wf.Format.nBlockAlign;
11678  }
11679 
11680  pData->formatOut = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)&wf);
11681  pData->channelsOut = wf.Format.nChannels;
11682  pData->sampleRateOut = wf.Format.nSamplesPerSec;
11683 
11684  /* Get the internal channel map based on the channel mask. */
11685  ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pData->channelsOut, pData->channelMapOut);
11686 
11687  /* Period size. */
11688  pData->periodsOut = pData->periodsIn;
11689  pData->periodSizeInFramesOut = pData->periodSizeInFramesIn;
11690  if (pData->periodSizeInFramesOut == 0) {
11691  pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, wf.Format.nSamplesPerSec);
11692  }
11693 
11694  periodDurationInMicroseconds = ((ma_uint64)pData->periodSizeInFramesOut * 1000 * 1000) / wf.Format.nSamplesPerSec;
11695 
11696 
11697  /* Slightly different initialization for shared and exclusive modes. We try exclusive mode first, and if it fails, fall back to shared mode. */
11698  if (shareMode == MA_AUDCLNT_SHAREMODE_EXCLUSIVE) {
11699  MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * 10;
11700 
11701  /*
11702  If the periodicy is too small, Initialize() will fail with AUDCLNT_E_INVALID_DEVICE_PERIOD. In this case we should just keep increasing
11703  it and trying it again.
11704  */
11705  hr = E_FAIL;
11706  for (;;) {
11707  hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL);
11708  if (hr == MA_AUDCLNT_E_INVALID_DEVICE_PERIOD) {
11709  if (bufferDuration > 500*10000) {
11710  break;
11711  } else {
11712  if (bufferDuration == 0) { /* <-- Just a sanity check to prevent an infinit loop. Should never happen, but it makes me feel better. */
11713  break;
11714  }
11715 
11716  bufferDuration = bufferDuration * 2;
11717  continue;
11718  }
11719  } else {
11720  break;
11721  }
11722  }
11723 
11724  if (hr == MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) {
11725  ma_uint32 bufferSizeInFrames;
11726  hr = ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient, &bufferSizeInFrames);
11727  if (SUCCEEDED(hr)) {
11728  bufferDuration = (MA_REFERENCE_TIME)((10000.0 * 1000 / wf.Format.nSamplesPerSec * bufferSizeInFrames) + 0.5);
11729 
11730  /* Unfortunately we need to release and re-acquire the audio client according to MSDN. Seems silly - why not just call IAudioClient_Initialize() again?! */
11731  ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient);
11732 
11733  #ifdef MA_WIN32_DESKTOP
11734  hr = ma_IMMDevice_Activate(pDeviceInterface, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pData->pAudioClient);
11735  #else
11736  hr = ma_IUnknown_QueryInterface(pDeviceInterface, &MA_IID_IAudioClient, (void**)&pData->pAudioClient);
11737  #endif
11738 
11739  if (SUCCEEDED(hr)) {
11740  hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL);
11741  }
11742  }
11743  }
11744 
11745  if (FAILED(hr)) {
11746  /* Failed to initialize in exclusive mode. Don't fall back to shared mode - instead tell the client about it. They can reinitialize in shared mode if they want. */
11747  if (hr == E_ACCESSDENIED) {
11748  errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Access denied.", result = MA_ACCESS_DENIED;
11749  } else if (hr == MA_AUDCLNT_E_DEVICE_IN_USE) {
11750  errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Device in use.", result = MA_BUSY;
11751  } else {
11752  errorMsg = "[WASAPI] Failed to initialize device in exclusive mode."; result = ma_result_from_HRESULT(hr);
11753  }
11754  goto done;
11755  }
11756  }
11757 
11758  if (shareMode == MA_AUDCLNT_SHAREMODE_SHARED) {
11759  /*
11760  Low latency shared mode via IAudioClient3.
11761 
11762  NOTE
11763  ====
11764  Contrary to the documentation on MSDN (https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nf-audioclient-iaudioclient3-initializesharedaudiostream), the
11765  use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM and AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY with IAudioClient3_InitializeSharedAudioStream() absolutely does not work. Using
11766  any of these flags will result in HRESULT code 0x88890021. The other problem is that calling IAudioClient3_GetSharedModeEnginePeriod() with a sample rate different to
11767  that returned by IAudioClient_GetMixFormat() also results in an error. I'm therefore disabling low-latency shared mode with AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM.
11768  */
11769 #ifndef MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE
11770  if ((streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) == 0 || nativeSampleRate == wf.Format.nSamplesPerSec) {
11771  ma_IAudioClient3* pAudioClient3 = NULL;
11772  hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient3, (void**)&pAudioClient3);
11773  if (SUCCEEDED(hr)) {
11774  UINT32 defaultPeriodInFrames;
11775  UINT32 fundamentalPeriodInFrames;
11776  UINT32 minPeriodInFrames;
11777  UINT32 maxPeriodInFrames;
11778  hr = ma_IAudioClient3_GetSharedModeEnginePeriod(pAudioClient3, (WAVEFORMATEX*)&wf, &defaultPeriodInFrames, &fundamentalPeriodInFrames, &minPeriodInFrames, &maxPeriodInFrames);
11779  if (SUCCEEDED(hr)) {
11780  UINT32 desiredPeriodInFrames = pData->periodSizeInFramesOut;
11781  UINT32 actualPeriodInFrames = desiredPeriodInFrames;
11782 
11783  /* Make sure the period size is a multiple of fundamentalPeriodInFrames. */
11784  actualPeriodInFrames = actualPeriodInFrames / fundamentalPeriodInFrames;
11785  actualPeriodInFrames = actualPeriodInFrames * fundamentalPeriodInFrames;
11786 
11787  /* The period needs to be clamped between minPeriodInFrames and maxPeriodInFrames. */
11788  actualPeriodInFrames = ma_clamp(actualPeriodInFrames, minPeriodInFrames, maxPeriodInFrames);
11789 
11790  #if defined(MA_DEBUG_OUTPUT)
11791  printf("[WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=%d)\n", actualPeriodInFrames);
11792  printf(" defaultPeriodInFrames=%d\n", defaultPeriodInFrames);
11793  printf(" fundamentalPeriodInFrames=%d\n", fundamentalPeriodInFrames);
11794  printf(" minPeriodInFrames=%d\n", minPeriodInFrames);
11795  printf(" maxPeriodInFrames=%d\n", maxPeriodInFrames);
11796  #endif
11797 
11798  /* If the client requested a largish buffer than we don't actually want to use low latency shared mode because it forces small buffers. */
11799  if (actualPeriodInFrames >= desiredPeriodInFrames) {
11800  /*
11801  MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY must not be in the stream flags. If either of these are specified,
11802  IAudioClient3_InitializeSharedAudioStream() will fail.
11803  */
11804  hr = ma_IAudioClient3_InitializeSharedAudioStream(pAudioClient3, streamFlags & ~(MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY), actualPeriodInFrames, (WAVEFORMATEX*)&wf, NULL);
11805  if (SUCCEEDED(hr)) {
11806  wasInitializedUsingIAudioClient3 = MA_TRUE;
11807  pData->periodSizeInFramesOut = actualPeriodInFrames;
11808  #if defined(MA_DEBUG_OUTPUT)
11809  printf("[WASAPI] Using IAudioClient3\n");
11810  printf(" periodSizeInFramesOut=%d\n", pData->periodSizeInFramesOut);
11811  #endif
11812  } else {
11813  #if defined(MA_DEBUG_OUTPUT)
11814  printf("[WASAPI] IAudioClient3_InitializeSharedAudioStream failed. Falling back to IAudioClient.\n");
11815  #endif
11816  }
11817  } else {
11818  #if defined(MA_DEBUG_OUTPUT)
11819  printf("[WASAPI] Not using IAudioClient3 because the desired period size is larger than the maximum supported by IAudioClient3.\n");
11820  #endif
11821  }
11822  } else {
11823  #if defined(MA_DEBUG_OUTPUT)
11824  printf("[WASAPI] IAudioClient3_GetSharedModeEnginePeriod failed. Falling back to IAudioClient.\n");
11825  #endif
11826  }
11827 
11828  ma_IAudioClient3_Release(pAudioClient3);
11829  pAudioClient3 = NULL;
11830  }
11831  }
11832 #else
11833  #if defined(MA_DEBUG_OUTPUT)
11834  printf("[WASAPI] Not using IAudioClient3 because MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE is enabled.\n");
11835  #endif
11836 #endif
11837 
11838  /* If we don't have an IAudioClient3 then we need to use the normal initialization routine. */
11839  if (!wasInitializedUsingIAudioClient3) {
11840  MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * pData->periodsOut * 10; /* <-- Multiply by 10 for microseconds to 100-nanoseconds. */
11841  hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, 0, (WAVEFORMATEX*)&wf, NULL);
11842  if (FAILED(hr)) {
11843  if (hr == E_ACCESSDENIED) {
11844  errorMsg = "[WASAPI] Failed to initialize device. Access denied.", result = MA_ACCESS_DENIED;
11845  } else if (hr == MA_AUDCLNT_E_DEVICE_IN_USE) {
11846  errorMsg = "[WASAPI] Failed to initialize device. Device in use.", result = MA_BUSY;
11847  } else {
11848  errorMsg = "[WASAPI] Failed to initialize device.", result = ma_result_from_HRESULT(hr);
11849  }
11850 
11851  goto done;
11852  }
11853  }
11854  }
11855 
11856  if (!wasInitializedUsingIAudioClient3) {
11857  ma_uint32 bufferSizeInFrames;
11858  hr = ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient, &bufferSizeInFrames);
11859  if (FAILED(hr)) {
11860  errorMsg = "[WASAPI] Failed to get audio client's actual buffer size.", result = ma_result_from_HRESULT(hr);
11861  goto done;
11862  }
11863 
11864  pData->periodSizeInFramesOut = bufferSizeInFrames / pData->periodsOut;
11865  }
11866 
11867  pData->usingAudioClient3 = wasInitializedUsingIAudioClient3;
11868 
11869  if (deviceType == ma_device_type_playback) {
11870  hr = ma_IAudioClient_GetService((ma_IAudioClient*)pData->pAudioClient, &MA_IID_IAudioRenderClient, (void**)&pData->pRenderClient);
11871  } else {
11872  hr = ma_IAudioClient_GetService((ma_IAudioClient*)pData->pAudioClient, &MA_IID_IAudioCaptureClient, (void**)&pData->pCaptureClient);
11873  }
11874 
11875  if (FAILED(hr)) {
11876  errorMsg = "[WASAPI] Failed to get audio client service.", result = ma_result_from_HRESULT(hr);
11877  goto done;
11878  }
11879 
11880 
11881  /* Grab the name of the device. */
11882 #ifdef MA_WIN32_DESKTOP
11883  {
11884  ma_IPropertyStore *pProperties;
11885  hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pProperties);
11886  if (SUCCEEDED(hr)) {
11887  PROPVARIANT varName;
11888  ma_PropVariantInit(&varName);
11889  hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &varName);
11890  if (SUCCEEDED(hr)) {
11891  WideCharToMultiByte(CP_UTF8, 0, varName.pwszVal, -1, pData->deviceName, sizeof(pData->deviceName), 0, FALSE);
11892  ma_PropVariantClear(pContext, &varName);
11893  }
11894 
11895  ma_IPropertyStore_Release(pProperties);
11896  }
11897  }
11898 #endif
11899 
11900 done:
11901  /* Clean up. */
11902 #ifdef MA_WIN32_DESKTOP
11903  if (pDeviceInterface != NULL) {
11904  ma_IMMDevice_Release(pDeviceInterface);
11905  }
11906 #else
11907  if (pDeviceInterface != NULL) {
11908  ma_IUnknown_Release(pDeviceInterface);
11909  }
11910 #endif
11911 
11912  if (result != MA_SUCCESS) {
11913  if (pData->pRenderClient) {
11914  ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pData->pRenderClient);
11915  pData->pRenderClient = NULL;
11916  }
11917  if (pData->pCaptureClient) {
11918  ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pData->pCaptureClient);
11919  pData->pCaptureClient = NULL;
11920  }
11921  if (pData->pAudioClient) {
11922  ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient);
11923  pData->pAudioClient = NULL;
11924  }
11925 
11926  if (errorMsg != NULL && errorMsg[0] != '\0') {
11927  ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, errorMsg, result);
11928  }
11929 
11930  return result;
11931  } else {
11932  return MA_SUCCESS;
11933  }
11934 }
11935 
11936 static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type deviceType)
11937 {
11938  ma_device_init_internal_data__wasapi data;
11939  ma_result result;
11940 
11941  MA_ASSERT(pDevice != NULL);
11942 
11943  /* We only re-initialize the playback or capture device. Never a full-duplex device. */
11944  if (deviceType == ma_device_type_duplex) {
11945  return MA_INVALID_ARGS;
11946  }
11947 
11948  if (deviceType == ma_device_type_playback) {
11949  data.formatIn = pDevice->playback.format;
11950  data.channelsIn = pDevice->playback.channels;
11951  MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
11952  data.shareMode = pDevice->playback.shareMode;
11953  data.usingDefaultFormat = pDevice->playback.usingDefaultFormat;
11954  data.usingDefaultChannels = pDevice->playback.usingDefaultChannels;
11955  data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap;
11956  } else {
11957  data.formatIn = pDevice->capture.format;
11958  data.channelsIn = pDevice->capture.channels;
11959  MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
11960  data.shareMode = pDevice->capture.shareMode;
11961  data.usingDefaultFormat = pDevice->capture.usingDefaultFormat;
11962  data.usingDefaultChannels = pDevice->capture.usingDefaultChannels;
11963  data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap;
11964  }
11965 
11966  data.sampleRateIn = pDevice->sampleRate;
11967  data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
11968  data.periodSizeInFramesIn = pDevice->wasapi.originalPeriodSizeInFrames;
11969  data.periodSizeInMillisecondsIn = pDevice->wasapi.originalPeriodSizeInMilliseconds;
11970  data.periodsIn = pDevice->wasapi.originalPeriods;
11971  data.noAutoConvertSRC = pDevice->wasapi.noAutoConvertSRC;
11972  data.noDefaultQualitySRC = pDevice->wasapi.noDefaultQualitySRC;
11973  data.noHardwareOffloading = pDevice->wasapi.noHardwareOffloading;
11974  result = ma_device_init_internal__wasapi(pDevice->pContext, deviceType, NULL, &data);
11975  if (result != MA_SUCCESS) {
11976  return result;
11977  }
11978 
11979  /* At this point we have some new objects ready to go. We need to uninitialize the previous ones and then set the new ones. */
11980  if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
11981  if (pDevice->wasapi.pCaptureClient) {
11982  ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
11983  pDevice->wasapi.pCaptureClient = NULL;
11984  }
11985 
11986  if (pDevice->wasapi.pAudioClientCapture) {
11987  ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
11988  pDevice->wasapi.pAudioClientCapture = NULL;
11989  }
11990 
11991  pDevice->wasapi.pAudioClientCapture = data.pAudioClient;
11992  pDevice->wasapi.pCaptureClient = data.pCaptureClient;
11993 
11994  pDevice->capture.internalFormat = data.formatOut;
11995  pDevice->capture.internalChannels = data.channelsOut;
11996  pDevice->capture.internalSampleRate = data.sampleRateOut;
11997  MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
11998  pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
11999  pDevice->capture.internalPeriods = data.periodsOut;
12000  ma_strcpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), data.deviceName);
12001 
12002  ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture);
12003 
12004  pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut;
12005  ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture);
12006 
12007  /* The device may be in a started state. If so we need to immediately restart it. */
12008  if (pDevice->wasapi.isStartedCapture) {
12009  HRESULT hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
12010  if (FAILED(hr)) {
12011  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device after reinitialization.", ma_result_from_HRESULT(hr));
12012  }
12013  }
12014  }
12015 
12016  if (deviceType == ma_device_type_playback) {
12017  if (pDevice->wasapi.pRenderClient) {
12018  ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient);
12019  pDevice->wasapi.pRenderClient = NULL;
12020  }
12021 
12022  if (pDevice->wasapi.pAudioClientPlayback) {
12023  ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
12024  pDevice->wasapi.pAudioClientPlayback = NULL;
12025  }
12026 
12027  pDevice->wasapi.pAudioClientPlayback = data.pAudioClient;
12028  pDevice->wasapi.pRenderClient = data.pRenderClient;
12029 
12030  pDevice->playback.internalFormat = data.formatOut;
12031  pDevice->playback.internalChannels = data.channelsOut;
12032  pDevice->playback.internalSampleRate = data.sampleRateOut;
12033  MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
12034  pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
12035  pDevice->playback.internalPeriods = data.periodsOut;
12036  ma_strcpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), data.deviceName);
12037 
12038  ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback);
12039 
12040  pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut;
12041  ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback);
12042 
12043  /* The device may be in a started state. If so we need to immediately restart it. */
12044  if (pDevice->wasapi.isStartedPlayback) {
12045  HRESULT hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
12046  if (FAILED(hr)) {
12047  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device after reinitialization.", ma_result_from_HRESULT(hr));
12048  }
12049  }
12050  }
12051 
12052  return MA_SUCCESS;
12053 }
12054 
12055 static ma_result ma_device_init__wasapi(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
12056 {
12057  ma_result result = MA_SUCCESS;
12058 
12059  (void)pContext;
12060 
12061  MA_ASSERT(pContext != NULL);
12062  MA_ASSERT(pDevice != NULL);
12063 
12064  MA_ZERO_OBJECT(&pDevice->wasapi);
12065  pDevice->wasapi.originalPeriodSizeInFrames = pConfig->periodSizeInFrames;
12066  pDevice->wasapi.originalPeriodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
12067  pDevice->wasapi.originalPeriods = pConfig->periods;
12068  pDevice->wasapi.noAutoConvertSRC = pConfig->wasapi.noAutoConvertSRC;
12069  pDevice->wasapi.noDefaultQualitySRC = pConfig->wasapi.noDefaultQualitySRC;
12070  pDevice->wasapi.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading;
12071 
12072  /* Exclusive mode is not allowed with loopback. */
12074  return MA_INVALID_DEVICE_CONFIG;
12075  }
12076 
12078  ma_device_init_internal_data__wasapi data;
12079  data.formatIn = pConfig->capture.format;
12080  data.channelsIn = pConfig->capture.channels;
12081  data.sampleRateIn = pConfig->sampleRate;
12082  MA_COPY_MEMORY(data.channelMapIn, pConfig->capture.channelMap, sizeof(pConfig->capture.channelMap));
12083  data.usingDefaultFormat = pDevice->capture.usingDefaultFormat;
12084  data.usingDefaultChannels = pDevice->capture.usingDefaultChannels;
12085  data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
12086  data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap;
12087  data.shareMode = pConfig->capture.shareMode;
12088  data.periodSizeInFramesIn = pConfig->periodSizeInFrames;
12089  data.periodSizeInMillisecondsIn = pConfig->periodSizeInMilliseconds;
12090  data.periodsIn = pConfig->periods;
12091  data.noAutoConvertSRC = pConfig->wasapi.noAutoConvertSRC;
12092  data.noDefaultQualitySRC = pConfig->wasapi.noDefaultQualitySRC;
12093  data.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading;
12094 
12095  result = ma_device_init_internal__wasapi(pDevice->pContext, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture, pConfig->capture.pDeviceID, &data);
12096  if (result != MA_SUCCESS) {
12097  return result;
12098  }
12099 
12100  pDevice->wasapi.pAudioClientCapture = data.pAudioClient;
12101  pDevice->wasapi.pCaptureClient = data.pCaptureClient;
12102 
12103  pDevice->capture.internalFormat = data.formatOut;
12104  pDevice->capture.internalChannels = data.channelsOut;
12105  pDevice->capture.internalSampleRate = data.sampleRateOut;
12106  MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
12107  pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
12108  pDevice->capture.internalPeriods = data.periodsOut;
12109  ma_strcpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), data.deviceName);
12110 
12111  /*
12112  The event for capture needs to be manual reset for the same reason as playback. We keep the initial state set to unsignaled,
12113  however, because we want to block until we actually have something for the first call to ma_device_read().
12114  */
12115  pDevice->wasapi.hEventCapture = CreateEventW(NULL, FALSE, FALSE, NULL); /* Auto reset, unsignaled by default. */
12116  if (pDevice->wasapi.hEventCapture == NULL) {
12117  result = ma_result_from_GetLastError(GetLastError());
12118 
12119  if (pDevice->wasapi.pCaptureClient != NULL) {
12120  ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
12121  pDevice->wasapi.pCaptureClient = NULL;
12122  }
12123  if (pDevice->wasapi.pAudioClientCapture != NULL) {
12124  ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
12125  pDevice->wasapi.pAudioClientCapture = NULL;
12126  }
12127 
12128  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for capture.", result);
12129  }
12130  ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture);
12131 
12132  pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut;
12133  ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture);
12134  }
12135 
12136  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
12137  ma_device_init_internal_data__wasapi data;
12138  data.formatIn = pConfig->playback.format;
12139  data.channelsIn = pConfig->playback.channels;
12140  data.sampleRateIn = pConfig->sampleRate;
12141  MA_COPY_MEMORY(data.channelMapIn, pConfig->playback.channelMap, sizeof(pConfig->playback.channelMap));
12142  data.usingDefaultFormat = pDevice->playback.usingDefaultFormat;
12143  data.usingDefaultChannels = pDevice->playback.usingDefaultChannels;
12144  data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
12145  data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap;
12146  data.shareMode = pConfig->playback.shareMode;
12147  data.periodSizeInFramesIn = pConfig->periodSizeInFrames;
12148  data.periodSizeInMillisecondsIn = pConfig->periodSizeInMilliseconds;
12149  data.periodsIn = pConfig->periods;
12150  data.noAutoConvertSRC = pConfig->wasapi.noAutoConvertSRC;
12151  data.noDefaultQualitySRC = pConfig->wasapi.noDefaultQualitySRC;
12152  data.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading;
12153 
12154  result = ma_device_init_internal__wasapi(pDevice->pContext, ma_device_type_playback, pConfig->playback.pDeviceID, &data);
12155  if (result != MA_SUCCESS) {
12156  if (pConfig->deviceType == ma_device_type_duplex) {
12157  if (pDevice->wasapi.pCaptureClient != NULL) {
12158  ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
12159  pDevice->wasapi.pCaptureClient = NULL;
12160  }
12161  if (pDevice->wasapi.pAudioClientCapture != NULL) {
12162  ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
12163  pDevice->wasapi.pAudioClientCapture = NULL;
12164  }
12165 
12166  CloseHandle(pDevice->wasapi.hEventCapture);
12167  pDevice->wasapi.hEventCapture = NULL;
12168  }
12169  return result;
12170  }
12171 
12172  pDevice->wasapi.pAudioClientPlayback = data.pAudioClient;
12173  pDevice->wasapi.pRenderClient = data.pRenderClient;
12174 
12175  pDevice->playback.internalFormat = data.formatOut;
12176  pDevice->playback.internalChannels = data.channelsOut;
12177  pDevice->playback.internalSampleRate = data.sampleRateOut;
12178  MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
12179  pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
12180  pDevice->playback.internalPeriods = data.periodsOut;
12181  ma_strcpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), data.deviceName);
12182 
12183  /*
12184  The event for playback is needs to be manual reset because we want to explicitly control the fact that it becomes signalled
12185  only after the whole available space has been filled, never before.
12186 
12187  The playback event also needs to be initially set to a signaled state so that the first call to ma_device_write() is able
12188  to get passed WaitForMultipleObjects().
12189  */
12190  pDevice->wasapi.hEventPlayback = CreateEventW(NULL, FALSE, TRUE, NULL); /* Auto reset, signaled by default. */
12191  if (pDevice->wasapi.hEventPlayback == NULL) {
12192  result = ma_result_from_GetLastError(GetLastError());
12193 
12194  if (pConfig->deviceType == ma_device_type_duplex) {
12195  if (pDevice->wasapi.pCaptureClient != NULL) {
12196  ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
12197  pDevice->wasapi.pCaptureClient = NULL;
12198  }
12199  if (pDevice->wasapi.pAudioClientCapture != NULL) {
12200  ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
12201  pDevice->wasapi.pAudioClientCapture = NULL;
12202  }
12203 
12204  CloseHandle(pDevice->wasapi.hEventCapture);
12205  pDevice->wasapi.hEventCapture = NULL;
12206  }
12207 
12208  if (pDevice->wasapi.pRenderClient != NULL) {
12209  ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient);
12210  pDevice->wasapi.pRenderClient = NULL;
12211  }
12212  if (pDevice->wasapi.pAudioClientPlayback != NULL) {
12213  ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
12214  pDevice->wasapi.pAudioClientPlayback = NULL;
12215  }
12216 
12217  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for playback.", result);
12218  }
12219  ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback);
12220 
12221  pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut;
12222  ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback);
12223  }
12224 
12225  /*
12226  We need to get notifications of when the default device changes. We do this through a device enumerator by
12227  registering a IMMNotificationClient with it. We only care about this if it's the default device.
12228  */
12229 #ifdef MA_WIN32_DESKTOP
12230  if (pConfig->wasapi.noAutoStreamRouting == MA_FALSE) {
12231  if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID == NULL) {
12232  pDevice->wasapi.allowCaptureAutoStreamRouting = MA_TRUE;
12233  }
12234  if ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID == NULL) {
12235  pDevice->wasapi.allowPlaybackAutoStreamRouting = MA_TRUE;
12236  }
12237 
12238  if (pDevice->wasapi.allowCaptureAutoStreamRouting || pDevice->wasapi.allowPlaybackAutoStreamRouting) {
12239  ma_IMMDeviceEnumerator* pDeviceEnumerator;
12240  HRESULT hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
12241  if (FAILED(hr)) {
12242  ma_device_uninit__wasapi(pDevice);
12243  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr));
12244  }
12245 
12246  pDevice->wasapi.notificationClient.lpVtbl = (void*)&g_maNotificationCientVtbl;
12247  pDevice->wasapi.notificationClient.counter = 1;
12248  pDevice->wasapi.notificationClient.pDevice = pDevice;
12249 
12250  hr = pDeviceEnumerator->lpVtbl->RegisterEndpointNotificationCallback(pDeviceEnumerator, &pDevice->wasapi.notificationClient);
12251  if (SUCCEEDED(hr)) {
12252  pDevice->wasapi.pDeviceEnumerator = (ma_ptr)pDeviceEnumerator;
12253  } else {
12254  /* Not the end of the world if we fail to register the notification callback. We just won't support automatic stream routing. */
12255  ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
12256  }
12257  }
12258  }
12259 #endif
12260 
12261  ma_atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_FALSE);
12262  ma_atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE);
12263 
12264  return MA_SUCCESS;
12265 }
12266 
12267 static ma_result ma_device__get_available_frames__wasapi(ma_device* pDevice, ma_IAudioClient* pAudioClient, ma_uint32* pFrameCount)
12268 {
12269  ma_uint32 paddingFramesCount;
12270  HRESULT hr;
12271  ma_share_mode shareMode;
12272 
12273  MA_ASSERT(pDevice != NULL);
12274  MA_ASSERT(pFrameCount != NULL);
12275 
12276  *pFrameCount = 0;
12277 
12278  if ((ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientPlayback && (ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientCapture) {
12279  return MA_INVALID_OPERATION;
12280  }
12281 
12282  hr = ma_IAudioClient_GetCurrentPadding(pAudioClient, &paddingFramesCount);
12283  if (FAILED(hr)) {
12284  return ma_result_from_HRESULT(hr);
12285  }
12286 
12287  /* Slightly different rules for exclusive and shared modes. */
12288  shareMode = ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) ? pDevice->playback.shareMode : pDevice->capture.shareMode;
12289  if (shareMode == ma_share_mode_exclusive) {
12290  *pFrameCount = paddingFramesCount;
12291  } else {
12292  if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) {
12293  *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesPlayback - paddingFramesCount;
12294  } else {
12295  *pFrameCount = paddingFramesCount;
12296  }
12297  }
12298 
12299  return MA_SUCCESS;
12300 }
12301 
12302 static ma_bool32 ma_device_is_reroute_required__wasapi(ma_device* pDevice, ma_device_type deviceType)
12303 {
12304  MA_ASSERT(pDevice != NULL);
12305 
12306  if (deviceType == ma_device_type_playback) {
12307  return pDevice->wasapi.hasDefaultPlaybackDeviceChanged;
12308  }
12309 
12310  if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
12311  return pDevice->wasapi.hasDefaultCaptureDeviceChanged;
12312  }
12313 
12314  return MA_FALSE;
12315 }
12316 
12317 static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type deviceType)
12318 {
12319  ma_result result;
12320 
12321  if (deviceType == ma_device_type_duplex) {
12322  return MA_INVALID_ARGS;
12323  }
12324 
12325  if (deviceType == ma_device_type_playback) {
12326  ma_atomic_exchange_32(&pDevice->wasapi.hasDefaultPlaybackDeviceChanged, MA_FALSE);
12327  }
12328  if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
12329  ma_atomic_exchange_32(&pDevice->wasapi.hasDefaultCaptureDeviceChanged, MA_FALSE);
12330  }
12331 
12332 
12333  #ifdef MA_DEBUG_OUTPUT
12334  printf("=== CHANGING DEVICE ===\n");
12335  #endif
12336 
12337  result = ma_device_reinit__wasapi(pDevice, deviceType);
12338  if (result != MA_SUCCESS) {
12339  return result;
12340  }
12341 
12342  ma_device__post_init_setup(pDevice, deviceType);
12343 
12344  return MA_SUCCESS;
12345 }
12346 
12347 
12348 static ma_result ma_device_stop__wasapi(ma_device* pDevice)
12349 {
12350  MA_ASSERT(pDevice != NULL);
12351 
12352  /*
12353  We need to explicitly signal the capture event in loopback mode to ensure we return from WaitForSingleObject() when nothing is being played. When nothing
12354  is being played, the event is never signalled internally by WASAPI which means we will deadlock when stopping the device.
12355  */
12356  if (pDevice->type == ma_device_type_loopback) {
12357  SetEvent((HANDLE)pDevice->wasapi.hEventCapture);
12358  }
12359 
12360  return MA_SUCCESS;
12361 }
12362 
12363 
12364 static ma_result ma_device_main_loop__wasapi(ma_device* pDevice)
12365 {
12366  ma_result result;
12367  HRESULT hr;
12368  ma_bool32 exitLoop = MA_FALSE;
12369  ma_uint32 framesWrittenToPlaybackDevice = 0;
12370  ma_uint32 mappedDeviceBufferSizeInFramesCapture = 0;
12371  ma_uint32 mappedDeviceBufferSizeInFramesPlayback = 0;
12372  ma_uint32 mappedDeviceBufferFramesRemainingCapture = 0;
12373  ma_uint32 mappedDeviceBufferFramesRemainingPlayback = 0;
12374  BYTE* pMappedDeviceBufferCapture = NULL;
12375  BYTE* pMappedDeviceBufferPlayback = NULL;
12376  ma_uint32 bpfCaptureDevice = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
12377  ma_uint32 bpfPlaybackDevice = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
12378  ma_uint32 bpfCaptureClient = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
12379  ma_uint32 bpfPlaybackClient = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
12380  ma_uint8 inputDataInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
12381  ma_uint32 inputDataInClientFormatCap = sizeof(inputDataInClientFormat) / bpfCaptureClient;
12382  ma_uint8 outputDataInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
12383  ma_uint32 outputDataInClientFormatCap = sizeof(outputDataInClientFormat) / bpfPlaybackClient;
12384  ma_uint32 outputDataInClientFormatCount = 0;
12385  ma_uint32 outputDataInClientFormatConsumed = 0;
12386  ma_uint32 periodSizeInFramesCapture = 0;
12387 
12388  MA_ASSERT(pDevice != NULL);
12389 
12390  /* The capture device needs to be started immediately. */
12391  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
12392  periodSizeInFramesCapture = pDevice->capture.internalPeriodSizeInFrames;
12393 
12394  hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
12395  if (FAILED(hr)) {
12396  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device.", ma_result_from_HRESULT(hr));
12397  }
12398  ma_atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_TRUE);
12399  }
12400 
12401  while (ma_device__get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
12402  /* We may need to reroute the device. */
12403  if (ma_device_is_reroute_required__wasapi(pDevice, ma_device_type_playback)) {
12404  result = ma_device_reroute__wasapi(pDevice, ma_device_type_playback);
12405  if (result != MA_SUCCESS) {
12406  exitLoop = MA_TRUE;
12407  break;
12408  }
12409  }
12410  if (ma_device_is_reroute_required__wasapi(pDevice, ma_device_type_capture)) {
12411  result = ma_device_reroute__wasapi(pDevice, (pDevice->type == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture);
12412  if (result != MA_SUCCESS) {
12413  exitLoop = MA_TRUE;
12414  break;
12415  }
12416  }
12417 
12418  switch (pDevice->type)
12419  {
12420  case ma_device_type_duplex:
12421  {
12422  ma_uint32 framesAvailableCapture;
12423  ma_uint32 framesAvailablePlayback;
12424  DWORD flagsCapture; /* Passed to IAudioCaptureClient_GetBuffer(). */
12425 
12426  /* The process is to map the playback buffer and fill it as quickly as possible from input data. */
12427  if (pMappedDeviceBufferPlayback == NULL) {
12428  /* WASAPI is weird with exclusive mode. You need to wait on the event _before_ querying the available frames. */
12429  if (pDevice->playback.shareMode == ma_share_mode_exclusive) {
12430  if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE) == WAIT_FAILED) {
12431  return MA_ERROR; /* Wait failed. */
12432  }
12433  }
12434 
12435  result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback);
12436  if (result != MA_SUCCESS) {
12437  return result;
12438  }
12439 
12440  /*printf("TRACE 1: framesAvailablePlayback=%d\n", framesAvailablePlayback);*/
12441 
12442 
12443  /* In exclusive mode, the frame count needs to exactly match the value returned by GetCurrentPadding(). */
12444  if (pDevice->playback.shareMode != ma_share_mode_exclusive) {
12445  if (framesAvailablePlayback > pDevice->wasapi.periodSizeInFramesPlayback) {
12446  framesAvailablePlayback = pDevice->wasapi.periodSizeInFramesPlayback;
12447  }
12448  }
12449 
12450  /* If there's no frames available in the playback device we need to wait for more. */
12451  if (framesAvailablePlayback == 0) {
12452  /* In exclusive mode we waited at the top. */
12453  if (pDevice->playback.shareMode != ma_share_mode_exclusive) {
12454  if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE) == WAIT_FAILED) {
12455  return MA_ERROR; /* Wait failed. */
12456  }
12457  }
12458 
12459  continue;
12460  }
12461 
12462  /* We're ready to map the playback device's buffer. We don't release this until it's been entirely filled. */
12463  hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedDeviceBufferPlayback);
12464  if (FAILED(hr)) {
12465  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
12466  exitLoop = MA_TRUE;
12467  break;
12468  }
12469 
12470  mappedDeviceBufferSizeInFramesPlayback = framesAvailablePlayback;
12471  mappedDeviceBufferFramesRemainingPlayback = framesAvailablePlayback;
12472  }
12473 
12474  /* At this point we should have a buffer available for output. We need to keep writing input samples to it. */
12475  for (;;) {
12476  /* Try grabbing some captured data if we haven't already got a mapped buffer. */
12477  if (pMappedDeviceBufferCapture == NULL) {
12478  if (pDevice->capture.shareMode == ma_share_mode_shared) {
12479  if (WaitForSingleObject(pDevice->wasapi.hEventCapture, INFINITE) == WAIT_FAILED) {
12480  return MA_ERROR; /* Wait failed. */
12481  }
12482  }
12483 
12484  result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture);
12485  if (result != MA_SUCCESS) {
12486  exitLoop = MA_TRUE;
12487  break;
12488  }
12489 
12490  /*printf("TRACE 2: framesAvailableCapture=%d\n", framesAvailableCapture);*/
12491 
12492  /* Wait for more if nothing is available. */
12493  if (framesAvailableCapture == 0) {
12494  /* In exclusive mode we waited at the top. */
12495  if (pDevice->capture.shareMode != ma_share_mode_shared) {
12496  if (WaitForSingleObject(pDevice->wasapi.hEventCapture, INFINITE) == WAIT_FAILED) {
12497  return MA_ERROR; /* Wait failed. */
12498  }
12499  }
12500 
12501  continue;
12502  }
12503 
12504  /* Getting here means there's data available for writing to the output device. */
12505  mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture);
12506  hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
12507  if (FAILED(hr)) {
12508  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
12509  exitLoop = MA_TRUE;
12510  break;
12511  }
12512 
12513 
12514  /* Overrun detection. */
12515  if ((flagsCapture & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) {
12516  /* Glitched. Probably due to an overrun. */
12517  #ifdef MA_DEBUG_OUTPUT
12518  printf("[WASAPI] Data discontinuity (possible overrun). framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
12519  #endif
12520 
12521  /*
12522  Exeriment: If we get an overrun it probably means we're straddling the end of the buffer. In order to prevent a never-ending sequence of glitches let's experiment
12523  by dropping every frame until we're left with only a single period. To do this we just keep retrieving and immediately releasing buffers until we're down to the
12524  last period.
12525  */
12526  if (framesAvailableCapture >= pDevice->wasapi.actualPeriodSizeInFramesCapture) {
12527  #ifdef MA_DEBUG_OUTPUT
12528  printf("[WASAPI] Synchronizing capture stream. ");
12529  #endif
12530  do
12531  {
12532  hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
12533  if (FAILED(hr)) {
12534  break;
12535  }
12536 
12537  framesAvailableCapture -= mappedDeviceBufferSizeInFramesCapture;
12538 
12539  if (framesAvailableCapture > 0) {
12540  mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture);
12541  hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
12542  if (FAILED(hr)) {
12543  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
12544  exitLoop = MA_TRUE;
12545  break;
12546  }
12547  } else {
12548  pMappedDeviceBufferCapture = NULL;
12549  mappedDeviceBufferSizeInFramesCapture = 0;
12550  }
12551  } while (framesAvailableCapture > periodSizeInFramesCapture);
12552  #ifdef MA_DEBUG_OUTPUT
12553  printf("framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
12554  #endif
12555  }
12556  } else {
12557  #ifdef MA_DEBUG_OUTPUT
12558  if (flagsCapture != 0) {
12559  printf("[WASAPI] Capture Flags: %d\n", flagsCapture);
12560  }
12561  #endif
12562  }
12563 
12564  mappedDeviceBufferFramesRemainingCapture = mappedDeviceBufferSizeInFramesCapture;
12565  }
12566 
12567 
12568  /* At this point we should have both input and output data available. We now need to convert the data and post it to the client. */
12569  for (;;) {
12570  BYTE* pRunningDeviceBufferCapture;
12571  BYTE* pRunningDeviceBufferPlayback;
12572  ma_uint32 framesToProcess;
12573  ma_uint32 framesProcessed;
12574 
12575  pRunningDeviceBufferCapture = pMappedDeviceBufferCapture + ((mappedDeviceBufferSizeInFramesCapture - mappedDeviceBufferFramesRemainingCapture ) * bpfCaptureDevice);
12576  pRunningDeviceBufferPlayback = pMappedDeviceBufferPlayback + ((mappedDeviceBufferSizeInFramesPlayback - mappedDeviceBufferFramesRemainingPlayback) * bpfPlaybackDevice);
12577 
12578  /* There may be some data sitting in the converter that needs to be processed first. Once this is exhaused, run the data callback again. */
12579  if (!pDevice->playback.converter.isPassthrough && outputDataInClientFormatConsumed < outputDataInClientFormatCount) {
12580  ma_uint64 convertedFrameCountClient = (outputDataInClientFormatCount - outputDataInClientFormatConsumed);
12581  ma_uint64 convertedFrameCountDevice = mappedDeviceBufferFramesRemainingPlayback;
12582  void* pConvertedFramesClient = outputDataInClientFormat + (outputDataInClientFormatConsumed * bpfPlaybackClient);
12583  void* pConvertedFramesDevice = pRunningDeviceBufferPlayback;
12584  result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pConvertedFramesClient, &convertedFrameCountClient, pConvertedFramesDevice, &convertedFrameCountDevice);
12585  if (result != MA_SUCCESS) {
12586  break;
12587  }
12588 
12589  outputDataInClientFormatConsumed += (ma_uint32)convertedFrameCountClient; /* Safe cast. */
12590  mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)convertedFrameCountDevice; /* Safe cast. */
12591 
12592  if (mappedDeviceBufferFramesRemainingPlayback == 0) {
12593  break;
12594  }
12595  }
12596 
12597  /*
12598  Getting here means we need to fire the callback. If format conversion is unnecessary, we can optimize this by passing the pointers to the internal
12599  buffers directly to the callback.
12600  */
12601  if (pDevice->capture.converter.isPassthrough && pDevice->playback.converter.isPassthrough) {
12602  /* Optimal path. We can pass mapped pointers directly to the callback. */
12603  framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, mappedDeviceBufferFramesRemainingPlayback);
12604  framesProcessed = framesToProcess;
12605 
12606  ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, pRunningDeviceBufferCapture, framesToProcess);
12607 
12608  mappedDeviceBufferFramesRemainingCapture -= framesProcessed;
12609  mappedDeviceBufferFramesRemainingPlayback -= framesProcessed;
12610 
12611  if (mappedDeviceBufferFramesRemainingCapture == 0) {
12612  break; /* Exhausted input data. */
12613  }
12614  if (mappedDeviceBufferFramesRemainingPlayback == 0) {
12615  break; /* Exhausted output data. */
12616  }
12617  } else if (pDevice->capture.converter.isPassthrough) {
12618  /* The input buffer is a passthrough, but the playback buffer requires a conversion. */
12619  framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, outputDataInClientFormatCap);
12620  framesProcessed = framesToProcess;
12621 
12622  ma_device__on_data(pDevice, outputDataInClientFormat, pRunningDeviceBufferCapture, framesToProcess);
12623  outputDataInClientFormatCount = framesProcessed;
12624  outputDataInClientFormatConsumed = 0;
12625 
12626  mappedDeviceBufferFramesRemainingCapture -= framesProcessed;
12627  if (mappedDeviceBufferFramesRemainingCapture == 0) {
12628  break; /* Exhausted input data. */
12629  }
12630  } else if (pDevice->playback.converter.isPassthrough) {
12631  /* The input buffer requires conversion, the playback buffer is passthrough. */
12632  ma_uint64 capturedDeviceFramesToProcess = mappedDeviceBufferFramesRemainingCapture;
12633  ma_uint64 capturedClientFramesToProcess = ma_min(inputDataInClientFormatCap, mappedDeviceBufferFramesRemainingPlayback);
12634 
12635  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningDeviceBufferCapture, &capturedDeviceFramesToProcess, inputDataInClientFormat, &capturedClientFramesToProcess);
12636  if (result != MA_SUCCESS) {
12637  break;
12638  }
12639 
12640  if (capturedClientFramesToProcess == 0) {
12641  break;
12642  }
12643 
12644  ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess); /* Safe cast. */
12645 
12646  mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess;
12647  mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)capturedClientFramesToProcess;
12648  } else {
12649  ma_uint64 capturedDeviceFramesToProcess = mappedDeviceBufferFramesRemainingCapture;
12650  ma_uint64 capturedClientFramesToProcess = ma_min(inputDataInClientFormatCap, outputDataInClientFormatCap);
12651 
12652  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningDeviceBufferCapture, &capturedDeviceFramesToProcess, inputDataInClientFormat, &capturedClientFramesToProcess);
12653  if (result != MA_SUCCESS) {
12654  break;
12655  }
12656 
12657  if (capturedClientFramesToProcess == 0) {
12658  break;
12659  }
12660 
12661  ma_device__on_data(pDevice, outputDataInClientFormat, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess);
12662 
12663  mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess;
12664  outputDataInClientFormatCount = (ma_uint32)capturedClientFramesToProcess;
12665  outputDataInClientFormatConsumed = 0;
12666  }
12667  }
12668 
12669 
12670  /* If at this point we've run out of capture data we need to release the buffer. */
12671  if (mappedDeviceBufferFramesRemainingCapture == 0 && pMappedDeviceBufferCapture != NULL) {
12672  hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
12673  if (FAILED(hr)) {
12674  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr));
12675  exitLoop = MA_TRUE;
12676  break;
12677  }
12678 
12679  /*printf("TRACE: Released capture buffer\n");*/
12680 
12681  pMappedDeviceBufferCapture = NULL;
12682  mappedDeviceBufferFramesRemainingCapture = 0;
12683  mappedDeviceBufferSizeInFramesCapture = 0;
12684  }
12685 
12686  /* Get out of this loop if we're run out of room in the playback buffer. */
12687  if (mappedDeviceBufferFramesRemainingPlayback == 0) {
12688  break;
12689  }
12690  }
12691 
12692 
12693  /* If at this point we've run out of data we need to release the buffer. */
12694  if (mappedDeviceBufferFramesRemainingPlayback == 0 && pMappedDeviceBufferPlayback != NULL) {
12695  hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedDeviceBufferSizeInFramesPlayback, 0);
12696  if (FAILED(hr)) {
12697  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
12698  exitLoop = MA_TRUE;
12699  break;
12700  }
12701 
12702  /*printf("TRACE: Released playback buffer\n");*/
12703  framesWrittenToPlaybackDevice += mappedDeviceBufferSizeInFramesPlayback;
12704 
12705  pMappedDeviceBufferPlayback = NULL;
12706  mappedDeviceBufferFramesRemainingPlayback = 0;
12707  mappedDeviceBufferSizeInFramesPlayback = 0;
12708  }
12709 
12710  if (!pDevice->wasapi.isStartedPlayback) {
12711  ma_uint32 startThreshold = pDevice->playback.internalPeriodSizeInFrames * 1;
12712 
12713  /* Prevent a deadlock. If we don't clamp against the actual buffer size we'll never end up starting the playback device which will result in a deadlock. */
12714  if (startThreshold > pDevice->wasapi.actualPeriodSizeInFramesPlayback) {
12715  startThreshold = pDevice->wasapi.actualPeriodSizeInFramesPlayback;
12716  }
12717 
12718  if (pDevice->playback.shareMode == ma_share_mode_exclusive || framesWrittenToPlaybackDevice >= startThreshold) {
12719  hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
12720  if (FAILED(hr)) {
12721  ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
12722  ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
12723  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", ma_result_from_HRESULT(hr));
12724  }
12725  ma_atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE);
12726  }
12727  }
12728  } break;
12729 
12730 
12731 
12734  {
12735  ma_uint32 framesAvailableCapture;
12736  DWORD flagsCapture; /* Passed to IAudioCaptureClient_GetBuffer(). */
12737 
12738  /* Wait for data to become available first. */
12739  if (WaitForSingleObject(pDevice->wasapi.hEventCapture, INFINITE) == WAIT_FAILED) {
12740  exitLoop = MA_TRUE;
12741  break; /* Wait failed. */
12742  }
12743 
12744  /* See how many frames are available. Since we waited at the top, I don't think this should ever return 0. I'm checking for this anyway. */
12745  result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture);
12746  if (result != MA_SUCCESS) {
12747  exitLoop = MA_TRUE;
12748  break;
12749  }
12750 
12751  if (framesAvailableCapture < pDevice->wasapi.periodSizeInFramesCapture) {
12752  continue; /* Nothing available. Keep waiting. */
12753  }
12754 
12755  /* Map the data buffer in preparation for sending to the client. */
12756  mappedDeviceBufferSizeInFramesCapture = framesAvailableCapture;
12757  hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
12758  if (FAILED(hr)) {
12759  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
12760  exitLoop = MA_TRUE;
12761  break;
12762  }
12763 
12764  /* We should have a buffer at this point. */
12765  ma_device__send_frames_to_client(pDevice, mappedDeviceBufferSizeInFramesCapture, pMappedDeviceBufferCapture);
12766 
12767  /* At this point we're done with the buffer. */
12768  hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
12769  pMappedDeviceBufferCapture = NULL; /* <-- Important. Not doing this can result in an error once we leave this loop because it will use this to know whether or not a final ReleaseBuffer() needs to be called. */
12770  mappedDeviceBufferSizeInFramesCapture = 0;
12771  if (FAILED(hr)) {
12772  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr));
12773  exitLoop = MA_TRUE;
12774  break;
12775  }
12776  } break;
12777 
12778 
12779 
12781  {
12782  ma_uint32 framesAvailablePlayback;
12783 
12784  /* Wait for space to become available first. */
12785  if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE) == WAIT_FAILED) {
12786  exitLoop = MA_TRUE;
12787  break; /* Wait failed. */
12788  }
12789 
12790  /* Check how much space is available. If this returns 0 we just keep waiting. */
12791  result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback);
12792  if (result != MA_SUCCESS) {
12793  exitLoop = MA_TRUE;
12794  break;
12795  }
12796 
12797  if (framesAvailablePlayback < pDevice->wasapi.periodSizeInFramesPlayback) {
12798  continue; /* No space available. */
12799  }
12800 
12801  /* Map a the data buffer in preparation for the callback. */
12802  hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedDeviceBufferPlayback);
12803  if (FAILED(hr)) {
12804  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
12805  exitLoop = MA_TRUE;
12806  break;
12807  }
12808 
12809  /* We should have a buffer at this point. */
12810  ma_device__read_frames_from_client(pDevice, framesAvailablePlayback, pMappedDeviceBufferPlayback);
12811 
12812  /* At this point we're done writing to the device and we just need to release the buffer. */
12813  hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, 0);
12814  pMappedDeviceBufferPlayback = NULL; /* <-- Important. Not doing this can result in an error once we leave this loop because it will use this to know whether or not a final ReleaseBuffer() needs to be called. */
12815  mappedDeviceBufferSizeInFramesPlayback = 0;
12816 
12817  if (FAILED(hr)) {
12818  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
12819  exitLoop = MA_TRUE;
12820  break;
12821  }
12822 
12823  framesWrittenToPlaybackDevice += framesAvailablePlayback;
12824  if (!pDevice->wasapi.isStartedPlayback) {
12825  if (pDevice->playback.shareMode == ma_share_mode_exclusive || framesWrittenToPlaybackDevice >= pDevice->playback.internalPeriodSizeInFrames*1) {
12826  hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
12827  if (FAILED(hr)) {
12828  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", ma_result_from_HRESULT(hr));
12829  exitLoop = MA_TRUE;
12830  break;
12831  }
12832  ma_atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE);
12833  }
12834  }
12835  } break;
12836 
12837  default: return MA_INVALID_ARGS;
12838  }
12839  }
12840 
12841  /* Here is where the device needs to be stopped. */
12842  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
12843  /* Any mapped buffers need to be released. */
12844  if (pMappedDeviceBufferCapture != NULL) {
12845  hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
12846  }
12847 
12848  hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
12849  if (FAILED(hr)) {
12850  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device.", ma_result_from_HRESULT(hr));
12851  }
12852 
12853  /* The audio client needs to be reset otherwise restarting will fail. */
12854  hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
12855  if (FAILED(hr)) {
12856  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal capture device.", ma_result_from_HRESULT(hr));
12857  }
12858 
12859  ma_atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_FALSE);
12860  }
12861 
12862  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
12863  /* Any mapped buffers need to be released. */
12864  if (pMappedDeviceBufferPlayback != NULL) {
12865  hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedDeviceBufferSizeInFramesPlayback, 0);
12866  }
12867 
12868  /*
12869  The buffer needs to be drained before stopping the device. Not doing this will result in the last few frames not getting output to
12870  the speakers. This is a problem for very short sounds because it'll result in a significant portion of it not getting played.
12871  */
12872  if (pDevice->wasapi.isStartedPlayback) {
12873  if (pDevice->playback.shareMode == ma_share_mode_exclusive) {
12874  WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE);
12875  } else {
12876  ma_uint32 prevFramesAvaialablePlayback = (ma_uint32)-1;
12877  ma_uint32 framesAvailablePlayback;
12878  for (;;) {
12879  result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback);
12880  if (result != MA_SUCCESS) {
12881  break;
12882  }
12883 
12884  if (framesAvailablePlayback >= pDevice->wasapi.actualPeriodSizeInFramesPlayback) {
12885  break;
12886  }
12887 
12888  /*
12889  Just a safety check to avoid an infinite loop. If this iteration results in a situation where the number of available frames
12890  has not changed, get out of the loop. I don't think this should ever happen, but I think it's nice to have just in case.
12891  */
12892  if (framesAvailablePlayback == prevFramesAvaialablePlayback) {
12893  break;
12894  }
12895  prevFramesAvaialablePlayback = framesAvailablePlayback;
12896 
12897  WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE);
12898  ResetEvent(pDevice->wasapi.hEventPlayback); /* Manual reset. */
12899  }
12900  }
12901  }
12902 
12903  hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
12904  if (FAILED(hr)) {
12905  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal playback device.", ma_result_from_HRESULT(hr));
12906  }
12907 
12908  /* The audio client needs to be reset otherwise restarting will fail. */
12909  hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
12910  if (FAILED(hr)) {
12911  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal playback device.", ma_result_from_HRESULT(hr));
12912  }
12913 
12914  ma_atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE);
12915  }
12916 
12917  return MA_SUCCESS;
12918 }
12919 
12920 static ma_result ma_context_uninit__wasapi(ma_context* pContext)
12921 {
12922  MA_ASSERT(pContext != NULL);
12923  MA_ASSERT(pContext->backend == ma_backend_wasapi);
12924  (void)pContext;
12925 
12926  return MA_SUCCESS;
12927 }
12928 
12929 static ma_result ma_context_init__wasapi(const ma_context_config* pConfig, ma_context* pContext)
12930 {
12931  ma_result result = MA_SUCCESS;
12932 
12933  MA_ASSERT(pContext != NULL);
12934 
12935  (void)pConfig;
12936 
12937 #ifdef MA_WIN32_DESKTOP
12938  /*
12939  WASAPI is only supported in Vista SP1 and newer. The reason for SP1 and not the base version of Vista is that event-driven
12940  exclusive mode does not work until SP1.
12941 
12942  Unfortunately older compilers don't define these functions so we need to dynamically load them in order to avoid a lin error.
12943  */
12944  {
12945  ma_OSVERSIONINFOEXW osvi;
12946  ma_handle kernel32DLL;
12947  ma_PFNVerifyVersionInfoW _VerifyVersionInfoW;
12948  ma_PFNVerSetConditionMask _VerSetConditionMask;
12949 
12950  kernel32DLL = ma_dlopen(pContext, "kernel32.dll");
12951  if (kernel32DLL == NULL) {
12952  return MA_NO_BACKEND;
12953  }
12954 
12955  _VerifyVersionInfoW = (ma_PFNVerifyVersionInfoW)ma_dlsym(pContext, kernel32DLL, "VerifyVersionInfoW");
12956  _VerSetConditionMask = (ma_PFNVerSetConditionMask)ma_dlsym(pContext, kernel32DLL, "VerSetConditionMask");
12957  if (_VerifyVersionInfoW == NULL || _VerSetConditionMask == NULL) {
12958  ma_dlclose(pContext, kernel32DLL);
12959  return MA_NO_BACKEND;
12960  }
12961 
12962  MA_ZERO_OBJECT(&osvi);
12963  osvi.dwOSVersionInfoSize = sizeof(osvi);
12964  osvi.dwMajorVersion = HIBYTE(MA_WIN32_WINNT_VISTA);
12965  osvi.dwMinorVersion = LOBYTE(MA_WIN32_WINNT_VISTA);
12966  osvi.wServicePackMajor = 1;
12967  if (_VerifyVersionInfoW(&osvi, MA_VER_MAJORVERSION | MA_VER_MINORVERSION | MA_VER_SERVICEPACKMAJOR, _VerSetConditionMask(_VerSetConditionMask(_VerSetConditionMask(0, MA_VER_MAJORVERSION, MA_VER_GREATER_EQUAL), MA_VER_MINORVERSION, MA_VER_GREATER_EQUAL), MA_VER_SERVICEPACKMAJOR, MA_VER_GREATER_EQUAL))) {
12968  result = MA_SUCCESS;
12969  } else {
12970  result = MA_NO_BACKEND;
12971  }
12972 
12973  ma_dlclose(pContext, kernel32DLL);
12974  }
12975 #endif
12976 
12977  if (result != MA_SUCCESS) {
12978  return result;
12979  }
12980 
12981  pContext->onUninit = ma_context_uninit__wasapi;
12982  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__wasapi;
12983  pContext->onEnumDevices = ma_context_enumerate_devices__wasapi;
12984  pContext->onGetDeviceInfo = ma_context_get_device_info__wasapi;
12985  pContext->onDeviceInit = ma_device_init__wasapi;
12986  pContext->onDeviceUninit = ma_device_uninit__wasapi;
12987  pContext->onDeviceStart = NULL; /* Not used. Started in onDeviceMainLoop. */
12988  pContext->onDeviceStop = ma_device_stop__wasapi; /* Required to ensure the capture event is signalled when stopping a loopback device while nothing is playing. */
12989  pContext->onDeviceMainLoop = ma_device_main_loop__wasapi;
12990 
12991  return result;
12992 }
12993 #endif
12994 
12995 /******************************************************************************
12996 
12997 DirectSound Backend
12998 
12999 ******************************************************************************/
13000 #ifdef MA_HAS_DSOUND
13001 /*#include <dsound.h>*/
13002 
13003 static const GUID MA_GUID_IID_DirectSoundNotify = {0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}};
13004 
13005 /* miniaudio only uses priority or exclusive modes. */
13006 #define MA_DSSCL_NORMAL 1
13007 #define MA_DSSCL_PRIORITY 2
13008 #define MA_DSSCL_EXCLUSIVE 3
13009 #define MA_DSSCL_WRITEPRIMARY 4
13010 
13011 #define MA_DSCAPS_PRIMARYMONO 0x00000001
13012 #define MA_DSCAPS_PRIMARYSTEREO 0x00000002
13013 #define MA_DSCAPS_PRIMARY8BIT 0x00000004
13014 #define MA_DSCAPS_PRIMARY16BIT 0x00000008
13015 #define MA_DSCAPS_CONTINUOUSRATE 0x00000010
13016 #define MA_DSCAPS_EMULDRIVER 0x00000020
13017 #define MA_DSCAPS_CERTIFIED 0x00000040
13018 #define MA_DSCAPS_SECONDARYMONO 0x00000100
13019 #define MA_DSCAPS_SECONDARYSTEREO 0x00000200
13020 #define MA_DSCAPS_SECONDARY8BIT 0x00000400
13021 #define MA_DSCAPS_SECONDARY16BIT 0x00000800
13022 
13023 #define MA_DSBCAPS_PRIMARYBUFFER 0x00000001
13024 #define MA_DSBCAPS_STATIC 0x00000002
13025 #define MA_DSBCAPS_LOCHARDWARE 0x00000004
13026 #define MA_DSBCAPS_LOCSOFTWARE 0x00000008
13027 #define MA_DSBCAPS_CTRL3D 0x00000010
13028 #define MA_DSBCAPS_CTRLFREQUENCY 0x00000020
13029 #define MA_DSBCAPS_CTRLPAN 0x00000040
13030 #define MA_DSBCAPS_CTRLVOLUME 0x00000080
13031 #define MA_DSBCAPS_CTRLPOSITIONNOTIFY 0x00000100
13032 #define MA_DSBCAPS_CTRLFX 0x00000200
13033 #define MA_DSBCAPS_STICKYFOCUS 0x00004000
13034 #define MA_DSBCAPS_GLOBALFOCUS 0x00008000
13035 #define MA_DSBCAPS_GETCURRENTPOSITION2 0x00010000
13036 #define MA_DSBCAPS_MUTE3DATMAXDISTANCE 0x00020000
13037 #define MA_DSBCAPS_LOCDEFER 0x00040000
13038 #define MA_DSBCAPS_TRUEPLAYPOSITION 0x00080000
13039 
13040 #define MA_DSBPLAY_LOOPING 0x00000001
13041 #define MA_DSBPLAY_LOCHARDWARE 0x00000002
13042 #define MA_DSBPLAY_LOCSOFTWARE 0x00000004
13043 #define MA_DSBPLAY_TERMINATEBY_TIME 0x00000008
13044 #define MA_DSBPLAY_TERMINATEBY_DISTANCE 0x00000010
13045 #define MA_DSBPLAY_TERMINATEBY_PRIORITY 0x00000020
13046 
13047 #define MA_DSCBSTART_LOOPING 0x00000001
13048 
13049 typedef struct
13050 {
13051  DWORD dwSize;
13052  DWORD dwFlags;
13053  DWORD dwBufferBytes;
13054  DWORD dwReserved;
13055  WAVEFORMATEX* lpwfxFormat;
13056  GUID guid3DAlgorithm;
13057 } MA_DSBUFFERDESC;
13058 
13059 typedef struct
13060 {
13061  DWORD dwSize;
13062  DWORD dwFlags;
13063  DWORD dwBufferBytes;
13064  DWORD dwReserved;
13065  WAVEFORMATEX* lpwfxFormat;
13066  DWORD dwFXCount;
13067  void* lpDSCFXDesc; /* <-- miniaudio doesn't use this, so set to void*. */
13068 } MA_DSCBUFFERDESC;
13069 
13070 typedef struct
13071 {
13072  DWORD dwSize;
13073  DWORD dwFlags;
13074  DWORD dwMinSecondarySampleRate;
13075  DWORD dwMaxSecondarySampleRate;
13076  DWORD dwPrimaryBuffers;
13077  DWORD dwMaxHwMixingAllBuffers;
13078  DWORD dwMaxHwMixingStaticBuffers;
13079  DWORD dwMaxHwMixingStreamingBuffers;
13080  DWORD dwFreeHwMixingAllBuffers;
13081  DWORD dwFreeHwMixingStaticBuffers;
13082  DWORD dwFreeHwMixingStreamingBuffers;
13083  DWORD dwMaxHw3DAllBuffers;
13084  DWORD dwMaxHw3DStaticBuffers;
13085  DWORD dwMaxHw3DStreamingBuffers;
13086  DWORD dwFreeHw3DAllBuffers;
13087  DWORD dwFreeHw3DStaticBuffers;
13088  DWORD dwFreeHw3DStreamingBuffers;
13089  DWORD dwTotalHwMemBytes;
13090  DWORD dwFreeHwMemBytes;
13091  DWORD dwMaxContigFreeHwMemBytes;
13092  DWORD dwUnlockTransferRateHwBuffers;
13093  DWORD dwPlayCpuOverheadSwBuffers;
13094  DWORD dwReserved1;
13095  DWORD dwReserved2;
13096 } MA_DSCAPS;
13097 
13098 typedef struct
13099 {
13100  DWORD dwSize;
13101  DWORD dwFlags;
13102  DWORD dwBufferBytes;
13103  DWORD dwUnlockTransferRate;
13104  DWORD dwPlayCpuOverhead;
13105 } MA_DSBCAPS;
13106 
13107 typedef struct
13108 {
13109  DWORD dwSize;
13110  DWORD dwFlags;
13111  DWORD dwFormats;
13112  DWORD dwChannels;
13113 } MA_DSCCAPS;
13114 
13115 typedef struct
13116 {
13117  DWORD dwSize;
13118  DWORD dwFlags;
13119  DWORD dwBufferBytes;
13120  DWORD dwReserved;
13121 } MA_DSCBCAPS;
13122 
13123 typedef struct
13124 {
13125  DWORD dwOffset;
13126  HANDLE hEventNotify;
13127 } MA_DSBPOSITIONNOTIFY;
13128 
13129 typedef struct ma_IDirectSound ma_IDirectSound;
13130 typedef struct ma_IDirectSoundBuffer ma_IDirectSoundBuffer;
13131 typedef struct ma_IDirectSoundCapture ma_IDirectSoundCapture;
13132 typedef struct ma_IDirectSoundCaptureBuffer ma_IDirectSoundCaptureBuffer;
13133 typedef struct ma_IDirectSoundNotify ma_IDirectSoundNotify;
13134 
13135 
13136 /*
13137 COM objects. The way these work is that you have a vtable (a list of function pointers, kind of
13138 like how C++ works internally), and then you have a structure with a single member, which is a
13139 pointer to the vtable. The vtable is where the methods of the object are defined. Methods need
13140 to be in a specific order, and parent classes need to have their methods declared first.
13141 */
13142 
13143 /* IDirectSound */
13144 typedef struct
13145 {
13146  /* IUnknown */
13147  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSound* pThis, const IID* const riid, void** ppObject);
13148  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSound* pThis);
13149  ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSound* pThis);
13150 
13151  /* IDirectSound */
13152  HRESULT (STDMETHODCALLTYPE * CreateSoundBuffer) (ma_IDirectSound* pThis, const MA_DSBUFFERDESC* pDSBufferDesc, ma_IDirectSoundBuffer** ppDSBuffer, void* pUnkOuter);
13153  HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSound* pThis, MA_DSCAPS* pDSCaps);
13154  HRESULT (STDMETHODCALLTYPE * DuplicateSoundBuffer)(ma_IDirectSound* pThis, ma_IDirectSoundBuffer* pDSBufferOriginal, ma_IDirectSoundBuffer** ppDSBufferDuplicate);
13155  HRESULT (STDMETHODCALLTYPE * SetCooperativeLevel) (ma_IDirectSound* pThis, HWND hwnd, DWORD dwLevel);
13156  HRESULT (STDMETHODCALLTYPE * Compact) (ma_IDirectSound* pThis);
13157  HRESULT (STDMETHODCALLTYPE * GetSpeakerConfig) (ma_IDirectSound* pThis, DWORD* pSpeakerConfig);
13158  HRESULT (STDMETHODCALLTYPE * SetSpeakerConfig) (ma_IDirectSound* pThis, DWORD dwSpeakerConfig);
13159  HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSound* pThis, const GUID* pGuidDevice);
13160 } ma_IDirectSoundVtbl;
13161 struct ma_IDirectSound
13162 {
13163  ma_IDirectSoundVtbl* lpVtbl;
13164 };
13165 static MA_INLINE HRESULT ma_IDirectSound_QueryInterface(ma_IDirectSound* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13166 static MA_INLINE ULONG ma_IDirectSound_AddRef(ma_IDirectSound* pThis) { return pThis->lpVtbl->AddRef(pThis); }
13167 static MA_INLINE ULONG ma_IDirectSound_Release(ma_IDirectSound* pThis) { return pThis->lpVtbl->Release(pThis); }
13168 static MA_INLINE HRESULT ma_IDirectSound_CreateSoundBuffer(ma_IDirectSound* pThis, const MA_DSBUFFERDESC* pDSBufferDesc, ma_IDirectSoundBuffer** ppDSBuffer, void* pUnkOuter) { return pThis->lpVtbl->CreateSoundBuffer(pThis, pDSBufferDesc, ppDSBuffer, pUnkOuter); }
13169 static MA_INLINE HRESULT ma_IDirectSound_GetCaps(ma_IDirectSound* pThis, MA_DSCAPS* pDSCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSCaps); }
13170 static MA_INLINE HRESULT ma_IDirectSound_DuplicateSoundBuffer(ma_IDirectSound* pThis, ma_IDirectSoundBuffer* pDSBufferOriginal, ma_IDirectSoundBuffer** ppDSBufferDuplicate) { return pThis->lpVtbl->DuplicateSoundBuffer(pThis, pDSBufferOriginal, ppDSBufferDuplicate); }
13171 static MA_INLINE HRESULT ma_IDirectSound_SetCooperativeLevel(ma_IDirectSound* pThis, HWND hwnd, DWORD dwLevel) { return pThis->lpVtbl->SetCooperativeLevel(pThis, hwnd, dwLevel); }
13172 static MA_INLINE HRESULT ma_IDirectSound_Compact(ma_IDirectSound* pThis) { return pThis->lpVtbl->Compact(pThis); }
13173 static MA_INLINE HRESULT ma_IDirectSound_GetSpeakerConfig(ma_IDirectSound* pThis, DWORD* pSpeakerConfig) { return pThis->lpVtbl->GetSpeakerConfig(pThis, pSpeakerConfig); }
13174 static MA_INLINE HRESULT ma_IDirectSound_SetSpeakerConfig(ma_IDirectSound* pThis, DWORD dwSpeakerConfig) { return pThis->lpVtbl->SetSpeakerConfig(pThis, dwSpeakerConfig); }
13175 static MA_INLINE HRESULT ma_IDirectSound_Initialize(ma_IDirectSound* pThis, const GUID* pGuidDevice) { return pThis->lpVtbl->Initialize(pThis, pGuidDevice); }
13176 
13177 
13178 /* IDirectSoundBuffer */
13179 typedef struct
13180 {
13181  /* IUnknown */
13182  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundBuffer* pThis, const IID* const riid, void** ppObject);
13183  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundBuffer* pThis);
13184  ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundBuffer* pThis);
13185 
13186  /* IDirectSoundBuffer */
13187  HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSoundBuffer* pThis, MA_DSBCAPS* pDSBufferCaps);
13188  HRESULT (STDMETHODCALLTYPE * GetCurrentPosition)(ma_IDirectSoundBuffer* pThis, DWORD* pCurrentPlayCursor, DWORD* pCurrentWriteCursor);
13189  HRESULT (STDMETHODCALLTYPE * GetFormat) (ma_IDirectSoundBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten);
13190  HRESULT (STDMETHODCALLTYPE * GetVolume) (ma_IDirectSoundBuffer* pThis, LONG* pVolume);
13191  HRESULT (STDMETHODCALLTYPE * GetPan) (ma_IDirectSoundBuffer* pThis, LONG* pPan);
13192  HRESULT (STDMETHODCALLTYPE * GetFrequency) (ma_IDirectSoundBuffer* pThis, DWORD* pFrequency);
13193  HRESULT (STDMETHODCALLTYPE * GetStatus) (ma_IDirectSoundBuffer* pThis, DWORD* pStatus);
13194  HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSoundBuffer* pThis, ma_IDirectSound* pDirectSound, const MA_DSBUFFERDESC* pDSBufferDesc);
13195  HRESULT (STDMETHODCALLTYPE * Lock) (ma_IDirectSoundBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags);
13196  HRESULT (STDMETHODCALLTYPE * Play) (ma_IDirectSoundBuffer* pThis, DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags);
13197  HRESULT (STDMETHODCALLTYPE * SetCurrentPosition)(ma_IDirectSoundBuffer* pThis, DWORD dwNewPosition);
13198  HRESULT (STDMETHODCALLTYPE * SetFormat) (ma_IDirectSoundBuffer* pThis, const WAVEFORMATEX* pFormat);
13199  HRESULT (STDMETHODCALLTYPE * SetVolume) (ma_IDirectSoundBuffer* pThis, LONG volume);
13200  HRESULT (STDMETHODCALLTYPE * SetPan) (ma_IDirectSoundBuffer* pThis, LONG pan);
13201  HRESULT (STDMETHODCALLTYPE * SetFrequency) (ma_IDirectSoundBuffer* pThis, DWORD dwFrequency);
13202  HRESULT (STDMETHODCALLTYPE * Stop) (ma_IDirectSoundBuffer* pThis);
13203  HRESULT (STDMETHODCALLTYPE * Unlock) (ma_IDirectSoundBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2);
13204  HRESULT (STDMETHODCALLTYPE * Restore) (ma_IDirectSoundBuffer* pThis);
13205 } ma_IDirectSoundBufferVtbl;
13206 struct ma_IDirectSoundBuffer
13207 {
13208  ma_IDirectSoundBufferVtbl* lpVtbl;
13209 };
13210 static MA_INLINE HRESULT ma_IDirectSoundBuffer_QueryInterface(ma_IDirectSoundBuffer* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13211 static MA_INLINE ULONG ma_IDirectSoundBuffer_AddRef(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->AddRef(pThis); }
13212 static MA_INLINE ULONG ma_IDirectSoundBuffer_Release(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->Release(pThis); }
13213 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetCaps(ma_IDirectSoundBuffer* pThis, MA_DSBCAPS* pDSBufferCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSBufferCaps); }
13214 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetCurrentPosition(ma_IDirectSoundBuffer* pThis, DWORD* pCurrentPlayCursor, DWORD* pCurrentWriteCursor) { return pThis->lpVtbl->GetCurrentPosition(pThis, pCurrentPlayCursor, pCurrentWriteCursor); }
13215 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetFormat(ma_IDirectSoundBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); }
13216 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetVolume(ma_IDirectSoundBuffer* pThis, LONG* pVolume) { return pThis->lpVtbl->GetVolume(pThis, pVolume); }
13217 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetPan(ma_IDirectSoundBuffer* pThis, LONG* pPan) { return pThis->lpVtbl->GetPan(pThis, pPan); }
13218 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetFrequency(ma_IDirectSoundBuffer* pThis, DWORD* pFrequency) { return pThis->lpVtbl->GetFrequency(pThis, pFrequency); }
13219 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetStatus(ma_IDirectSoundBuffer* pThis, DWORD* pStatus) { return pThis->lpVtbl->GetStatus(pThis, pStatus); }
13220 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Initialize(ma_IDirectSoundBuffer* pThis, ma_IDirectSound* pDirectSound, const MA_DSBUFFERDESC* pDSBufferDesc) { return pThis->lpVtbl->Initialize(pThis, pDirectSound, pDSBufferDesc); }
13221 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Lock(ma_IDirectSoundBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags) { return pThis->lpVtbl->Lock(pThis, dwOffset, dwBytes, ppAudioPtr1, pAudioBytes1, ppAudioPtr2, pAudioBytes2, dwFlags); }
13222 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Play(ma_IDirectSoundBuffer* pThis, DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) { return pThis->lpVtbl->Play(pThis, dwReserved1, dwPriority, dwFlags); }
13223 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetCurrentPosition(ma_IDirectSoundBuffer* pThis, DWORD dwNewPosition) { return pThis->lpVtbl->SetCurrentPosition(pThis, dwNewPosition); }
13224 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetFormat(ma_IDirectSoundBuffer* pThis, const WAVEFORMATEX* pFormat) { return pThis->lpVtbl->SetFormat(pThis, pFormat); }
13225 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetVolume(ma_IDirectSoundBuffer* pThis, LONG volume) { return pThis->lpVtbl->SetVolume(pThis, volume); }
13226 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetPan(ma_IDirectSoundBuffer* pThis, LONG pan) { return pThis->lpVtbl->SetPan(pThis, pan); }
13227 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetFrequency(ma_IDirectSoundBuffer* pThis, DWORD dwFrequency) { return pThis->lpVtbl->SetFrequency(pThis, dwFrequency); }
13228 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Stop(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->Stop(pThis); }
13229 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Unlock(ma_IDirectSoundBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2) { return pThis->lpVtbl->Unlock(pThis, pAudioPtr1, dwAudioBytes1, pAudioPtr2, dwAudioBytes2); }
13230 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Restore(ma_IDirectSoundBuffer* pThis) { return pThis->lpVtbl->Restore(pThis); }
13231 
13232 
13233 /* IDirectSoundCapture */
13234 typedef struct
13235 {
13236  /* IUnknown */
13237  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject);
13238  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundCapture* pThis);
13239  ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundCapture* pThis);
13240 
13241  /* IDirectSoundCapture */
13242  HRESULT (STDMETHODCALLTYPE * CreateCaptureBuffer)(ma_IDirectSoundCapture* pThis, const MA_DSCBUFFERDESC* pDSCBufferDesc, ma_IDirectSoundCaptureBuffer** ppDSCBuffer, void* pUnkOuter);
13243  HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSoundCapture* pThis, MA_DSCCAPS* pDSCCaps);
13244  HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSoundCapture* pThis, const GUID* pGuidDevice);
13245 } ma_IDirectSoundCaptureVtbl;
13246 struct ma_IDirectSoundCapture
13247 {
13248  ma_IDirectSoundCaptureVtbl* lpVtbl;
13249 };
13250 static MA_INLINE HRESULT ma_IDirectSoundCapture_QueryInterface(ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13251 static MA_INLINE ULONG ma_IDirectSoundCapture_AddRef(ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->AddRef(pThis); }
13252 static MA_INLINE ULONG ma_IDirectSoundCapture_Release(ma_IDirectSoundCapture* pThis) { return pThis->lpVtbl->Release(pThis); }
13253 static MA_INLINE HRESULT ma_IDirectSoundCapture_CreateCaptureBuffer(ma_IDirectSoundCapture* pThis, const MA_DSCBUFFERDESC* pDSCBufferDesc, ma_IDirectSoundCaptureBuffer** ppDSCBuffer, void* pUnkOuter) { return pThis->lpVtbl->CreateCaptureBuffer(pThis, pDSCBufferDesc, ppDSCBuffer, pUnkOuter); }
13254 static MA_INLINE HRESULT ma_IDirectSoundCapture_GetCaps (ma_IDirectSoundCapture* pThis, MA_DSCCAPS* pDSCCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSCCaps); }
13255 static MA_INLINE HRESULT ma_IDirectSoundCapture_Initialize (ma_IDirectSoundCapture* pThis, const GUID* pGuidDevice) { return pThis->lpVtbl->Initialize(pThis, pGuidDevice); }
13256 
13257 
13258 /* IDirectSoundCaptureBuffer */
13259 typedef struct
13260 {
13261  /* IUnknown */
13262  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundCaptureBuffer* pThis, const IID* const riid, void** ppObject);
13263  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundCaptureBuffer* pThis);
13264  ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundCaptureBuffer* pThis);
13265 
13266  /* IDirectSoundCaptureBuffer */
13267  HRESULT (STDMETHODCALLTYPE * GetCaps) (ma_IDirectSoundCaptureBuffer* pThis, MA_DSCBCAPS* pDSCBCaps);
13268  HRESULT (STDMETHODCALLTYPE * GetCurrentPosition)(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pCapturePosition, DWORD* pReadPosition);
13269  HRESULT (STDMETHODCALLTYPE * GetFormat) (ma_IDirectSoundCaptureBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten);
13270  HRESULT (STDMETHODCALLTYPE * GetStatus) (ma_IDirectSoundCaptureBuffer* pThis, DWORD* pStatus);
13271  HRESULT (STDMETHODCALLTYPE * Initialize) (ma_IDirectSoundCaptureBuffer* pThis, ma_IDirectSoundCapture* pDirectSoundCapture, const MA_DSCBUFFERDESC* pDSCBufferDesc);
13272  HRESULT (STDMETHODCALLTYPE * Lock) (ma_IDirectSoundCaptureBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags);
13273  HRESULT (STDMETHODCALLTYPE * Start) (ma_IDirectSoundCaptureBuffer* pThis, DWORD dwFlags);
13274  HRESULT (STDMETHODCALLTYPE * Stop) (ma_IDirectSoundCaptureBuffer* pThis);
13275  HRESULT (STDMETHODCALLTYPE * Unlock) (ma_IDirectSoundCaptureBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2);
13276 } ma_IDirectSoundCaptureBufferVtbl;
13277 struct ma_IDirectSoundCaptureBuffer
13278 {
13279  ma_IDirectSoundCaptureBufferVtbl* lpVtbl;
13280 };
13281 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_QueryInterface(ma_IDirectSoundCaptureBuffer* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13282 static MA_INLINE ULONG ma_IDirectSoundCaptureBuffer_AddRef(ma_IDirectSoundCaptureBuffer* pThis) { return pThis->lpVtbl->AddRef(pThis); }
13283 static MA_INLINE ULONG ma_IDirectSoundCaptureBuffer_Release(ma_IDirectSoundCaptureBuffer* pThis) { return pThis->lpVtbl->Release(pThis); }
13284 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetCaps(ma_IDirectSoundCaptureBuffer* pThis, MA_DSCBCAPS* pDSCBCaps) { return pThis->lpVtbl->GetCaps(pThis, pDSCBCaps); }
13285 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetCurrentPosition(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pCapturePosition, DWORD* pReadPosition) { return pThis->lpVtbl->GetCurrentPosition(pThis, pCapturePosition, pReadPosition); }
13286 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetFormat(ma_IDirectSoundCaptureBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); }
13287 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetStatus(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pStatus) { return pThis->lpVtbl->GetStatus(pThis, pStatus); }
13288 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Initialize(ma_IDirectSoundCaptureBuffer* pThis, ma_IDirectSoundCapture* pDirectSoundCapture, const MA_DSCBUFFERDESC* pDSCBufferDesc) { return pThis->lpVtbl->Initialize(pThis, pDirectSoundCapture, pDSCBufferDesc); }
13289 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Lock(ma_IDirectSoundCaptureBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags) { return pThis->lpVtbl->Lock(pThis, dwOffset, dwBytes, ppAudioPtr1, pAudioBytes1, ppAudioPtr2, pAudioBytes2, dwFlags); }
13290 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Start(ma_IDirectSoundCaptureBuffer* pThis, DWORD dwFlags) { return pThis->lpVtbl->Start(pThis, dwFlags); }
13291 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Stop(ma_IDirectSoundCaptureBuffer* pThis) { return pThis->lpVtbl->Stop(pThis); }
13292 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Unlock(ma_IDirectSoundCaptureBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2) { return pThis->lpVtbl->Unlock(pThis, pAudioPtr1, dwAudioBytes1, pAudioPtr2, dwAudioBytes2); }
13293 
13294 
13295 /* IDirectSoundNotify */
13296 typedef struct
13297 {
13298  /* IUnknown */
13299  HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundNotify* pThis, const IID* const riid, void** ppObject);
13300  ULONG (STDMETHODCALLTYPE * AddRef) (ma_IDirectSoundNotify* pThis);
13301  ULONG (STDMETHODCALLTYPE * Release) (ma_IDirectSoundNotify* pThis);
13302 
13303  /* IDirectSoundNotify */
13304  HRESULT (STDMETHODCALLTYPE * SetNotificationPositions)(ma_IDirectSoundNotify* pThis, DWORD dwPositionNotifies, const MA_DSBPOSITIONNOTIFY* pPositionNotifies);
13305 } ma_IDirectSoundNotifyVtbl;
13306 struct ma_IDirectSoundNotify
13307 {
13308  ma_IDirectSoundNotifyVtbl* lpVtbl;
13309 };
13310 static MA_INLINE HRESULT ma_IDirectSoundNotify_QueryInterface(ma_IDirectSoundNotify* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13311 static MA_INLINE ULONG ma_IDirectSoundNotify_AddRef(ma_IDirectSoundNotify* pThis) { return pThis->lpVtbl->AddRef(pThis); }
13312 static MA_INLINE ULONG ma_IDirectSoundNotify_Release(ma_IDirectSoundNotify* pThis) { return pThis->lpVtbl->Release(pThis); }
13313 static MA_INLINE HRESULT ma_IDirectSoundNotify_SetNotificationPositions(ma_IDirectSoundNotify* pThis, DWORD dwPositionNotifies, const MA_DSBPOSITIONNOTIFY* pPositionNotifies) { return pThis->lpVtbl->SetNotificationPositions(pThis, dwPositionNotifies, pPositionNotifies); }
13314 
13315 
13316 typedef BOOL (CALLBACK * ma_DSEnumCallbackAProc) (LPGUID pDeviceGUID, LPCSTR pDeviceDescription, LPCSTR pModule, LPVOID pContext);
13317 typedef HRESULT (WINAPI * ma_DirectSoundCreateProc) (const GUID* pcGuidDevice, ma_IDirectSound** ppDS8, LPUNKNOWN pUnkOuter);
13318 typedef HRESULT (WINAPI * ma_DirectSoundEnumerateAProc) (ma_DSEnumCallbackAProc pDSEnumCallback, LPVOID pContext);
13319 typedef HRESULT (WINAPI * ma_DirectSoundCaptureCreateProc) (const GUID* pcGuidDevice, ma_IDirectSoundCapture** ppDSC8, LPUNKNOWN pUnkOuter);
13320 typedef HRESULT (WINAPI * ma_DirectSoundCaptureEnumerateAProc)(ma_DSEnumCallbackAProc pDSEnumCallback, LPVOID pContext);
13321 
13322 static ma_uint32 ma_get_best_sample_rate_within_range(ma_uint32 sampleRateMin, ma_uint32 sampleRateMax)
13323 {
13324  /* Normalize the range in case we were given something stupid. */
13325  if (sampleRateMin < MA_MIN_SAMPLE_RATE) {
13326  sampleRateMin = MA_MIN_SAMPLE_RATE;
13327  }
13328  if (sampleRateMax > MA_MAX_SAMPLE_RATE) {
13329  sampleRateMax = MA_MAX_SAMPLE_RATE;
13330  }
13331  if (sampleRateMin > sampleRateMax) {
13332  sampleRateMin = sampleRateMax;
13333  }
13334 
13335  if (sampleRateMin == sampleRateMax) {
13336  return sampleRateMax;
13337  } else {
13338  size_t iStandardRate;
13339  for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) {
13340  ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate];
13341  if (standardRate >= sampleRateMin && standardRate <= sampleRateMax) {
13342  return standardRate;
13343  }
13344  }
13345  }
13346 
13347  /* Should never get here. */
13349  return 0;
13350 }
13351 
13352 /*
13353 Retrieves the channel count and channel map for the given speaker configuration. If the speaker configuration is unknown,
13354 the channel count and channel map will be left unmodified.
13355 */
13356 static void ma_get_channels_from_speaker_config__dsound(DWORD speakerConfig, WORD* pChannelsOut, DWORD* pChannelMapOut)
13357 {
13358  WORD channels;
13359  DWORD channelMap;
13360 
13361  channels = 0;
13362  if (pChannelsOut != NULL) {
13363  channels = *pChannelsOut;
13364  }
13365 
13366  channelMap = 0;
13367  if (pChannelMapOut != NULL) {
13368  channelMap = *pChannelMapOut;
13369  }
13370 
13371  /*
13372  The speaker configuration is a combination of speaker config and speaker geometry. The lower 8 bits is what we care about. The upper
13373  16 bits is for the geometry.
13374  */
13375  switch ((BYTE)(speakerConfig)) {
13376  case 1 /*DSSPEAKER_HEADPHONE*/: channels = 2; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break;
13377  case 2 /*DSSPEAKER_MONO*/: channels = 1; channelMap = SPEAKER_FRONT_CENTER; break;
13378  case 3 /*DSSPEAKER_QUAD*/: channels = 4; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
13379  case 4 /*DSSPEAKER_STEREO*/: channels = 2; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break;
13380  case 5 /*DSSPEAKER_SURROUND*/: channels = 4; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER; break;
13381  case 6 /*DSSPEAKER_5POINT1_BACK*/ /*DSSPEAKER_5POINT1*/: channels = 6; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
13382  case 7 /*DSSPEAKER_7POINT1_WIDE*/ /*DSSPEAKER_7POINT1*/: channels = 8; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER; break;
13383  case 8 /*DSSPEAKER_7POINT1_SURROUND*/: channels = 8; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; break;
13384  case 9 /*DSSPEAKER_5POINT1_SURROUND*/: channels = 6; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; break;
13385  default: break;
13386  }
13387 
13388  if (pChannelsOut != NULL) {
13389  *pChannelsOut = channels;
13390  }
13391 
13392  if (pChannelMapOut != NULL) {
13393  *pChannelMapOut = channelMap;
13394  }
13395 }
13396 
13397 
13398 static ma_result ma_context_create_IDirectSound__dsound(ma_context* pContext, ma_share_mode shareMode, const ma_device_id* pDeviceID, ma_IDirectSound** ppDirectSound)
13399 {
13400  ma_IDirectSound* pDirectSound;
13401  HWND hWnd;
13402  HRESULT hr;
13403 
13404  MA_ASSERT(pContext != NULL);
13405  MA_ASSERT(ppDirectSound != NULL);
13406 
13407  *ppDirectSound = NULL;
13408  pDirectSound = NULL;
13409 
13410  if (FAILED(((ma_DirectSoundCreateProc)pContext->dsound.DirectSoundCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSound, NULL))) {
13411  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCreate() failed for playback device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
13412  }
13413 
13414  /* The cooperative level must be set before doing anything else. */
13415  hWnd = ((MA_PFN_GetForegroundWindow)pContext->win32.GetForegroundWindow)();
13416  if (hWnd == NULL) {
13417  hWnd = ((MA_PFN_GetDesktopWindow)pContext->win32.GetDesktopWindow)();
13418  }
13419 
13420  hr = ma_IDirectSound_SetCooperativeLevel(pDirectSound, hWnd, (shareMode == ma_share_mode_exclusive) ? MA_DSSCL_EXCLUSIVE : MA_DSSCL_PRIORITY);
13421  if (FAILED(hr)) {
13422  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device.", ma_result_from_HRESULT(hr));
13423  }
13424 
13425  *ppDirectSound = pDirectSound;
13426  return MA_SUCCESS;
13427 }
13428 
13429 static ma_result ma_context_create_IDirectSoundCapture__dsound(ma_context* pContext, ma_share_mode shareMode, const ma_device_id* pDeviceID, ma_IDirectSoundCapture** ppDirectSoundCapture)
13430 {
13431  ma_IDirectSoundCapture* pDirectSoundCapture;
13432  HRESULT hr;
13433 
13434  MA_ASSERT(pContext != NULL);
13435  MA_ASSERT(ppDirectSoundCapture != NULL);
13436 
13437  /* DirectSound does not support exclusive mode for capture. */
13438  if (shareMode == ma_share_mode_exclusive) {
13440  }
13441 
13442  *ppDirectSoundCapture = NULL;
13443  pDirectSoundCapture = NULL;
13444 
13445  hr = ((ma_DirectSoundCaptureCreateProc)pContext->dsound.DirectSoundCaptureCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSoundCapture, NULL);
13446  if (FAILED(hr)) {
13447  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCaptureCreate() failed for capture device.", ma_result_from_HRESULT(hr));
13448  }
13449 
13450  *ppDirectSoundCapture = pDirectSoundCapture;
13451  return MA_SUCCESS;
13452 }
13453 
13454 static ma_result ma_context_get_format_info_for_IDirectSoundCapture__dsound(ma_context* pContext, ma_IDirectSoundCapture* pDirectSoundCapture, WORD* pChannels, WORD* pBitsPerSample, DWORD* pSampleRate)
13455 {
13456  HRESULT hr;
13457  MA_DSCCAPS caps;
13458  WORD bitsPerSample;
13459  DWORD sampleRate;
13460 
13461  MA_ASSERT(pContext != NULL);
13462  MA_ASSERT(pDirectSoundCapture != NULL);
13463 
13464  if (pChannels) {
13465  *pChannels = 0;
13466  }
13467  if (pBitsPerSample) {
13468  *pBitsPerSample = 0;
13469  }
13470  if (pSampleRate) {
13471  *pSampleRate = 0;
13472  }
13473 
13474  MA_ZERO_OBJECT(&caps);
13475  caps.dwSize = sizeof(caps);
13476  hr = ma_IDirectSoundCapture_GetCaps(pDirectSoundCapture, &caps);
13477  if (FAILED(hr)) {
13478  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_GetCaps() failed for capture device.", ma_result_from_HRESULT(hr));
13479  }
13480 
13481  if (pChannels) {
13482  *pChannels = (WORD)caps.dwChannels;
13483  }
13484 
13485  /* The device can support multiple formats. We just go through the different formats in order of priority and pick the first one. This the same type of system as the WinMM backend. */
13486  bitsPerSample = 16;
13487  sampleRate = 48000;
13488 
13489  if (caps.dwChannels == 1) {
13490  if ((caps.dwFormats & WAVE_FORMAT_48M16) != 0) {
13491  sampleRate = 48000;
13492  } else if ((caps.dwFormats & WAVE_FORMAT_44M16) != 0) {
13493  sampleRate = 44100;
13494  } else if ((caps.dwFormats & WAVE_FORMAT_2M16) != 0) {
13495  sampleRate = 22050;
13496  } else if ((caps.dwFormats & WAVE_FORMAT_1M16) != 0) {
13497  sampleRate = 11025;
13498  } else if ((caps.dwFormats & WAVE_FORMAT_96M16) != 0) {
13499  sampleRate = 96000;
13500  } else {
13501  bitsPerSample = 8;
13502  if ((caps.dwFormats & WAVE_FORMAT_48M08) != 0) {
13503  sampleRate = 48000;
13504  } else if ((caps.dwFormats & WAVE_FORMAT_44M08) != 0) {
13505  sampleRate = 44100;
13506  } else if ((caps.dwFormats & WAVE_FORMAT_2M08) != 0) {
13507  sampleRate = 22050;
13508  } else if ((caps.dwFormats & WAVE_FORMAT_1M08) != 0) {
13509  sampleRate = 11025;
13510  } else if ((caps.dwFormats & WAVE_FORMAT_96M08) != 0) {
13511  sampleRate = 96000;
13512  } else {
13513  bitsPerSample = 16; /* Didn't find it. Just fall back to 16-bit. */
13514  }
13515  }
13516  } else if (caps.dwChannels == 2) {
13517  if ((caps.dwFormats & WAVE_FORMAT_48S16) != 0) {
13518  sampleRate = 48000;
13519  } else if ((caps.dwFormats & WAVE_FORMAT_44S16) != 0) {
13520  sampleRate = 44100;
13521  } else if ((caps.dwFormats & WAVE_FORMAT_2S16) != 0) {
13522  sampleRate = 22050;
13523  } else if ((caps.dwFormats & WAVE_FORMAT_1S16) != 0) {
13524  sampleRate = 11025;
13525  } else if ((caps.dwFormats & WAVE_FORMAT_96S16) != 0) {
13526  sampleRate = 96000;
13527  } else {
13528  bitsPerSample = 8;
13529  if ((caps.dwFormats & WAVE_FORMAT_48S08) != 0) {
13530  sampleRate = 48000;
13531  } else if ((caps.dwFormats & WAVE_FORMAT_44S08) != 0) {
13532  sampleRate = 44100;
13533  } else if ((caps.dwFormats & WAVE_FORMAT_2S08) != 0) {
13534  sampleRate = 22050;
13535  } else if ((caps.dwFormats & WAVE_FORMAT_1S08) != 0) {
13536  sampleRate = 11025;
13537  } else if ((caps.dwFormats & WAVE_FORMAT_96S08) != 0) {
13538  sampleRate = 96000;
13539  } else {
13540  bitsPerSample = 16; /* Didn't find it. Just fall back to 16-bit. */
13541  }
13542  }
13543  }
13544 
13545  if (pBitsPerSample) {
13546  *pBitsPerSample = bitsPerSample;
13547  }
13548  if (pSampleRate) {
13549  *pSampleRate = sampleRate;
13550  }
13551 
13552  return MA_SUCCESS;
13553 }
13554 
13555 static ma_bool32 ma_context_is_device_id_equal__dsound(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
13556 {
13557  MA_ASSERT(pContext != NULL);
13558  MA_ASSERT(pID0 != NULL);
13559  MA_ASSERT(pID1 != NULL);
13560  (void)pContext;
13561 
13562  return memcmp(pID0->dsound, pID1->dsound, sizeof(pID0->dsound)) == 0;
13563 }
13564 
13565 
13566 typedef struct
13567 {
13568  ma_context* pContext;
13569  ma_device_type deviceType;
13571  void* pUserData;
13572  ma_bool32 terminated;
13573 } ma_context_enumerate_devices_callback_data__dsound;
13574 
13575 static BOOL CALLBACK ma_context_enumerate_devices_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext)
13576 {
13577  ma_context_enumerate_devices_callback_data__dsound* pData = (ma_context_enumerate_devices_callback_data__dsound*)lpContext;
13578  ma_device_info deviceInfo;
13579 
13580  MA_ZERO_OBJECT(&deviceInfo);
13581 
13582  /* ID. */
13583  if (lpGuid != NULL) {
13584  MA_COPY_MEMORY(deviceInfo.id.dsound, lpGuid, 16);
13585  } else {
13586  MA_ZERO_MEMORY(deviceInfo.id.dsound, 16);
13587  }
13588 
13589  /* Name / Description */
13590  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), lpcstrDescription, (size_t)-1);
13591 
13592 
13593  /* Call the callback function, but make sure we stop enumerating if the callee requested so. */
13594  MA_ASSERT(pData != NULL);
13595  pData->terminated = !pData->callback(pData->pContext, pData->deviceType, &deviceInfo, pData->pUserData);
13596  if (pData->terminated) {
13597  return FALSE; /* Stop enumeration. */
13598  } else {
13599  return TRUE; /* Continue enumeration. */
13600  }
13601 
13602  (void)lpcstrModule;
13603 }
13604 
13605 static ma_result ma_context_enumerate_devices__dsound(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
13606 {
13607  ma_context_enumerate_devices_callback_data__dsound data;
13608 
13609  MA_ASSERT(pContext != NULL);
13610  MA_ASSERT(callback != NULL);
13611 
13612  data.pContext = pContext;
13613  data.callback = callback;
13614  data.pUserData = pUserData;
13615  data.terminated = MA_FALSE;
13616 
13617  /* Playback. */
13618  if (!data.terminated) {
13619  data.deviceType = ma_device_type_playback;
13620  ((ma_DirectSoundEnumerateAProc)pContext->dsound.DirectSoundEnumerateA)(ma_context_enumerate_devices_callback__dsound, &data);
13621  }
13622 
13623  /* Capture. */
13624  if (!data.terminated) {
13625  data.deviceType = ma_device_type_capture;
13626  ((ma_DirectSoundCaptureEnumerateAProc)pContext->dsound.DirectSoundCaptureEnumerateA)(ma_context_enumerate_devices_callback__dsound, &data);
13627  }
13628 
13629  return MA_SUCCESS;
13630 }
13631 
13632 
13633 typedef struct
13634 {
13635  const ma_device_id* pDeviceID;
13636  ma_device_info* pDeviceInfo;
13637  ma_bool32 found;
13638 } ma_context_get_device_info_callback_data__dsound;
13639 
13640 static BOOL CALLBACK ma_context_get_device_info_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext)
13641 {
13642  ma_context_get_device_info_callback_data__dsound* pData = (ma_context_get_device_info_callback_data__dsound*)lpContext;
13643  MA_ASSERT(pData != NULL);
13644 
13645  if ((pData->pDeviceID == NULL || ma_is_guid_equal(pData->pDeviceID->dsound, &MA_GUID_NULL)) && (lpGuid == NULL || ma_is_guid_equal(lpGuid, &MA_GUID_NULL))) {
13646  /* Default device. */
13647  ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), lpcstrDescription, (size_t)-1);
13648  pData->found = MA_TRUE;
13649  return FALSE; /* Stop enumeration. */
13650  } else {
13651  /* Not the default device. */
13652  if (lpGuid != NULL && pData->pDeviceID != NULL) {
13653  if (memcmp(pData->pDeviceID->dsound, lpGuid, sizeof(pData->pDeviceID->dsound)) == 0) {
13654  ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), lpcstrDescription, (size_t)-1);
13655  pData->found = MA_TRUE;
13656  return FALSE; /* Stop enumeration. */
13657  }
13658  }
13659  }
13660 
13661  (void)lpcstrModule;
13662  return TRUE;
13663 }
13664 
13665 static ma_result ma_context_get_device_info__dsound(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
13666 {
13667  ma_result result;
13668  HRESULT hr;
13669 
13670  /* Exclusive mode and capture not supported with DirectSound. */
13671  if (deviceType == ma_device_type_capture && shareMode == ma_share_mode_exclusive) {
13673  }
13674 
13675  if (pDeviceID != NULL) {
13676  ma_context_get_device_info_callback_data__dsound data;
13677 
13678  /* ID. */
13679  MA_COPY_MEMORY(pDeviceInfo->id.dsound, pDeviceID->dsound, 16);
13680 
13681  /* Name / Description. This is retrieved by enumerating over each device until we find that one that matches the input ID. */
13682  data.pDeviceID = pDeviceID;
13683  data.pDeviceInfo = pDeviceInfo;
13684  data.found = MA_FALSE;
13685  if (deviceType == ma_device_type_playback) {
13686  ((ma_DirectSoundEnumerateAProc)pContext->dsound.DirectSoundEnumerateA)(ma_context_get_device_info_callback__dsound, &data);
13687  } else {
13688  ((ma_DirectSoundCaptureEnumerateAProc)pContext->dsound.DirectSoundCaptureEnumerateA)(ma_context_get_device_info_callback__dsound, &data);
13689  }
13690 
13691  if (!data.found) {
13692  return MA_NO_DEVICE;
13693  }
13694  } else {
13695  /* I don't think there's a way to get the name of the default device with DirectSound. In this case we just need to use defaults. */
13696 
13697  /* ID */
13698  MA_ZERO_MEMORY(pDeviceInfo->id.dsound, 16);
13699 
13700  /* Name / Description */
13701  if (deviceType == ma_device_type_playback) {
13702  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
13703  } else {
13704  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
13705  }
13706  }
13707 
13708  /* Retrieving detailed information is slightly different depending on the device type. */
13709  if (deviceType == ma_device_type_playback) {
13710  /* Playback. */
13711  ma_IDirectSound* pDirectSound;
13712  MA_DSCAPS caps;
13713  ma_uint32 iFormat;
13714 
13715  result = ma_context_create_IDirectSound__dsound(pContext, shareMode, pDeviceID, &pDirectSound);
13716  if (result != MA_SUCCESS) {
13717  return result;
13718  }
13719 
13720  MA_ZERO_OBJECT(&caps);
13721  caps.dwSize = sizeof(caps);
13722  hr = ma_IDirectSound_GetCaps(pDirectSound, &caps);
13723  if (FAILED(hr)) {
13724  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.", ma_result_from_HRESULT(hr));
13725  }
13726 
13727  if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) {
13728  /* It supports at least stereo, but could support more. */
13729  WORD channels = 2;
13730 
13731  /* Look at the speaker configuration to get a better idea on the channel count. */
13732  DWORD speakerConfig;
13733  hr = ma_IDirectSound_GetSpeakerConfig(pDirectSound, &speakerConfig);
13734  if (SUCCEEDED(hr)) {
13735  ma_get_channels_from_speaker_config__dsound(speakerConfig, &channels, NULL);
13736  }
13737 
13738  pDeviceInfo->minChannels = channels;
13739  pDeviceInfo->maxChannels = channels;
13740  } else {
13741  /* It does not support stereo, which means we are stuck with mono. */
13742  pDeviceInfo->minChannels = 1;
13743  pDeviceInfo->maxChannels = 1;
13744  }
13745 
13746  /* Sample rate. */
13747  if ((caps.dwFlags & MA_DSCAPS_CONTINUOUSRATE) != 0) {
13748  pDeviceInfo->minSampleRate = caps.dwMinSecondarySampleRate;
13749  pDeviceInfo->maxSampleRate = caps.dwMaxSecondarySampleRate;
13750 
13751  /*
13752  On my machine the min and max sample rates can return 100 and 200000 respectively. I'd rather these be within
13753  the range of our standard sample rates so I'm clamping.
13754  */
13755  if (caps.dwMinSecondarySampleRate < MA_MIN_SAMPLE_RATE && caps.dwMaxSecondarySampleRate >= MA_MIN_SAMPLE_RATE) {
13756  pDeviceInfo->minSampleRate = MA_MIN_SAMPLE_RATE;
13757  }
13758  if (caps.dwMaxSecondarySampleRate > MA_MAX_SAMPLE_RATE && caps.dwMinSecondarySampleRate <= MA_MAX_SAMPLE_RATE) {
13759  pDeviceInfo->maxSampleRate = MA_MAX_SAMPLE_RATE;
13760  }
13761  } else {
13762  /* Only supports a single sample rate. Set both min an max to the same thing. Do not clamp within the standard rates. */
13763  pDeviceInfo->minSampleRate = caps.dwMaxSecondarySampleRate;
13764  pDeviceInfo->maxSampleRate = caps.dwMaxSecondarySampleRate;
13765  }
13766 
13767  /* DirectSound can support all formats. */
13768  pDeviceInfo->formatCount = ma_format_count - 1; /* Minus one because we don't want to include ma_format_unknown. */
13769  for (iFormat = 0; iFormat < pDeviceInfo->formatCount; ++iFormat) {
13770  pDeviceInfo->formats[iFormat] = (ma_format)(iFormat + 1); /* +1 to skip over ma_format_unknown. */
13771  }
13772 
13773  ma_IDirectSound_Release(pDirectSound);
13774  } else {
13775  /*
13776  Capture. This is a little different to playback due to the say the supported formats are reported. Technically capture
13777  devices can support a number of different formats, but for simplicity and consistency with ma_device_init() I'm just
13778  reporting the best format.
13779  */
13780  ma_IDirectSoundCapture* pDirectSoundCapture;
13781  WORD channels;
13782  WORD bitsPerSample;
13783  DWORD sampleRate;
13784 
13785  result = ma_context_create_IDirectSoundCapture__dsound(pContext, shareMode, pDeviceID, &pDirectSoundCapture);
13786  if (result != MA_SUCCESS) {
13787  return result;
13788  }
13789 
13790  result = ma_context_get_format_info_for_IDirectSoundCapture__dsound(pContext, pDirectSoundCapture, &channels, &bitsPerSample, &sampleRate);
13791  if (result != MA_SUCCESS) {
13792  ma_IDirectSoundCapture_Release(pDirectSoundCapture);
13793  return result;
13794  }
13795 
13796  pDeviceInfo->minChannels = channels;
13797  pDeviceInfo->maxChannels = channels;
13798  pDeviceInfo->minSampleRate = sampleRate;
13799  pDeviceInfo->maxSampleRate = sampleRate;
13800  pDeviceInfo->formatCount = 1;
13801  if (bitsPerSample == 8) {
13802  pDeviceInfo->formats[0] = ma_format_u8;
13803  } else if (bitsPerSample == 16) {
13804  pDeviceInfo->formats[0] = ma_format_s16;
13805  } else if (bitsPerSample == 24) {
13806  pDeviceInfo->formats[0] = ma_format_s24;
13807  } else if (bitsPerSample == 32) {
13808  pDeviceInfo->formats[0] = ma_format_s32;
13809  } else {
13810  ma_IDirectSoundCapture_Release(pDirectSoundCapture);
13811  return MA_FORMAT_NOT_SUPPORTED;
13812  }
13813 
13814  ma_IDirectSoundCapture_Release(pDirectSoundCapture);
13815  }
13816 
13817  return MA_SUCCESS;
13818 }
13819 
13820 
13821 
13822 static void ma_device_uninit__dsound(ma_device* pDevice)
13823 {
13824  MA_ASSERT(pDevice != NULL);
13825 
13826  if (pDevice->dsound.pCaptureBuffer != NULL) {
13827  ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
13828  }
13829  if (pDevice->dsound.pCapture != NULL) {
13830  ma_IDirectSoundCapture_Release((ma_IDirectSoundCapture*)pDevice->dsound.pCapture);
13831  }
13832 
13833  if (pDevice->dsound.pPlaybackBuffer != NULL) {
13834  ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer);
13835  }
13836  if (pDevice->dsound.pPlaybackPrimaryBuffer != NULL) {
13837  ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer);
13838  }
13839  if (pDevice->dsound.pPlayback != NULL) {
13840  ma_IDirectSound_Release((ma_IDirectSound*)pDevice->dsound.pPlayback);
13841  }
13842 }
13843 
13844 static ma_result ma_config_to_WAVEFORMATEXTENSIBLE(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const ma_channel* pChannelMap, WAVEFORMATEXTENSIBLE* pWF)
13845 {
13846  GUID subformat;
13847 
13848  switch (format)
13849  {
13850  case ma_format_u8:
13851  case ma_format_s16:
13852  case ma_format_s24:
13853  /*case ma_format_s24_32:*/
13854  case ma_format_s32:
13855  {
13856  subformat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
13857  } break;
13858 
13859  case ma_format_f32:
13860  {
13861  subformat = MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
13862  } break;
13863 
13864  default:
13865  return MA_FORMAT_NOT_SUPPORTED;
13866  }
13867 
13868  MA_ZERO_OBJECT(pWF);
13869  pWF->Format.cbSize = sizeof(*pWF);
13870  pWF->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
13871  pWF->Format.nChannels = (WORD)channels;
13872  pWF->Format.nSamplesPerSec = (DWORD)sampleRate;
13873  pWF->Format.wBitsPerSample = (WORD)ma_get_bytes_per_sample(format)*8;
13874  pWF->Format.nBlockAlign = (pWF->Format.nChannels * pWF->Format.wBitsPerSample) / 8;
13875  pWF->Format.nAvgBytesPerSec = pWF->Format.nBlockAlign * pWF->Format.nSamplesPerSec;
13876  pWF->Samples.wValidBitsPerSample = pWF->Format.wBitsPerSample;
13877  pWF->dwChannelMask = ma_channel_map_to_channel_mask__win32(pChannelMap, channels);
13878  pWF->SubFormat = subformat;
13879 
13880  return MA_SUCCESS;
13881 }
13882 
13883 static ma_result ma_device_init__dsound(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
13884 {
13885  ma_result result;
13886  HRESULT hr;
13887  ma_uint32 periodSizeInMilliseconds;
13888 
13889  MA_ASSERT(pDevice != NULL);
13890  MA_ZERO_OBJECT(&pDevice->dsound);
13891 
13892  if (pConfig->deviceType == ma_device_type_loopback) {
13894  }
13895 
13896  periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
13897  if (periodSizeInMilliseconds == 0) {
13898  periodSizeInMilliseconds = ma_calculate_buffer_size_in_milliseconds_from_frames(pConfig->periodSizeInFrames, pConfig->sampleRate);
13899  }
13900 
13901  /* DirectSound should use a latency of about 20ms per period for low latency mode. */
13902  if (pDevice->usingDefaultBufferSize) {
13904  periodSizeInMilliseconds = 20;
13905  } else {
13906  periodSizeInMilliseconds = 200;
13907  }
13908  }
13909 
13910  /* DirectSound breaks down with tiny buffer sizes (bad glitching and silent output). I am therefore restricting the size of the buffer to a minimum of 20 milliseconds. */
13911  if (periodSizeInMilliseconds < 20) {
13912  periodSizeInMilliseconds = 20;
13913  }
13914 
13915  /*
13916  Unfortunately DirectSound uses different APIs and data structures for playback and catpure devices. We need to initialize
13917  the capture device first because we'll want to match it's buffer size and period count on the playback side if we're using
13918  full-duplex mode.
13919  */
13920  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
13921  WAVEFORMATEXTENSIBLE wf;
13922  MA_DSCBUFFERDESC descDS;
13923  ma_uint32 periodSizeInFrames;
13924  char rawdata[1024]; /* <-- Ugly hack to avoid a malloc() due to a crappy DirectSound API. */
13925  WAVEFORMATEXTENSIBLE* pActualFormat;
13926 
13927  result = ma_config_to_WAVEFORMATEXTENSIBLE(pConfig->capture.format, pConfig->capture.channels, pConfig->sampleRate, pConfig->capture.channelMap, &wf);
13928  if (result != MA_SUCCESS) {
13929  return result;
13930  }
13931 
13932  result = ma_context_create_IDirectSoundCapture__dsound(pContext, pConfig->capture.shareMode, pConfig->capture.pDeviceID, (ma_IDirectSoundCapture**)&pDevice->dsound.pCapture);
13933  if (result != MA_SUCCESS) {
13934  ma_device_uninit__dsound(pDevice);
13935  return result;
13936  }
13937 
13938  result = ma_context_get_format_info_for_IDirectSoundCapture__dsound(pContext, (ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &wf.Format.nChannels, &wf.Format.wBitsPerSample, &wf.Format.nSamplesPerSec);
13939  if (result != MA_SUCCESS) {
13940  ma_device_uninit__dsound(pDevice);
13941  return result;
13942  }
13943 
13944  wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8;
13945  wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
13946  wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample;
13947  wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
13948 
13949  /* The size of the buffer must be a clean multiple of the period count. */
13950  periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(periodSizeInMilliseconds, wf.Format.nSamplesPerSec);
13951 
13952  MA_ZERO_OBJECT(&descDS);
13953  descDS.dwSize = sizeof(descDS);
13954  descDS.dwFlags = 0;
13955  descDS.dwBufferBytes = periodSizeInFrames * pConfig->periods * ma_get_bytes_per_frame(pDevice->capture.internalFormat, wf.Format.nChannels);
13956  descDS.lpwfxFormat = (WAVEFORMATEX*)&wf;
13957  hr = ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL);
13958  if (FAILED(hr)) {
13959  ma_device_uninit__dsound(pDevice);
13960  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", ma_result_from_HRESULT(hr));
13961  }
13962 
13963  /* Get the _actual_ properties of the buffer. */
13964  pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata;
13965  hr = ma_IDirectSoundCaptureBuffer_GetFormat((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL);
13966  if (FAILED(hr)) {
13967  ma_device_uninit__dsound(pDevice);
13968  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the capture device's buffer.", ma_result_from_HRESULT(hr));
13969  }
13970 
13971  pDevice->capture.internalFormat = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)pActualFormat);
13972  pDevice->capture.internalChannels = pActualFormat->Format.nChannels;
13973  pDevice->capture.internalSampleRate = pActualFormat->Format.nSamplesPerSec;
13974 
13975  /* Get the internal channel map based on the channel mask. */
13976  if (pActualFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
13977  ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap);
13978  } else {
13979  ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap);
13980  }
13981 
13982  /*
13983  After getting the actual format the size of the buffer in frames may have actually changed. However, we want this to be as close to what the
13984  user has asked for as possible, so let's go ahead and release the old capture buffer and create a new one in this case.
13985  */
13986  if (periodSizeInFrames != (descDS.dwBufferBytes / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels) / pConfig->periods)) {
13987  descDS.dwBufferBytes = periodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, wf.Format.nChannels) * pConfig->periods;
13988  ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
13989 
13990  hr = ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL);
13991  if (FAILED(hr)) {
13992  ma_device_uninit__dsound(pDevice);
13993  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Second attempt at IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", ma_result_from_HRESULT(hr));
13994  }
13995  }
13996 
13997  /* DirectSound should give us a buffer exactly the size we asked for. */
13998  pDevice->capture.internalPeriodSizeInFrames = periodSizeInFrames;
13999  pDevice->capture.internalPeriods = pConfig->periods;
14000  }
14001 
14002  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
14003  WAVEFORMATEXTENSIBLE wf;
14004  MA_DSBUFFERDESC descDSPrimary;
14005  MA_DSCAPS caps;
14006  char rawdata[1024]; /* <-- Ugly hack to avoid a malloc() due to a crappy DirectSound API. */
14007  WAVEFORMATEXTENSIBLE* pActualFormat;
14008  ma_uint32 periodSizeInFrames;
14009  MA_DSBUFFERDESC descDS;
14010 
14011  result = ma_config_to_WAVEFORMATEXTENSIBLE(pConfig->playback.format, pConfig->playback.channels, pConfig->sampleRate, pConfig->playback.channelMap, &wf);
14012  if (result != MA_SUCCESS) {
14013  return result;
14014  }
14015 
14016  result = ma_context_create_IDirectSound__dsound(pContext, pConfig->playback.shareMode, pConfig->playback.pDeviceID, (ma_IDirectSound**)&pDevice->dsound.pPlayback);
14017  if (result != MA_SUCCESS) {
14018  ma_device_uninit__dsound(pDevice);
14019  return result;
14020  }
14021 
14022  MA_ZERO_OBJECT(&descDSPrimary);
14023  descDSPrimary.dwSize = sizeof(MA_DSBUFFERDESC);
14024  descDSPrimary.dwFlags = MA_DSBCAPS_PRIMARYBUFFER | MA_DSBCAPS_CTRLVOLUME;
14025  hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDSPrimary, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackPrimaryBuffer, NULL);
14026  if (FAILED(hr)) {
14027  ma_device_uninit__dsound(pDevice);
14028  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's primary buffer.", ma_result_from_HRESULT(hr));
14029  }
14030 
14031 
14032  /* We may want to make some adjustments to the format if we are using defaults. */
14033  MA_ZERO_OBJECT(&caps);
14034  caps.dwSize = sizeof(caps);
14035  hr = ma_IDirectSound_GetCaps((ma_IDirectSound*)pDevice->dsound.pPlayback, &caps);
14036  if (FAILED(hr)) {
14037  ma_device_uninit__dsound(pDevice);
14038  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.", ma_result_from_HRESULT(hr));
14039  }
14040 
14041  if (pDevice->playback.usingDefaultChannels) {
14042  if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) {
14043  DWORD speakerConfig;
14044 
14045  /* It supports at least stereo, but could support more. */
14046  wf.Format.nChannels = 2;
14047 
14048  /* Look at the speaker configuration to get a better idea on the channel count. */
14049  if (SUCCEEDED(ma_IDirectSound_GetSpeakerConfig((ma_IDirectSound*)pDevice->dsound.pPlayback, &speakerConfig))) {
14050  ma_get_channels_from_speaker_config__dsound(speakerConfig, &wf.Format.nChannels, &wf.dwChannelMask);
14051  }
14052  } else {
14053  /* It does not support stereo, which means we are stuck with mono. */
14054  wf.Format.nChannels = 1;
14055  }
14056  }
14057 
14058  if (pDevice->usingDefaultSampleRate) {
14059  /* We base the sample rate on the values returned by GetCaps(). */
14060  if ((caps.dwFlags & MA_DSCAPS_CONTINUOUSRATE) != 0) {
14061  wf.Format.nSamplesPerSec = ma_get_best_sample_rate_within_range(caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate);
14062  } else {
14063  wf.Format.nSamplesPerSec = caps.dwMaxSecondarySampleRate;
14064  }
14065  }
14066 
14067  wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8;
14068  wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
14069 
14070  /*
14071  From MSDN:
14072 
14073  The method succeeds even if the hardware does not support the requested format; DirectSound sets the buffer to the closest
14074  supported format. To determine whether this has happened, an application can call the GetFormat method for the primary buffer
14075  and compare the result with the format that was requested with the SetFormat method.
14076  */
14077  hr = ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)&wf);
14078  if (FAILED(hr)) {
14079  ma_device_uninit__dsound(pDevice);
14080  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer.", ma_result_from_HRESULT(hr));
14081  }
14082 
14083  /* Get the _actual_ properties of the buffer. */
14084  pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata;
14085  hr = ma_IDirectSoundBuffer_GetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL);
14086  if (FAILED(hr)) {
14087  ma_device_uninit__dsound(pDevice);
14088  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.", ma_result_from_HRESULT(hr));
14089  }
14090 
14091  pDevice->playback.internalFormat = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)pActualFormat);
14092  pDevice->playback.internalChannels = pActualFormat->Format.nChannels;
14093  pDevice->playback.internalSampleRate = pActualFormat->Format.nSamplesPerSec;
14094 
14095  /* Get the internal channel map based on the channel mask. */
14096  if (pActualFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
14097  ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap);
14098  } else {
14099  ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap);
14100  }
14101 
14102  /* The size of the buffer must be a clean multiple of the period count. */
14103  periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(periodSizeInMilliseconds, pDevice->playback.internalSampleRate);
14104 
14105  /*
14106  Meaning of dwFlags (from MSDN):
14107 
14108  DSBCAPS_CTRLPOSITIONNOTIFY
14109  The buffer has position notification capability.
14110 
14111  DSBCAPS_GLOBALFOCUS
14112  With this flag set, an application using DirectSound can continue to play its buffers if the user switches focus to
14113  another application, even if the new application uses DirectSound.
14114 
14115  DSBCAPS_GETCURRENTPOSITION2
14116  In the first version of DirectSound, the play cursor was significantly ahead of the actual playing sound on emulated
14117  sound cards; it was directly behind the write cursor. Now, if the DSBCAPS_GETCURRENTPOSITION2 flag is specified, the
14118  application can get a more accurate play cursor.
14119  */
14120  MA_ZERO_OBJECT(&descDS);
14121  descDS.dwSize = sizeof(descDS);
14122  descDS.dwFlags = MA_DSBCAPS_CTRLPOSITIONNOTIFY | MA_DSBCAPS_GLOBALFOCUS | MA_DSBCAPS_GETCURRENTPOSITION2;
14123  descDS.dwBufferBytes = periodSizeInFrames * pConfig->periods * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
14124  descDS.lpwfxFormat = (WAVEFORMATEX*)&wf;
14125  hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDS, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackBuffer, NULL);
14126  if (FAILED(hr)) {
14127  ma_device_uninit__dsound(pDevice);
14128  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer.", ma_result_from_HRESULT(hr));
14129  }
14130 
14131  /* DirectSound should give us a buffer exactly the size we asked for. */
14132  pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames;
14133  pDevice->playback.internalPeriods = pConfig->periods;
14134  }
14135 
14136  (void)pContext;
14137  return MA_SUCCESS;
14138 }
14139 
14140 
14141 static ma_result ma_device_main_loop__dsound(ma_device* pDevice)
14142 {
14143  ma_result result = MA_SUCCESS;
14144  ma_uint32 bpfDeviceCapture = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
14145  ma_uint32 bpfDevicePlayback = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
14146  HRESULT hr;
14147  DWORD lockOffsetInBytesCapture;
14148  DWORD lockSizeInBytesCapture;
14149  DWORD mappedSizeInBytesCapture;
14150  DWORD mappedDeviceFramesProcessedCapture;
14151  void* pMappedDeviceBufferCapture;
14152  DWORD lockOffsetInBytesPlayback;
14153  DWORD lockSizeInBytesPlayback;
14154  DWORD mappedSizeInBytesPlayback;
14155  void* pMappedDeviceBufferPlayback;
14156  DWORD prevReadCursorInBytesCapture = 0;
14157  DWORD prevPlayCursorInBytesPlayback = 0;
14158  ma_bool32 physicalPlayCursorLoopFlagPlayback = 0;
14159  DWORD virtualWriteCursorInBytesPlayback = 0;
14160  ma_bool32 virtualWriteCursorLoopFlagPlayback = 0;
14161  ma_bool32 isPlaybackDeviceStarted = MA_FALSE;
14162  ma_uint32 framesWrittenToPlaybackDevice = 0; /* For knowing whether or not the playback device needs to be started. */
14163  ma_uint32 waitTimeInMilliseconds = 1;
14164 
14165  MA_ASSERT(pDevice != NULL);
14166 
14167  /* The first thing to do is start the capture device. The playback device is only started after the first period is written. */
14168  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
14169  if (FAILED(ma_IDirectSoundCaptureBuffer_Start((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, MA_DSCBSTART_LOOPING))) {
14170  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed.", MA_FAILED_TO_START_BACKEND_DEVICE);
14171  }
14172  }
14173 
14174  while (ma_device__get_state(pDevice) == MA_STATE_STARTED) {
14175  switch (pDevice->type)
14176  {
14177  case ma_device_type_duplex:
14178  {
14179  DWORD physicalCaptureCursorInBytes;
14180  DWORD physicalReadCursorInBytes;
14181  hr = ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, &physicalCaptureCursorInBytes, &physicalReadCursorInBytes);
14182  if (FAILED(hr)) {
14183  return ma_result_from_HRESULT(hr);
14184  }
14185 
14186  /* If nothing is available we just sleep for a bit and return from this iteration. */
14187  if (physicalReadCursorInBytes == prevReadCursorInBytesCapture) {
14188  ma_sleep(waitTimeInMilliseconds);
14189  continue; /* Nothing is available in the capture buffer. */
14190  }
14191 
14192  /*
14193  The current position has moved. We need to map all of the captured samples and write them to the playback device, making sure
14194  we don't return until every frame has been copied over.
14195  */
14196  if (prevReadCursorInBytesCapture < physicalReadCursorInBytes) {
14197  /* The capture position has not looped. This is the simple case. */
14198  lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
14199  lockSizeInBytesCapture = (physicalReadCursorInBytes - prevReadCursorInBytesCapture);
14200  } else {
14201  /*
14202  The capture position has looped. This is the more complex case. Map to the end of the buffer. If this does not return anything,
14203  do it again from the start.
14204  */
14205  if (prevReadCursorInBytesCapture < pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) {
14206  /* Lock up to the end of the buffer. */
14207  lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
14208  lockSizeInBytesCapture = (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) - prevReadCursorInBytesCapture;
14209  } else {
14210  /* Lock starting from the start of the buffer. */
14211  lockOffsetInBytesCapture = 0;
14212  lockSizeInBytesCapture = physicalReadCursorInBytes;
14213  }
14214  }
14215 
14216  if (lockSizeInBytesCapture == 0) {
14217  ma_sleep(waitTimeInMilliseconds);
14218  continue; /* Nothing is available in the capture buffer. */
14219  }
14220 
14221  hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0);
14222  if (FAILED(hr)) {
14223  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
14224  }
14225 
14226 
14227  /* At this point we have some input data that we need to output. We do not return until every mapped frame of the input data is written to the playback device. */
14228  mappedDeviceFramesProcessedCapture = 0;
14229 
14230  for (;;) { /* Keep writing to the playback device. */
14231  ma_uint8 inputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
14232  ma_uint32 inputFramesInClientFormatCap = sizeof(inputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
14233  ma_uint8 outputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
14234  ma_uint32 outputFramesInClientFormatCap = sizeof(outputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
14235  ma_uint32 outputFramesInClientFormatCount;
14236  ma_uint32 outputFramesInClientFormatConsumed = 0;
14237  ma_uint64 clientCapturedFramesToProcess = ma_min(inputFramesInClientFormatCap, outputFramesInClientFormatCap);
14238  ma_uint64 deviceCapturedFramesToProcess = (mappedSizeInBytesCapture / bpfDeviceCapture) - mappedDeviceFramesProcessedCapture;
14239  void* pRunningMappedDeviceBufferCapture = ma_offset_ptr(pMappedDeviceBufferCapture, mappedDeviceFramesProcessedCapture * bpfDeviceCapture);
14240 
14241  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningMappedDeviceBufferCapture, &deviceCapturedFramesToProcess, inputFramesInClientFormat, &clientCapturedFramesToProcess);
14242  if (result != MA_SUCCESS) {
14243  break;
14244  }
14245 
14246  outputFramesInClientFormatCount = (ma_uint32)clientCapturedFramesToProcess;
14247  mappedDeviceFramesProcessedCapture += (ma_uint32)deviceCapturedFramesToProcess;
14248 
14249  ma_device__on_data(pDevice, outputFramesInClientFormat, inputFramesInClientFormat, (ma_uint32)clientCapturedFramesToProcess);
14250 
14251  /* At this point we have input and output data in client format. All we need to do now is convert it to the output device format. This may take a few passes. */
14252  for (;;) {
14253  ma_uint32 framesWrittenThisIteration;
14254  DWORD physicalPlayCursorInBytes;
14255  DWORD physicalWriteCursorInBytes;
14256  DWORD availableBytesPlayback;
14257  DWORD silentPaddingInBytes = 0; /* <-- Must be initialized to 0. */
14258 
14259  /* We need the physical play and write cursors. */
14260  if (FAILED(ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes))) {
14261  break;
14262  }
14263 
14264  if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
14265  physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
14266  }
14267  prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes;
14268 
14269  /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */
14270  if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
14271  /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
14272  if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
14273  availableBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
14274  availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */
14275  } else {
14276  /* This is an error. */
14277  #ifdef MA_DEBUG_OUTPUT
14278  printf("[DirectSound] (Duplex/Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%d, virtualWriteCursorInBytes=%d.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
14279  #endif
14280  availableBytesPlayback = 0;
14281  }
14282  } else {
14283  /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
14284  if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
14285  availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
14286  } else {
14287  /* This is an error. */
14288  #ifdef MA_DEBUG_OUTPUT
14289  printf("[DirectSound] (Duplex/Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%d, virtualWriteCursorInBytes=%d.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
14290  #endif
14291  availableBytesPlayback = 0;
14292  }
14293  }
14294 
14295  #ifdef MA_DEBUG_OUTPUT
14296  /*printf("[DirectSound] (Duplex/Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/
14297  #endif
14298 
14299  /* If there's no room available for writing we need to wait for more. */
14300  if (availableBytesPlayback == 0) {
14301  /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */
14302  if (!isPlaybackDeviceStarted) {
14303  hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
14304  if (FAILED(hr)) {
14305  ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
14306  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
14307  }
14308  isPlaybackDeviceStarted = MA_TRUE;
14309  } else {
14310  ma_sleep(waitTimeInMilliseconds);
14311  continue;
14312  }
14313  }
14314 
14315 
14316  /* Getting here means there room available somewhere. We limit this to either the end of the buffer or the physical play cursor, whichever is closest. */
14317  lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback;
14318  if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
14319  /* Same loop iteration. Go up to the end of the buffer. */
14320  lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
14321  } else {
14322  /* Different loop iterations. Go up to the physical play cursor. */
14323  lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
14324  }
14325 
14326  hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0);
14327  if (FAILED(hr)) {
14328  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
14329  break;
14330  }
14331 
14332  /*
14333  Experiment: If the playback buffer is being starved, pad it with some silence to get it back in sync. This will cause a glitch, but it may prevent
14334  endless glitching due to it constantly running out of data.
14335  */
14336  if (isPlaybackDeviceStarted) {
14337  DWORD bytesQueuedForPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - availableBytesPlayback;
14338  if (bytesQueuedForPlayback < (pDevice->playback.internalPeriodSizeInFrames*bpfDevicePlayback)) {
14339  silentPaddingInBytes = (pDevice->playback.internalPeriodSizeInFrames*2*bpfDevicePlayback) - bytesQueuedForPlayback;
14340  if (silentPaddingInBytes > lockSizeInBytesPlayback) {
14341  silentPaddingInBytes = lockSizeInBytesPlayback;
14342  }
14343 
14344  #ifdef MA_DEBUG_OUTPUT
14345  printf("[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%d, silentPaddingInBytes=%d\n", availableBytesPlayback, silentPaddingInBytes);
14346  #endif
14347  }
14348  }
14349 
14350  /* At this point we have a buffer for output. */
14351  if (silentPaddingInBytes > 0) {
14352  MA_ZERO_MEMORY(pMappedDeviceBufferPlayback, silentPaddingInBytes);
14353  framesWrittenThisIteration = silentPaddingInBytes/bpfDevicePlayback;
14354  } else {
14355  ma_uint64 convertedFrameCountIn = (outputFramesInClientFormatCount - outputFramesInClientFormatConsumed);
14356  ma_uint64 convertedFrameCountOut = mappedSizeInBytesPlayback/bpfDevicePlayback;
14357  void* pConvertedFramesIn = ma_offset_ptr(outputFramesInClientFormat, outputFramesInClientFormatConsumed * bpfDevicePlayback);
14358  void* pConvertedFramesOut = pMappedDeviceBufferPlayback;
14359 
14360  result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pConvertedFramesIn, &convertedFrameCountIn, pConvertedFramesOut, &convertedFrameCountOut);
14361  if (result != MA_SUCCESS) {
14362  break;
14363  }
14364 
14365  outputFramesInClientFormatConsumed += (ma_uint32)convertedFrameCountOut;
14366  framesWrittenThisIteration = (ma_uint32)convertedFrameCountOut;
14367  }
14368 
14369 
14370  hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, framesWrittenThisIteration*bpfDevicePlayback, NULL, 0);
14371  if (FAILED(hr)) {
14372  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
14373  break;
14374  }
14375 
14376  virtualWriteCursorInBytesPlayback += framesWrittenThisIteration*bpfDevicePlayback;
14377  if ((virtualWriteCursorInBytesPlayback/bpfDevicePlayback) == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods) {
14378  virtualWriteCursorInBytesPlayback = 0;
14379  virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback;
14380  }
14381 
14382  /*
14383  We may need to start the device. We want two full periods to be written before starting the playback device. Having an extra period adds
14384  a bit of a buffer to prevent the playback buffer from getting starved.
14385  */
14386  framesWrittenToPlaybackDevice += framesWrittenThisIteration;
14387  if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= (pDevice->playback.internalPeriodSizeInFrames*2)) {
14388  hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
14389  if (FAILED(hr)) {
14390  ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
14391  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
14392  }
14393  isPlaybackDeviceStarted = MA_TRUE;
14394  }
14395 
14396  if (framesWrittenThisIteration < mappedSizeInBytesPlayback/bpfDevicePlayback) {
14397  break; /* We're finished with the output data.*/
14398  }
14399  }
14400 
14401  if (clientCapturedFramesToProcess == 0) {
14402  break; /* We just consumed every input sample. */
14403  }
14404  }
14405 
14406 
14407  /* At this point we're done with the mapped portion of the capture buffer. */
14408  hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0);
14409  if (FAILED(hr)) {
14410  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr));
14411  }
14412  prevReadCursorInBytesCapture = (lockOffsetInBytesCapture + mappedSizeInBytesCapture);
14413  } break;
14414 
14415 
14416 
14418  {
14419  DWORD physicalCaptureCursorInBytes;
14420  DWORD physicalReadCursorInBytes;
14421  hr = ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, &physicalCaptureCursorInBytes, &physicalReadCursorInBytes);
14422  if (FAILED(hr)) {
14423  return MA_ERROR;
14424  }
14425 
14426  /* If the previous capture position is the same as the current position we need to wait a bit longer. */
14427  if (prevReadCursorInBytesCapture == physicalReadCursorInBytes) {
14428  ma_sleep(waitTimeInMilliseconds);
14429  continue;
14430  }
14431 
14432  /* Getting here means we have capture data available. */
14433  if (prevReadCursorInBytesCapture < physicalReadCursorInBytes) {
14434  /* The capture position has not looped. This is the simple case. */
14435  lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
14436  lockSizeInBytesCapture = (physicalReadCursorInBytes - prevReadCursorInBytesCapture);
14437  } else {
14438  /*
14439  The capture position has looped. This is the more complex case. Map to the end of the buffer. If this does not return anything,
14440  do it again from the start.
14441  */
14442  if (prevReadCursorInBytesCapture < pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) {
14443  /* Lock up to the end of the buffer. */
14444  lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
14445  lockSizeInBytesCapture = (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) - prevReadCursorInBytesCapture;
14446  } else {
14447  /* Lock starting from the start of the buffer. */
14448  lockOffsetInBytesCapture = 0;
14449  lockSizeInBytesCapture = physicalReadCursorInBytes;
14450  }
14451  }
14452 
14453  #ifdef MA_DEBUG_OUTPUT
14454  /*printf("[DirectSound] (Capture) physicalCaptureCursorInBytes=%d, physicalReadCursorInBytes=%d\n", physicalCaptureCursorInBytes, physicalReadCursorInBytes);*/
14455  /*printf("[DirectSound] (Capture) lockOffsetInBytesCapture=%d, lockSizeInBytesCapture=%d\n", lockOffsetInBytesCapture, lockSizeInBytesCapture);*/
14456  #endif
14457 
14458  if (lockSizeInBytesCapture < pDevice->capture.internalPeriodSizeInFrames) {
14459  ma_sleep(waitTimeInMilliseconds);
14460  continue; /* Nothing is available in the capture buffer. */
14461  }
14462 
14463  hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0);
14464  if (FAILED(hr)) {
14465  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
14466  }
14467 
14468  #ifdef MA_DEBUG_OUTPUT
14469  if (lockSizeInBytesCapture != mappedSizeInBytesCapture) {
14470  printf("[DirectSound] (Capture) lockSizeInBytesCapture=%d != mappedSizeInBytesCapture=%d\n", lockSizeInBytesCapture, mappedSizeInBytesCapture);
14471  }
14472  #endif
14473 
14474  ma_device__send_frames_to_client(pDevice, mappedSizeInBytesCapture/bpfDeviceCapture, pMappedDeviceBufferCapture);
14475 
14476  hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0);
14477  if (FAILED(hr)) {
14478  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr));
14479  }
14480  prevReadCursorInBytesCapture = lockOffsetInBytesCapture + mappedSizeInBytesCapture;
14481 
14482  if (prevReadCursorInBytesCapture == (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture)) {
14483  prevReadCursorInBytesCapture = 0;
14484  }
14485  } break;
14486 
14487 
14488 
14490  {
14491  DWORD availableBytesPlayback;
14492  DWORD physicalPlayCursorInBytes;
14493  DWORD physicalWriteCursorInBytes;
14494  hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes);
14495  if (FAILED(hr)) {
14496  break;
14497  }
14498 
14499  if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
14500  physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
14501  }
14502  prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes;
14503 
14504  /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */
14505  if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
14506  /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
14507  if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
14508  availableBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
14509  availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */
14510  } else {
14511  /* This is an error. */
14512  #ifdef MA_DEBUG_OUTPUT
14513  printf("[DirectSound] (Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%d, virtualWriteCursorInBytes=%d.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
14514  #endif
14515  availableBytesPlayback = 0;
14516  }
14517  } else {
14518  /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
14519  if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
14520  availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
14521  } else {
14522  /* This is an error. */
14523  #ifdef MA_DEBUG_OUTPUT
14524  printf("[DirectSound] (Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%d, virtualWriteCursorInBytes=%d.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
14525  #endif
14526  availableBytesPlayback = 0;
14527  }
14528  }
14529 
14530  #ifdef MA_DEBUG_OUTPUT
14531  /*printf("[DirectSound] (Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/
14532  #endif
14533 
14534  /* If there's no room available for writing we need to wait for more. */
14535  if (availableBytesPlayback < pDevice->playback.internalPeriodSizeInFrames) {
14536  /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */
14537  if (availableBytesPlayback == 0 && !isPlaybackDeviceStarted) {
14538  hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
14539  if (FAILED(hr)) {
14540  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
14541  }
14542  isPlaybackDeviceStarted = MA_TRUE;
14543  } else {
14544  ma_sleep(waitTimeInMilliseconds);
14545  continue;
14546  }
14547  }
14548 
14549  /* Getting here means there room available somewhere. We limit this to either the end of the buffer or the physical play cursor, whichever is closest. */
14550  lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback;
14551  if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
14552  /* Same loop iteration. Go up to the end of the buffer. */
14553  lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
14554  } else {
14555  /* Different loop iterations. Go up to the physical play cursor. */
14556  lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
14557  }
14558 
14559  hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0);
14560  if (FAILED(hr)) {
14561  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
14562  break;
14563  }
14564 
14565  /* At this point we have a buffer for output. */
14566  ma_device__read_frames_from_client(pDevice, (mappedSizeInBytesPlayback/bpfDevicePlayback), pMappedDeviceBufferPlayback);
14567 
14568  hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, mappedSizeInBytesPlayback, NULL, 0);
14569  if (FAILED(hr)) {
14570  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
14571  break;
14572  }
14573 
14574  virtualWriteCursorInBytesPlayback += mappedSizeInBytesPlayback;
14575  if (virtualWriteCursorInBytesPlayback == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) {
14576  virtualWriteCursorInBytesPlayback = 0;
14577  virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback;
14578  }
14579 
14580  /*
14581  We may need to start the device. We want two full periods to be written before starting the playback device. Having an extra period adds
14582  a bit of a buffer to prevent the playback buffer from getting starved.
14583  */
14584  framesWrittenToPlaybackDevice += mappedSizeInBytesPlayback/bpfDevicePlayback;
14585  if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= pDevice->playback.internalPeriodSizeInFrames) {
14586  hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
14587  if (FAILED(hr)) {
14588  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
14589  }
14590  isPlaybackDeviceStarted = MA_TRUE;
14591  }
14592  } break;
14593 
14594 
14595  default: return MA_INVALID_ARGS; /* Invalid device type. */
14596  }
14597 
14598  if (result != MA_SUCCESS) {
14599  return result;
14600  }
14601  }
14602 
14603  /* Getting here means the device is being stopped. */
14604  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
14605  hr = ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
14606  if (FAILED(hr)) {
14607  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed.", ma_result_from_HRESULT(hr));
14608  }
14609  }
14610 
14611  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
14612  /* The playback device should be drained before stopping. All we do is wait until the available bytes is equal to the size of the buffer. */
14613  if (isPlaybackDeviceStarted) {
14614  for (;;) {
14615  DWORD availableBytesPlayback = 0;
14616  DWORD physicalPlayCursorInBytes;
14617  DWORD physicalWriteCursorInBytes;
14618  hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes);
14619  if (FAILED(hr)) {
14620  break;
14621  }
14622 
14623  if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
14624  physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
14625  }
14626  prevPlayCursorInBytesPlayback = physicalPlayCursorInBytes;
14627 
14628  if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
14629  /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
14630  if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
14631  availableBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
14632  availableBytesPlayback += physicalPlayCursorInBytes; /* Wrap around. */
14633  } else {
14634  break;
14635  }
14636  } else {
14637  /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
14638  if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
14639  availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
14640  } else {
14641  break;
14642  }
14643  }
14644 
14645  if (availableBytesPlayback >= (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback)) {
14646  break;
14647  }
14648 
14649  ma_sleep(waitTimeInMilliseconds);
14650  }
14651  }
14652 
14653  hr = ma_IDirectSoundBuffer_Stop((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer);
14654  if (FAILED(hr)) {
14655  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Stop() failed.", ma_result_from_HRESULT(hr));
14656  }
14657 
14658  ma_IDirectSoundBuffer_SetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0);
14659  }
14660 
14661  return MA_SUCCESS;
14662 }
14663 
14664 static ma_result ma_context_uninit__dsound(ma_context* pContext)
14665 {
14666  MA_ASSERT(pContext != NULL);
14667  MA_ASSERT(pContext->backend == ma_backend_dsound);
14668 
14669  ma_dlclose(pContext, pContext->dsound.hDSoundDLL);
14670 
14671  return MA_SUCCESS;
14672 }
14673 
14674 static ma_result ma_context_init__dsound(const ma_context_config* pConfig, ma_context* pContext)
14675 {
14676  MA_ASSERT(pContext != NULL);
14677 
14678  (void)pConfig;
14679 
14680  pContext->dsound.hDSoundDLL = ma_dlopen(pContext, "dsound.dll");
14681  if (pContext->dsound.hDSoundDLL == NULL) {
14682  return MA_API_NOT_FOUND;
14683  }
14684 
14685  pContext->dsound.DirectSoundCreate = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCreate");
14686  pContext->dsound.DirectSoundEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundEnumerateA");
14687  pContext->dsound.DirectSoundCaptureCreate = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureCreate");
14688  pContext->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA");
14689 
14690  pContext->onUninit = ma_context_uninit__dsound;
14691  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__dsound;
14692  pContext->onEnumDevices = ma_context_enumerate_devices__dsound;
14693  pContext->onGetDeviceInfo = ma_context_get_device_info__dsound;
14694  pContext->onDeviceInit = ma_device_init__dsound;
14695  pContext->onDeviceUninit = ma_device_uninit__dsound;
14696  pContext->onDeviceStart = NULL; /* Not used. Started in onDeviceMainLoop. */
14697  pContext->onDeviceStop = NULL; /* Not used. Stopped in onDeviceMainLoop. */
14698  pContext->onDeviceMainLoop = ma_device_main_loop__dsound;
14699 
14700  return MA_SUCCESS;
14701 }
14702 #endif
14703 
14704 
14705 
14706 /******************************************************************************
14707 
14708 WinMM Backend
14709 
14710 ******************************************************************************/
14711 #ifdef MA_HAS_WINMM
14712 
14713 /*
14714 Some older compilers don't have WAVEOUTCAPS2A and WAVEINCAPS2A, so we'll need to write this ourselves. These structures
14715 are exactly the same as the older ones but they have a few GUIDs for manufacturer/product/name identification. I'm keeping
14716 the names the same as the Win32 library for consistency, but namespaced to avoid naming conflicts with the Win32 version.
14717 */
14718 typedef struct
14719 {
14720  WORD wMid;
14721  WORD wPid;
14722  MMVERSION vDriverVersion;
14723  CHAR szPname[MAXPNAMELEN];
14724  DWORD dwFormats;
14725  WORD wChannels;
14726  WORD wReserved1;
14727  DWORD dwSupport;
14728  GUID ManufacturerGuid;
14729  GUID ProductGuid;
14730  GUID NameGuid;
14731 } MA_WAVEOUTCAPS2A;
14732 typedef struct
14733 {
14734  WORD wMid;
14735  WORD wPid;
14736  MMVERSION vDriverVersion;
14737  CHAR szPname[MAXPNAMELEN];
14738  DWORD dwFormats;
14739  WORD wChannels;
14740  WORD wReserved1;
14741  GUID ManufacturerGuid;
14742  GUID ProductGuid;
14743  GUID NameGuid;
14744 } MA_WAVEINCAPS2A;
14745 
14746 typedef UINT (WINAPI * MA_PFN_waveOutGetNumDevs)(void);
14747 typedef MMRESULT (WINAPI * MA_PFN_waveOutGetDevCapsA)(ma_uintptr uDeviceID, LPWAVEOUTCAPSA pwoc, UINT cbwoc);
14748 typedef MMRESULT (WINAPI * MA_PFN_waveOutOpen)(LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
14749 typedef MMRESULT (WINAPI * MA_PFN_waveOutClose)(HWAVEOUT hwo);
14750 typedef MMRESULT (WINAPI * MA_PFN_waveOutPrepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
14751 typedef MMRESULT (WINAPI * MA_PFN_waveOutUnprepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
14752 typedef MMRESULT (WINAPI * MA_PFN_waveOutWrite)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
14753 typedef MMRESULT (WINAPI * MA_PFN_waveOutReset)(HWAVEOUT hwo);
14754 typedef UINT (WINAPI * MA_PFN_waveInGetNumDevs)(void);
14755 typedef MMRESULT (WINAPI * MA_PFN_waveInGetDevCapsA)(ma_uintptr uDeviceID, LPWAVEINCAPSA pwic, UINT cbwic);
14756 typedef MMRESULT (WINAPI * MA_PFN_waveInOpen)(LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
14757 typedef MMRESULT (WINAPI * MA_PFN_waveInClose)(HWAVEIN hwi);
14758 typedef MMRESULT (WINAPI * MA_PFN_waveInPrepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
14759 typedef MMRESULT (WINAPI * MA_PFN_waveInUnprepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
14760 typedef MMRESULT (WINAPI * MA_PFN_waveInAddBuffer)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
14761 typedef MMRESULT (WINAPI * MA_PFN_waveInStart)(HWAVEIN hwi);
14762 typedef MMRESULT (WINAPI * MA_PFN_waveInReset)(HWAVEIN hwi);
14763 
14764 static ma_result ma_result_from_MMRESULT(MMRESULT resultMM)
14765 {
14766  switch (resultMM) {
14767  case MMSYSERR_NOERROR: return MA_SUCCESS;
14768  case MMSYSERR_BADDEVICEID: return MA_INVALID_ARGS;
14769  case MMSYSERR_INVALHANDLE: return MA_INVALID_ARGS;
14770  case MMSYSERR_NOMEM: return MA_OUT_OF_MEMORY;
14771  case MMSYSERR_INVALFLAG: return MA_INVALID_ARGS;
14772  case MMSYSERR_INVALPARAM: return MA_INVALID_ARGS;
14773  case MMSYSERR_HANDLEBUSY: return MA_BUSY;
14774  case MMSYSERR_ERROR: return MA_ERROR;
14775  default: return MA_ERROR;
14776  }
14777 }
14778 
14779 static char* ma_find_last_character(char* str, char ch)
14780 {
14781  char* last;
14782 
14783  if (str == NULL) {
14784  return NULL;
14785  }
14786 
14787  last = NULL;
14788  while (*str != '\0') {
14789  if (*str == ch) {
14790  last = str;
14791  }
14792 
14793  str += 1;
14794  }
14795 
14796  return last;
14797 }
14798 
14799 static ma_uint32 ma_get_period_size_in_bytes(ma_uint32 periodSizeInFrames, ma_format format, ma_uint32 channels)
14800 {
14801  return periodSizeInFrames * ma_get_bytes_per_frame(format, channels);
14802 }
14803 
14804 
14805 /*
14806 Our own "WAVECAPS" structure that contains generic information shared between WAVEOUTCAPS2 and WAVEINCAPS2 so
14807 we can do things generically and typesafely. Names are being kept the same for consistency.
14808 */
14809 typedef struct
14810 {
14811  CHAR szPname[MAXPNAMELEN];
14812  DWORD dwFormats;
14813  WORD wChannels;
14814  GUID NameGuid;
14815 } MA_WAVECAPSA;
14816 
14817 static ma_result ma_get_best_info_from_formats_flags__winmm(DWORD dwFormats, WORD channels, WORD* pBitsPerSample, DWORD* pSampleRate)
14818 {
14819  WORD bitsPerSample = 0;
14820  DWORD sampleRate = 0;
14821 
14822  if (pBitsPerSample) {
14823  *pBitsPerSample = 0;
14824  }
14825  if (pSampleRate) {
14826  *pSampleRate = 0;
14827  }
14828 
14829  if (channels == 1) {
14830  bitsPerSample = 16;
14831  if ((dwFormats & WAVE_FORMAT_48M16) != 0) {
14832  sampleRate = 48000;
14833  } else if ((dwFormats & WAVE_FORMAT_44M16) != 0) {
14834  sampleRate = 44100;
14835  } else if ((dwFormats & WAVE_FORMAT_2M16) != 0) {
14836  sampleRate = 22050;
14837  } else if ((dwFormats & WAVE_FORMAT_1M16) != 0) {
14838  sampleRate = 11025;
14839  } else if ((dwFormats & WAVE_FORMAT_96M16) != 0) {
14840  sampleRate = 96000;
14841  } else {
14842  bitsPerSample = 8;
14843  if ((dwFormats & WAVE_FORMAT_48M08) != 0) {
14844  sampleRate = 48000;
14845  } else if ((dwFormats & WAVE_FORMAT_44M08) != 0) {
14846  sampleRate = 44100;
14847  } else if ((dwFormats & WAVE_FORMAT_2M08) != 0) {
14848  sampleRate = 22050;
14849  } else if ((dwFormats & WAVE_FORMAT_1M08) != 0) {
14850  sampleRate = 11025;
14851  } else if ((dwFormats & WAVE_FORMAT_96M08) != 0) {
14852  sampleRate = 96000;
14853  } else {
14854  return MA_FORMAT_NOT_SUPPORTED;
14855  }
14856  }
14857  } else {
14858  bitsPerSample = 16;
14859  if ((dwFormats & WAVE_FORMAT_48S16) != 0) {
14860  sampleRate = 48000;
14861  } else if ((dwFormats & WAVE_FORMAT_44S16) != 0) {
14862  sampleRate = 44100;
14863  } else if ((dwFormats & WAVE_FORMAT_2S16) != 0) {
14864  sampleRate = 22050;
14865  } else if ((dwFormats & WAVE_FORMAT_1S16) != 0) {
14866  sampleRate = 11025;
14867  } else if ((dwFormats & WAVE_FORMAT_96S16) != 0) {
14868  sampleRate = 96000;
14869  } else {
14870  bitsPerSample = 8;
14871  if ((dwFormats & WAVE_FORMAT_48S08) != 0) {
14872  sampleRate = 48000;
14873  } else if ((dwFormats & WAVE_FORMAT_44S08) != 0) {
14874  sampleRate = 44100;
14875  } else if ((dwFormats & WAVE_FORMAT_2S08) != 0) {
14876  sampleRate = 22050;
14877  } else if ((dwFormats & WAVE_FORMAT_1S08) != 0) {
14878  sampleRate = 11025;
14879  } else if ((dwFormats & WAVE_FORMAT_96S08) != 0) {
14880  sampleRate = 96000;
14881  } else {
14882  return MA_FORMAT_NOT_SUPPORTED;
14883  }
14884  }
14885  }
14886 
14887  if (pBitsPerSample) {
14888  *pBitsPerSample = bitsPerSample;
14889  }
14890  if (pSampleRate) {
14891  *pSampleRate = sampleRate;
14892  }
14893 
14894  return MA_SUCCESS;
14895 }
14896 
14897 static ma_result ma_formats_flags_to_WAVEFORMATEX__winmm(DWORD dwFormats, WORD channels, WAVEFORMATEX* pWF)
14898 {
14899  MA_ASSERT(pWF != NULL);
14900 
14901  MA_ZERO_OBJECT(pWF);
14902  pWF->cbSize = sizeof(*pWF);
14903  pWF->wFormatTag = WAVE_FORMAT_PCM;
14904  pWF->nChannels = (WORD)channels;
14905  if (pWF->nChannels > 2) {
14906  pWF->nChannels = 2;
14907  }
14908 
14909  if (channels == 1) {
14910  pWF->wBitsPerSample = 16;
14911  if ((dwFormats & WAVE_FORMAT_48M16) != 0) {
14912  pWF->nSamplesPerSec = 48000;
14913  } else if ((dwFormats & WAVE_FORMAT_44M16) != 0) {
14914  pWF->nSamplesPerSec = 44100;
14915  } else if ((dwFormats & WAVE_FORMAT_2M16) != 0) {
14916  pWF->nSamplesPerSec = 22050;
14917  } else if ((dwFormats & WAVE_FORMAT_1M16) != 0) {
14918  pWF->nSamplesPerSec = 11025;
14919  } else if ((dwFormats & WAVE_FORMAT_96M16) != 0) {
14920  pWF->nSamplesPerSec = 96000;
14921  } else {
14922  pWF->wBitsPerSample = 8;
14923  if ((dwFormats & WAVE_FORMAT_48M08) != 0) {
14924  pWF->nSamplesPerSec = 48000;
14925  } else if ((dwFormats & WAVE_FORMAT_44M08) != 0) {
14926  pWF->nSamplesPerSec = 44100;
14927  } else if ((dwFormats & WAVE_FORMAT_2M08) != 0) {
14928  pWF->nSamplesPerSec = 22050;
14929  } else if ((dwFormats & WAVE_FORMAT_1M08) != 0) {
14930  pWF->nSamplesPerSec = 11025;
14931  } else if ((dwFormats & WAVE_FORMAT_96M08) != 0) {
14932  pWF->nSamplesPerSec = 96000;
14933  } else {
14934  return MA_FORMAT_NOT_SUPPORTED;
14935  }
14936  }
14937  } else {
14938  pWF->wBitsPerSample = 16;
14939  if ((dwFormats & WAVE_FORMAT_48S16) != 0) {
14940  pWF->nSamplesPerSec = 48000;
14941  } else if ((dwFormats & WAVE_FORMAT_44S16) != 0) {
14942  pWF->nSamplesPerSec = 44100;
14943  } else if ((dwFormats & WAVE_FORMAT_2S16) != 0) {
14944  pWF->nSamplesPerSec = 22050;
14945  } else if ((dwFormats & WAVE_FORMAT_1S16) != 0) {
14946  pWF->nSamplesPerSec = 11025;
14947  } else if ((dwFormats & WAVE_FORMAT_96S16) != 0) {
14948  pWF->nSamplesPerSec = 96000;
14949  } else {
14950  pWF->wBitsPerSample = 8;
14951  if ((dwFormats & WAVE_FORMAT_48S08) != 0) {
14952  pWF->nSamplesPerSec = 48000;
14953  } else if ((dwFormats & WAVE_FORMAT_44S08) != 0) {
14954  pWF->nSamplesPerSec = 44100;
14955  } else if ((dwFormats & WAVE_FORMAT_2S08) != 0) {
14956  pWF->nSamplesPerSec = 22050;
14957  } else if ((dwFormats & WAVE_FORMAT_1S08) != 0) {
14958  pWF->nSamplesPerSec = 11025;
14959  } else if ((dwFormats & WAVE_FORMAT_96S08) != 0) {
14960  pWF->nSamplesPerSec = 96000;
14961  } else {
14962  return MA_FORMAT_NOT_SUPPORTED;
14963  }
14964  }
14965  }
14966 
14967  pWF->nBlockAlign = (pWF->nChannels * pWF->wBitsPerSample) / 8;
14968  pWF->nAvgBytesPerSec = pWF->nBlockAlign * pWF->nSamplesPerSec;
14969 
14970  return MA_SUCCESS;
14971 }
14972 
14973 static ma_result ma_context_get_device_info_from_WAVECAPS(ma_context* pContext, MA_WAVECAPSA* pCaps, ma_device_info* pDeviceInfo)
14974 {
14975  WORD bitsPerSample;
14976  DWORD sampleRate;
14977  ma_result result;
14978 
14979  MA_ASSERT(pContext != NULL);
14980  MA_ASSERT(pCaps != NULL);
14981  MA_ASSERT(pDeviceInfo != NULL);
14982 
14983  /*
14984  Name / Description
14985 
14986  Unfortunately the name specified in WAVE(OUT/IN)CAPS2 is limited to 31 characters. This results in an unprofessional looking
14987  situation where the names of the devices are truncated. To help work around this, we need to look at the name GUID and try
14988  looking in the registry for the full name. If we can't find it there, we need to just fall back to the default name.
14989  */
14990 
14991  /* Set the default to begin with. */
14992  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), pCaps->szPname, (size_t)-1);
14993 
14994  /*
14995  Now try the registry. There's a few things to consider here:
14996  - The name GUID can be null, in which we case we just need to stick to the original 31 characters.
14997  - If the name GUID is not present in the registry we'll also need to stick to the original 31 characters.
14998  - I like consistency, so I want the returned device names to be consistent with those returned by WASAPI and DirectSound. The
14999  problem, however is that WASAPI and DirectSound use "<component> (<name>)" format (such as "Speakers (High Definition Audio)"),
15000  but WinMM does not specificy the component name. From my admittedly limited testing, I've notice the component name seems to
15001  usually fit within the 31 characters of the fixed sized buffer, so what I'm going to do is parse that string for the component
15002  name, and then concatenate the name from the registry.
15003  */
15004  if (!ma_is_guid_equal(&pCaps->NameGuid, &MA_GUID_NULL)) {
15005  wchar_t guidStrW[256];
15006  if (((MA_PFN_StringFromGUID2)pContext->win32.StringFromGUID2)(&pCaps->NameGuid, guidStrW, ma_countof(guidStrW)) > 0) {
15007  char guidStr[256];
15008  char keyStr[1024];
15009  HKEY hKey;
15010 
15011  WideCharToMultiByte(CP_UTF8, 0, guidStrW, -1, guidStr, sizeof(guidStr), 0, FALSE);
15012 
15013  ma_strcpy_s(keyStr, sizeof(keyStr), "SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\");
15014  ma_strcat_s(keyStr, sizeof(keyStr), guidStr);
15015 
15016  if (((MA_PFN_RegOpenKeyExA)pContext->win32.RegOpenKeyExA)(HKEY_LOCAL_MACHINE, keyStr, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
15017  BYTE nameFromReg[512];
15018  DWORD nameFromRegSize = sizeof(nameFromReg);
15019  result = ((MA_PFN_RegQueryValueExA)pContext->win32.RegQueryValueExA)(hKey, "Name", 0, NULL, (LPBYTE)nameFromReg, (LPDWORD)&nameFromRegSize);
15020  ((MA_PFN_RegCloseKey)pContext->win32.RegCloseKey)(hKey);
15021 
15022  if (result == ERROR_SUCCESS) {
15023  /* We have the value from the registry, so now we need to construct the name string. */
15024  char name[1024];
15025  if (ma_strcpy_s(name, sizeof(name), pDeviceInfo->name) == 0) {
15026  char* nameBeg = ma_find_last_character(name, '(');
15027  if (nameBeg != NULL) {
15028  size_t leadingLen = (nameBeg - name);
15029  ma_strncpy_s(nameBeg + 1, sizeof(name) - leadingLen, (const char*)nameFromReg, (size_t)-1);
15030 
15031  /* The closing ")", if it can fit. */
15032  if (leadingLen + nameFromRegSize < sizeof(name)-1) {
15033  ma_strcat_s(name, sizeof(name), ")");
15034  }
15035 
15036  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), name, (size_t)-1);
15037  }
15038  }
15039  }
15040  }
15041  }
15042  }
15043 
15044 
15045  result = ma_get_best_info_from_formats_flags__winmm(pCaps->dwFormats, pCaps->wChannels, &bitsPerSample, &sampleRate);
15046  if (result != MA_SUCCESS) {
15047  return result;
15048  }
15049 
15050  pDeviceInfo->minChannels = pCaps->wChannels;
15051  pDeviceInfo->maxChannels = pCaps->wChannels;
15052  pDeviceInfo->minSampleRate = sampleRate;
15053  pDeviceInfo->maxSampleRate = sampleRate;
15054  pDeviceInfo->formatCount = 1;
15055  if (bitsPerSample == 8) {
15056  pDeviceInfo->formats[0] = ma_format_u8;
15057  } else if (bitsPerSample == 16) {
15058  pDeviceInfo->formats[0] = ma_format_s16;
15059  } else if (bitsPerSample == 24) {
15060  pDeviceInfo->formats[0] = ma_format_s24;
15061  } else if (bitsPerSample == 32) {
15062  pDeviceInfo->formats[0] = ma_format_s32;
15063  } else {
15064  return MA_FORMAT_NOT_SUPPORTED;
15065  }
15066 
15067  return MA_SUCCESS;
15068 }
15069 
15070 static ma_result ma_context_get_device_info_from_WAVEOUTCAPS2(ma_context* pContext, MA_WAVEOUTCAPS2A* pCaps, ma_device_info* pDeviceInfo)
15071 {
15072  MA_WAVECAPSA caps;
15073 
15074  MA_ASSERT(pContext != NULL);
15075  MA_ASSERT(pCaps != NULL);
15076  MA_ASSERT(pDeviceInfo != NULL);
15077 
15078  MA_COPY_MEMORY(caps.szPname, pCaps->szPname, sizeof(caps.szPname));
15079  caps.dwFormats = pCaps->dwFormats;
15080  caps.wChannels = pCaps->wChannels;
15081  caps.NameGuid = pCaps->NameGuid;
15082  return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo);
15083 }
15084 
15085 static ma_result ma_context_get_device_info_from_WAVEINCAPS2(ma_context* pContext, MA_WAVEINCAPS2A* pCaps, ma_device_info* pDeviceInfo)
15086 {
15087  MA_WAVECAPSA caps;
15088 
15089  MA_ASSERT(pContext != NULL);
15090  MA_ASSERT(pCaps != NULL);
15091  MA_ASSERT(pDeviceInfo != NULL);
15092 
15093  MA_COPY_MEMORY(caps.szPname, pCaps->szPname, sizeof(caps.szPname));
15094  caps.dwFormats = pCaps->dwFormats;
15095  caps.wChannels = pCaps->wChannels;
15096  caps.NameGuid = pCaps->NameGuid;
15097  return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo);
15098 }
15099 
15100 
15101 static ma_bool32 ma_context_is_device_id_equal__winmm(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
15102 {
15103  MA_ASSERT(pContext != NULL);
15104  MA_ASSERT(pID0 != NULL);
15105  MA_ASSERT(pID1 != NULL);
15106  (void)pContext;
15107 
15108  return pID0->winmm == pID1->winmm;
15109 }
15110 
15111 static ma_result ma_context_enumerate_devices__winmm(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
15112 {
15113  UINT playbackDeviceCount;
15114  UINT captureDeviceCount;
15115  UINT iPlaybackDevice;
15116  UINT iCaptureDevice;
15117 
15118  MA_ASSERT(pContext != NULL);
15119  MA_ASSERT(callback != NULL);
15120 
15121  /* Playback. */
15122  playbackDeviceCount = ((MA_PFN_waveOutGetNumDevs)pContext->winmm.waveOutGetNumDevs)();
15123  for (iPlaybackDevice = 0; iPlaybackDevice < playbackDeviceCount; ++iPlaybackDevice) {
15124  MMRESULT result;
15125  MA_WAVEOUTCAPS2A caps;
15126 
15127  MA_ZERO_OBJECT(&caps);
15128 
15129  result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(iPlaybackDevice, (WAVEOUTCAPSA*)&caps, sizeof(caps));
15130  if (result == MMSYSERR_NOERROR) {
15131  ma_device_info deviceInfo;
15132 
15133  MA_ZERO_OBJECT(&deviceInfo);
15134  deviceInfo.id.winmm = iPlaybackDevice;
15135 
15136  if (ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, &deviceInfo) == MA_SUCCESS) {
15137  ma_bool32 cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
15138  if (cbResult == MA_FALSE) {
15139  return MA_SUCCESS; /* Enumeration was stopped. */
15140  }
15141  }
15142  }
15143  }
15144 
15145  /* Capture. */
15146  captureDeviceCount = ((MA_PFN_waveInGetNumDevs)pContext->winmm.waveInGetNumDevs)();
15147  for (iCaptureDevice = 0; iCaptureDevice < captureDeviceCount; ++iCaptureDevice) {
15148  MMRESULT result;
15149  MA_WAVEINCAPS2A caps;
15150 
15151  MA_ZERO_OBJECT(&caps);
15152 
15153  result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(iCaptureDevice, (WAVEINCAPSA*)&caps, sizeof(caps));
15154  if (result == MMSYSERR_NOERROR) {
15155  ma_device_info deviceInfo;
15156 
15157  MA_ZERO_OBJECT(&deviceInfo);
15158  deviceInfo.id.winmm = iCaptureDevice;
15159 
15160  if (ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, &deviceInfo) == MA_SUCCESS) {
15161  ma_bool32 cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
15162  if (cbResult == MA_FALSE) {
15163  return MA_SUCCESS; /* Enumeration was stopped. */
15164  }
15165  }
15166  }
15167  }
15168 
15169  return MA_SUCCESS;
15170 }
15171 
15172 static ma_result ma_context_get_device_info__winmm(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
15173 {
15174  UINT winMMDeviceID;
15175 
15176  MA_ASSERT(pContext != NULL);
15177 
15178  if (shareMode == ma_share_mode_exclusive) {
15180  }
15181 
15182  winMMDeviceID = 0;
15183  if (pDeviceID != NULL) {
15184  winMMDeviceID = (UINT)pDeviceID->winmm;
15185  }
15186 
15187  pDeviceInfo->id.winmm = winMMDeviceID;
15188 
15189  if (deviceType == ma_device_type_playback) {
15190  MMRESULT result;
15191  MA_WAVEOUTCAPS2A caps;
15192 
15193  MA_ZERO_OBJECT(&caps);
15194 
15195  result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceID, (WAVEOUTCAPSA*)&caps, sizeof(caps));
15196  if (result == MMSYSERR_NOERROR) {
15197  return ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, pDeviceInfo);
15198  }
15199  } else {
15200  MMRESULT result;
15201  MA_WAVEINCAPS2A caps;
15202 
15203  MA_ZERO_OBJECT(&caps);
15204 
15205  result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceID, (WAVEINCAPSA*)&caps, sizeof(caps));
15206  if (result == MMSYSERR_NOERROR) {
15207  return ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, pDeviceInfo);
15208  }
15209  }
15210 
15211  return MA_NO_DEVICE;
15212 }
15213 
15214 
15215 static void ma_device_uninit__winmm(ma_device* pDevice)
15216 {
15217  MA_ASSERT(pDevice != NULL);
15218 
15219  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
15220  ((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture);
15221  CloseHandle((HANDLE)pDevice->winmm.hEventCapture);
15222  }
15223 
15224  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
15225  ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
15226  ((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
15227  CloseHandle((HANDLE)pDevice->winmm.hEventPlayback);
15228  }
15229 
15230  ma__free_from_callbacks(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks);
15231 
15232  MA_ZERO_OBJECT(&pDevice->winmm); /* Safety. */
15233 }
15234 
15235 static ma_result ma_device_init__winmm(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
15236 {
15237  const char* errorMsg = "";
15238  ma_result errorCode = MA_ERROR;
15239  ma_result result = MA_SUCCESS;
15240  ma_uint32 heapSize;
15241  UINT winMMDeviceIDPlayback = 0;
15242  UINT winMMDeviceIDCapture = 0;
15243  ma_uint32 periodSizeInMilliseconds;
15244 
15245  MA_ASSERT(pDevice != NULL);
15246  MA_ZERO_OBJECT(&pDevice->winmm);
15247 
15248  if (pConfig->deviceType == ma_device_type_loopback) {
15250  }
15251 
15252  /* No exlusive mode with WinMM. */
15256  }
15257 
15258  periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
15259  if (periodSizeInMilliseconds == 0) {
15260  periodSizeInMilliseconds = ma_calculate_buffer_size_in_milliseconds_from_frames(pConfig->periodSizeInFrames, pConfig->sampleRate);
15261  }
15262 
15263  /* WinMM has horrible latency. */
15264  if (pDevice->usingDefaultBufferSize) {
15266  periodSizeInMilliseconds = 40;
15267  } else {
15268  periodSizeInMilliseconds = 400;
15269  }
15270  }
15271 
15272 
15273  if (pConfig->playback.pDeviceID != NULL) {
15274  winMMDeviceIDPlayback = (UINT)pConfig->playback.pDeviceID->winmm;
15275  }
15276  if (pConfig->capture.pDeviceID != NULL) {
15277  winMMDeviceIDCapture = (UINT)pConfig->capture.pDeviceID->winmm;
15278  }
15279 
15280  /* The capture device needs to be initialized first. */
15281  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
15282  WAVEINCAPSA caps;
15283  WAVEFORMATEX wf;
15284  MMRESULT resultMM;
15285 
15286  /* We use an event to know when a new fragment needs to be enqueued. */
15287  pDevice->winmm.hEventCapture = (ma_handle)CreateEventW(NULL, TRUE, TRUE, NULL);
15288  if (pDevice->winmm.hEventCapture == NULL) {
15289  errorMsg = "[WinMM] Failed to create event for fragment enqueing for the capture device.", errorCode = ma_result_from_GetLastError(GetLastError());
15290  goto on_error;
15291  }
15292 
15293  /* The format should be based on the device's actual format. */
15294  if (((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceIDCapture, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
15295  errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
15296  goto on_error;
15297  }
15298 
15299  result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf);
15300  if (result != MA_SUCCESS) {
15301  errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result;
15302  goto on_error;
15303  }
15304 
15305  resultMM = ((MA_PFN_waveInOpen)pDevice->pContext->winmm.waveInOpen)((LPHWAVEIN)&pDevice->winmm.hDeviceCapture, winMMDeviceIDCapture, &wf, (DWORD_PTR)pDevice->winmm.hEventCapture, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
15306  if (resultMM != MMSYSERR_NOERROR) {
15307  errorMsg = "[WinMM] Failed to open capture device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
15308  goto on_error;
15309  }
15310 
15311  pDevice->capture.internalFormat = ma_format_from_WAVEFORMATEX(&wf);
15312  pDevice->capture.internalChannels = wf.nChannels;
15313  pDevice->capture.internalSampleRate = wf.nSamplesPerSec;
15315  pDevice->capture.internalPeriods = pConfig->periods;
15317  }
15318 
15319  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
15320  WAVEOUTCAPSA caps;
15321  WAVEFORMATEX wf;
15322  MMRESULT resultMM;
15323 
15324  /* We use an event to know when a new fragment needs to be enqueued. */
15325  pDevice->winmm.hEventPlayback = (ma_handle)CreateEvent(NULL, TRUE, TRUE, NULL);
15326  if (pDevice->winmm.hEventPlayback == NULL) {
15327  errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError());
15328  goto on_error;
15329  }
15330 
15331  /* The format should be based on the device's actual format. */
15332  if (((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
15333  errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
15334  goto on_error;
15335  }
15336 
15337  result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf);
15338  if (result != MA_SUCCESS) {
15339  errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result;
15340  goto on_error;
15341  }
15342 
15343  resultMM = ((MA_PFN_waveOutOpen)pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevicePlayback, winMMDeviceIDPlayback, &wf, (DWORD_PTR)pDevice->winmm.hEventPlayback, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
15344  if (resultMM != MMSYSERR_NOERROR) {
15345  errorMsg = "[WinMM] Failed to open playback device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
15346  goto on_error;
15347  }
15348 
15349  pDevice->playback.internalFormat = ma_format_from_WAVEFORMATEX(&wf);
15350  pDevice->playback.internalChannels = wf.nChannels;
15351  pDevice->playback.internalSampleRate = wf.nSamplesPerSec;
15353  pDevice->playback.internalPeriods = pConfig->periods;
15355  }
15356 
15357  /*
15358  The heap allocated data is allocated like so:
15359 
15360  [Capture WAVEHDRs][Playback WAVEHDRs][Capture Intermediary Buffer][Playback Intermediary Buffer]
15361  */
15362  heapSize = 0;
15363  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
15364  heapSize += sizeof(WAVEHDR)*pDevice->capture.internalPeriods + (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
15365  }
15366  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
15368  }
15369 
15370  pDevice->winmm._pHeapData = (ma_uint8*)ma__calloc_from_callbacks(heapSize, &pContext->allocationCallbacks);
15371  if (pDevice->winmm._pHeapData == NULL) {
15372  errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MA_OUT_OF_MEMORY;
15373  goto on_error;
15374  }
15375 
15376  MA_ZERO_MEMORY(pDevice->winmm._pHeapData, heapSize);
15377 
15378  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
15379  ma_uint32 iPeriod;
15380 
15381  if (pConfig->deviceType == ma_device_type_capture) {
15382  pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData;
15383  pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods));
15384  } else {
15385  pDevice->winmm.pWAVEHDRCapture = pDevice->winmm._pHeapData;
15386  pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods + pDevice->playback.internalPeriods));
15387  }
15388 
15389  /* Prepare headers. */
15390  for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
15391  ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalFormat, pDevice->capture.internalChannels);
15392 
15393  ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBufferCapture + (periodSizeInBytes*iPeriod));
15394  ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwBufferLength = periodSizeInBytes;
15395  ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwFlags = 0L;
15396  ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwLoops = 0L;
15397  ((MA_PFN_waveInPrepareHeader)pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
15398 
15399  /*
15400  The user data of the WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means
15401  it's unlocked and available for writing. A value of 1 means it's locked.
15402  */
15403  ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwUser = 0;
15404  }
15405  }
15406  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
15407  ma_uint32 iPeriod;
15408 
15409  if (pConfig->deviceType == ma_device_type_playback) {
15410  pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData;
15411  pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*pDevice->playback.internalPeriods);
15412  } else {
15413  pDevice->winmm.pWAVEHDRPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods));
15414  pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDevice->capture.internalPeriods + pDevice->playback.internalPeriods)) + (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
15415  }
15416 
15417  /* Prepare headers. */
15418  for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) {
15419  ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalFormat, pDevice->playback.internalChannels);
15420 
15421  ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].lpData = (LPSTR)(pDevice->winmm.pIntermediaryBufferPlayback + (periodSizeInBytes*iPeriod));
15422  ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwBufferLength = periodSizeInBytes;
15423  ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwFlags = 0L;
15424  ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwLoops = 0L;
15425  ((MA_PFN_waveOutPrepareHeader)pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
15426 
15427  /*
15428  The user data of the WAVEHDR structure is a single flag the controls whether or not it is ready for writing. Consider it to be named "isLocked". A value of 0 means
15429  it's unlocked and available for writing. A value of 1 means it's locked.
15430  */
15431  ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwUser = 0;
15432  }
15433  }
15434 
15435  return MA_SUCCESS;
15436 
15437 on_error:
15438  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
15439  if (pDevice->winmm.pWAVEHDRCapture != NULL) {
15440  ma_uint32 iPeriod;
15441  for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
15442  ((MA_PFN_waveInUnprepareHeader)pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
15443  }
15444  }
15445 
15446  ((MA_PFN_waveInClose)pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture);
15447  }
15448 
15449  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
15450  if (pDevice->winmm.pWAVEHDRCapture != NULL) {
15451  ma_uint32 iPeriod;
15452  for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) {
15453  ((MA_PFN_waveOutUnprepareHeader)pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
15454  }
15455  }
15456 
15457  ((MA_PFN_waveOutClose)pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
15458  }
15459 
15460  ma__free_from_callbacks(pDevice->winmm._pHeapData, &pContext->allocationCallbacks);
15461  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, errorMsg, errorCode);
15462 }
15463 
15464 static ma_result ma_device_stop__winmm(ma_device* pDevice)
15465 {
15466  MMRESULT resultMM;
15467 
15468  MA_ASSERT(pDevice != NULL);
15469 
15470  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
15471  if (pDevice->winmm.hDeviceCapture == NULL) {
15472  return MA_INVALID_ARGS;
15473  }
15474 
15475  resultMM = ((MA_PFN_waveInReset)pDevice->pContext->winmm.waveInReset)((HWAVEIN)pDevice->winmm.hDeviceCapture);
15476  if (resultMM != MMSYSERR_NOERROR) {
15477  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset capture device.", ma_result_from_MMRESULT(resultMM));
15478  }
15479  }
15480 
15481  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
15482  ma_uint32 iPeriod;
15483  WAVEHDR* pWAVEHDR;
15484 
15485  if (pDevice->winmm.hDevicePlayback == NULL) {
15486  return MA_INVALID_ARGS;
15487  }
15488 
15489  /* We need to drain the device. To do this we just loop over each header and if it's locked just wait for the event. */
15490  pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback;
15491  for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; iPeriod += 1) {
15492  if (pWAVEHDR[iPeriod].dwUser == 1) { /* 1 = locked. */
15493  if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventPlayback, INFINITE) != WAIT_OBJECT_0) {
15494  break; /* An error occurred so just abandon ship and stop the device without draining. */
15495  }
15496 
15497  pWAVEHDR[iPeriod].dwUser = 0;
15498  }
15499  }
15500 
15501  resultMM = ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
15502  if (resultMM != MMSYSERR_NOERROR) {
15503  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset playback device.", ma_result_from_MMRESULT(resultMM));
15504  }
15505  }
15506 
15507  return MA_SUCCESS;
15508 }
15509 
15510 static ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
15511 {
15512  ma_result result = MA_SUCCESS;
15513  MMRESULT resultMM;
15514  ma_uint32 totalFramesWritten;
15515  WAVEHDR* pWAVEHDR;
15516 
15517  MA_ASSERT(pDevice != NULL);
15518  MA_ASSERT(pPCMFrames != NULL);
15519 
15520  if (pFramesWritten != NULL) {
15521  *pFramesWritten = 0;
15522  }
15523 
15524  pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback;
15525 
15526  /* Keep processing as much data as possible. */
15527  totalFramesWritten = 0;
15528  while (totalFramesWritten < frameCount) {
15529  /* If the current header has some space available we need to write part of it. */
15530  if (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser == 0) { /* 0 = unlocked. */
15531  /*
15532  This header has room in it. We copy as much of it as we can. If we end up fully consuming the buffer we need to
15533  write it out and move on to the next iteration.
15534  */
15536  ma_uint32 framesRemainingInHeader = (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwBufferLength/bpf) - pDevice->winmm.headerFramesConsumedPlayback;
15537 
15538  ma_uint32 framesToCopy = ma_min(framesRemainingInHeader, (frameCount - totalFramesWritten));
15539  const void* pSrc = ma_offset_ptr(pPCMFrames, totalFramesWritten*bpf);
15540  void* pDst = ma_offset_ptr(pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].lpData, pDevice->winmm.headerFramesConsumedPlayback*bpf);
15541  MA_COPY_MEMORY(pDst, pSrc, framesToCopy*bpf);
15542 
15543  pDevice->winmm.headerFramesConsumedPlayback += framesToCopy;
15544  totalFramesWritten += framesToCopy;
15545 
15546  /* If we've consumed the buffer entirely we need to write it out to the device. */
15547  if (pDevice->winmm.headerFramesConsumedPlayback == (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwBufferLength/bpf)) {
15548  pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser = 1; /* 1 = locked. */
15549  pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags &= ~WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */
15550 
15551  /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */
15552  ResetEvent((HANDLE)pDevice->winmm.hEventPlayback);
15553 
15554  /* The device will be started here. */
15555  resultMM = ((MA_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &pWAVEHDR[pDevice->winmm.iNextHeaderPlayback], sizeof(WAVEHDR));
15556  if (resultMM != MMSYSERR_NOERROR) {
15557  result = ma_result_from_MMRESULT(resultMM);
15558  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] waveOutWrite() failed.", result);
15559  break;
15560  }
15561 
15562  /* Make sure we move to the next header. */
15563  pDevice->winmm.iNextHeaderPlayback = (pDevice->winmm.iNextHeaderPlayback + 1) % pDevice->playback.internalPeriods;
15564  pDevice->winmm.headerFramesConsumedPlayback = 0;
15565  }
15566 
15567  /* If at this point we have consumed the entire input buffer we can return. */
15568  MA_ASSERT(totalFramesWritten <= frameCount);
15569  if (totalFramesWritten == frameCount) {
15570  break;
15571  }
15572 
15573  /* Getting here means there's more to process. */
15574  continue;
15575  }
15576 
15577  /* Getting here means there isn't enough room in the buffer and we need to wait for one to become available. */
15578  if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventPlayback, INFINITE) != WAIT_OBJECT_0) {
15579  result = MA_ERROR;
15580  break;
15581  }
15582 
15583  /* Something happened. If the next buffer has been marked as done we need to reset a bit of state. */
15584  if ((pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags & WHDR_DONE) != 0) {
15585  pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser = 0; /* 0 = unlocked (make it available for writing). */
15586  pDevice->winmm.headerFramesConsumedPlayback = 0;
15587  }
15588 
15589  /* If the device has been stopped we need to break. */
15590  if (ma_device__get_state(pDevice) != MA_STATE_STARTED) {
15591  break;
15592  }
15593  }
15594 
15595  if (pFramesWritten != NULL) {
15596  *pFramesWritten = totalFramesWritten;
15597  }
15598 
15599  return result;
15600 }
15601 
15602 static ma_result ma_device_read__winmm(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
15603 {
15604  ma_result result = MA_SUCCESS;
15605  MMRESULT resultMM;
15606  ma_uint32 totalFramesRead;
15607  WAVEHDR* pWAVEHDR;
15608 
15609  MA_ASSERT(pDevice != NULL);
15610  MA_ASSERT(pPCMFrames != NULL);
15611 
15612  if (pFramesRead != NULL) {
15613  *pFramesRead = 0;
15614  }
15615 
15616  pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRCapture;
15617 
15618  /* Keep processing as much data as possible. */
15619  totalFramesRead = 0;
15620  while (totalFramesRead < frameCount) {
15621  /* If the current header has some space available we need to write part of it. */
15622  if (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser == 0) { /* 0 = unlocked. */
15623  /* The buffer is available for reading. If we fully consume it we need to add it back to the buffer. */
15625  ma_uint32 framesRemainingInHeader = (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwBufferLength/bpf) - pDevice->winmm.headerFramesConsumedCapture;
15626 
15627  ma_uint32 framesToCopy = ma_min(framesRemainingInHeader, (frameCount - totalFramesRead));
15628  const void* pSrc = ma_offset_ptr(pWAVEHDR[pDevice->winmm.iNextHeaderCapture].lpData, pDevice->winmm.headerFramesConsumedCapture*bpf);
15629  void* pDst = ma_offset_ptr(pPCMFrames, totalFramesRead*bpf);
15630  MA_COPY_MEMORY(pDst, pSrc, framesToCopy*bpf);
15631 
15632  pDevice->winmm.headerFramesConsumedCapture += framesToCopy;
15633  totalFramesRead += framesToCopy;
15634 
15635  /* If we've consumed the buffer entirely we need to add it back to the device. */
15636  if (pDevice->winmm.headerFramesConsumedCapture == (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwBufferLength/bpf)) {
15637  pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser = 1; /* 1 = locked. */
15638  pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags &= ~WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */
15639 
15640  /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */
15641  ResetEvent((HANDLE)pDevice->winmm.hEventCapture);
15642 
15643  /* The device will be started here. */
15644  resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[pDevice->winmm.iNextHeaderCapture], sizeof(WAVEHDR));
15645  if (resultMM != MMSYSERR_NOERROR) {
15646  result = ma_result_from_MMRESULT(resultMM);
15647  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] waveInAddBuffer() failed.", result);
15648  break;
15649  }
15650 
15651  /* Make sure we move to the next header. */
15652  pDevice->winmm.iNextHeaderCapture = (pDevice->winmm.iNextHeaderCapture + 1) % pDevice->capture.internalPeriods;
15653  pDevice->winmm.headerFramesConsumedCapture = 0;
15654  }
15655 
15656  /* If at this point we have filled the entire input buffer we can return. */
15657  MA_ASSERT(totalFramesRead <= frameCount);
15658  if (totalFramesRead == frameCount) {
15659  break;
15660  }
15661 
15662  /* Getting here means there's more to process. */
15663  continue;
15664  }
15665 
15666  /* Getting here means there isn't enough any data left to send to the client which means we need to wait for more. */
15667  if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventCapture, INFINITE) != WAIT_OBJECT_0) {
15668  result = MA_ERROR;
15669  break;
15670  }
15671 
15672  /* Something happened. If the next buffer has been marked as done we need to reset a bit of state. */
15673  if ((pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags & WHDR_DONE) != 0) {
15674  pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser = 0; /* 0 = unlocked (make it available for reading). */
15675  pDevice->winmm.headerFramesConsumedCapture = 0;
15676  }
15677 
15678  /* If the device has been stopped we need to break. */
15679  if (ma_device__get_state(pDevice) != MA_STATE_STARTED) {
15680  break;
15681  }
15682  }
15683 
15684  if (pFramesRead != NULL) {
15685  *pFramesRead = totalFramesRead;
15686  }
15687 
15688  return result;
15689 }
15690 
15691 static ma_result ma_device_main_loop__winmm(ma_device* pDevice)
15692 {
15693  ma_result result = MA_SUCCESS;
15694  ma_bool32 exitLoop = MA_FALSE;
15695 
15696  MA_ASSERT(pDevice != NULL);
15697 
15698  /* The capture device needs to be started immediately. */
15699  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
15700  MMRESULT resultMM;
15701  WAVEHDR* pWAVEHDR;
15702  ma_uint32 iPeriod;
15703 
15704  pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRCapture;
15705 
15706  /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */
15707  ResetEvent((HANDLE)pDevice->winmm.hEventCapture);
15708 
15709  /* To start the device we attach all of the buffers and then start it. As the buffers are filled with data we will get notifications. */
15710  for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
15711  resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
15712  if (resultMM != MMSYSERR_NOERROR) {
15713  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to attach input buffers to capture device in preparation for capture.", ma_result_from_MMRESULT(resultMM));
15714  }
15715 
15716  /* Make sure all of the buffers start out locked. We don't want to access them until the backend tells us we can. */
15717  pWAVEHDR[iPeriod].dwUser = 1; /* 1 = locked. */
15718  }
15719 
15720  /* Capture devices need to be explicitly started, unlike playback devices. */
15721  resultMM = ((MA_PFN_waveInStart)pDevice->pContext->winmm.waveInStart)((HWAVEIN)pDevice->winmm.hDeviceCapture);
15722  if (resultMM != MMSYSERR_NOERROR) {
15723  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device.", ma_result_from_MMRESULT(resultMM));
15724  }
15725  }
15726 
15727 
15728  while (ma_device__get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
15729  switch (pDevice->type)
15730  {
15731  case ma_device_type_duplex:
15732  {
15733  /* The process is: device_read -> convert -> callback -> convert -> device_write */
15734  ma_uint32 totalCapturedDeviceFramesProcessed = 0;
15735  ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
15736 
15737  while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
15738  ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
15739  ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
15740  ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
15741  ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
15742  ma_uint32 capturedDeviceFramesRemaining;
15743  ma_uint32 capturedDeviceFramesProcessed;
15744  ma_uint32 capturedDeviceFramesToProcess;
15745  ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed;
15746  if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) {
15747  capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames;
15748  }
15749 
15750  result = ma_device_read__winmm(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess);
15751  if (result != MA_SUCCESS) {
15752  exitLoop = MA_TRUE;
15753  break;
15754  }
15755 
15756  capturedDeviceFramesRemaining = capturedDeviceFramesToProcess;
15757  capturedDeviceFramesProcessed = 0;
15758 
15759  for (;;) {
15760  ma_uint8 capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
15761  ma_uint8 playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
15762  ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
15763  ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
15764  ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames);
15765  ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining;
15766  ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
15767 
15768  /* Convert capture data from device format to client format. */
15769  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration);
15770  if (result != MA_SUCCESS) {
15771  break;
15772  }
15773 
15774  /*
15775  If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small
15776  which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
15777  */
15778  if (capturedClientFramesToProcessThisIteration == 0) {
15779  break;
15780  }
15781 
15782  ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/
15783 
15784  capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
15785  capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
15786 
15787  /* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */
15788  for (;;) {
15789  ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration;
15790  ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames;
15791  result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount);
15792  if (result != MA_SUCCESS) {
15793  break;
15794  }
15795 
15796  result = ma_device_write__winmm(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL); /* Safe cast. */
15797  if (result != MA_SUCCESS) {
15798  exitLoop = MA_TRUE;
15799  break;
15800  }
15801 
15802  capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount; /* Safe cast. */
15803  if (capturedClientFramesToProcessThisIteration == 0) {
15804  break;
15805  }
15806  }
15807 
15808  /* In case an error happened from ma_device_write__winmm()... */
15809  if (result != MA_SUCCESS) {
15810  exitLoop = MA_TRUE;
15811  break;
15812  }
15813  }
15814 
15815  totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed;
15816  }
15817  } break;
15818 
15820  {
15821  /* We read in chunks of the period size, but use a stack allocated buffer for the intermediary. */
15822  ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
15823  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
15824  ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
15825  ma_uint32 framesReadThisPeriod = 0;
15826  while (framesReadThisPeriod < periodSizeInFrames) {
15827  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
15828  ma_uint32 framesProcessed;
15829  ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
15830  if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
15831  framesToReadThisIteration = intermediaryBufferSizeInFrames;
15832  }
15833 
15834  result = ma_device_read__winmm(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
15835  if (result != MA_SUCCESS) {
15836  exitLoop = MA_TRUE;
15837  break;
15838  }
15839 
15840  ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
15841 
15842  framesReadThisPeriod += framesProcessed;
15843  }
15844  } break;
15845 
15847  {
15848  /* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
15849  ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
15850  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
15851  ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
15852  ma_uint32 framesWrittenThisPeriod = 0;
15853  while (framesWrittenThisPeriod < periodSizeInFrames) {
15854  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
15855  ma_uint32 framesProcessed;
15856  ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
15857  if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
15858  framesToWriteThisIteration = intermediaryBufferSizeInFrames;
15859  }
15860 
15861  ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
15862 
15863  result = ma_device_write__winmm(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
15864  if (result != MA_SUCCESS) {
15865  exitLoop = MA_TRUE;
15866  break;
15867  }
15868 
15869  framesWrittenThisPeriod += framesProcessed;
15870  }
15871  } break;
15872 
15873  /* To silence a warning. Will never hit this. */
15875  default: break;
15876  }
15877  }
15878 
15879 
15880  /* Here is where the device is started. */
15881  ma_device_stop__winmm(pDevice);
15882 
15883  return result;
15884 }
15885 
15886 static ma_result ma_context_uninit__winmm(ma_context* pContext)
15887 {
15888  MA_ASSERT(pContext != NULL);
15889  MA_ASSERT(pContext->backend == ma_backend_winmm);
15890 
15891  ma_dlclose(pContext, pContext->winmm.hWinMM);
15892  return MA_SUCCESS;
15893 }
15894 
15895 static ma_result ma_context_init__winmm(const ma_context_config* pConfig, ma_context* pContext)
15896 {
15897  MA_ASSERT(pContext != NULL);
15898 
15899  (void)pConfig;
15900 
15901  pContext->winmm.hWinMM = ma_dlopen(pContext, "winmm.dll");
15902  if (pContext->winmm.hWinMM == NULL) {
15903  return MA_NO_BACKEND;
15904  }
15905 
15906  pContext->winmm.waveOutGetNumDevs = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetNumDevs");
15907  pContext->winmm.waveOutGetDevCapsA = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetDevCapsA");
15908  pContext->winmm.waveOutOpen = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutOpen");
15909  pContext->winmm.waveOutClose = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutClose");
15910  pContext->winmm.waveOutPrepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutPrepareHeader");
15911  pContext->winmm.waveOutUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutUnprepareHeader");
15912  pContext->winmm.waveOutWrite = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutWrite");
15913  pContext->winmm.waveOutReset = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutReset");
15914  pContext->winmm.waveInGetNumDevs = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetNumDevs");
15915  pContext->winmm.waveInGetDevCapsA = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetDevCapsA");
15916  pContext->winmm.waveInOpen = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInOpen");
15917  pContext->winmm.waveInClose = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInClose");
15918  pContext->winmm.waveInPrepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInPrepareHeader");
15919  pContext->winmm.waveInUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInUnprepareHeader");
15920  pContext->winmm.waveInAddBuffer = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInAddBuffer");
15921  pContext->winmm.waveInStart = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInStart");
15922  pContext->winmm.waveInReset = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInReset");
15923 
15924  pContext->onUninit = ma_context_uninit__winmm;
15925  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__winmm;
15926  pContext->onEnumDevices = ma_context_enumerate_devices__winmm;
15927  pContext->onGetDeviceInfo = ma_context_get_device_info__winmm;
15928  pContext->onDeviceInit = ma_device_init__winmm;
15929  pContext->onDeviceUninit = ma_device_uninit__winmm;
15930  pContext->onDeviceStart = NULL; /* Not used with synchronous backends. */
15931  pContext->onDeviceStop = NULL; /* Not used with synchronous backends. */
15932  pContext->onDeviceMainLoop = ma_device_main_loop__winmm;
15933 
15934  return MA_SUCCESS;
15935 }
15936 #endif
15937 
15938 
15939 
15940 
15941 /******************************************************************************
15942 
15943 ALSA Backend
15944 
15945 ******************************************************************************/
15946 #ifdef MA_HAS_ALSA
15947 
15948 #ifdef MA_NO_RUNTIME_LINKING
15949 #include <alsa/asoundlib.h>
15950 typedef snd_pcm_uframes_t ma_snd_pcm_uframes_t;
15951 typedef snd_pcm_sframes_t ma_snd_pcm_sframes_t;
15952 typedef snd_pcm_stream_t ma_snd_pcm_stream_t;
15953 typedef snd_pcm_format_t ma_snd_pcm_format_t;
15954 typedef snd_pcm_access_t ma_snd_pcm_access_t;
15955 typedef snd_pcm_t ma_snd_pcm_t;
15956 typedef snd_pcm_hw_params_t ma_snd_pcm_hw_params_t;
15957 typedef snd_pcm_sw_params_t ma_snd_pcm_sw_params_t;
15958 typedef snd_pcm_format_mask_t ma_snd_pcm_format_mask_t;
15959 typedef snd_pcm_info_t ma_snd_pcm_info_t;
15960 typedef snd_pcm_channel_area_t ma_snd_pcm_channel_area_t;
15961 typedef snd_pcm_chmap_t ma_snd_pcm_chmap_t;
15962 
15963 /* snd_pcm_stream_t */
15964 #define MA_SND_PCM_STREAM_PLAYBACK SND_PCM_STREAM_PLAYBACK
15965 #define MA_SND_PCM_STREAM_CAPTURE SND_PCM_STREAM_CAPTURE
15966 
15967 /* snd_pcm_format_t */
15968 #define MA_SND_PCM_FORMAT_UNKNOWN SND_PCM_FORMAT_UNKNOWN
15969 #define MA_SND_PCM_FORMAT_U8 SND_PCM_FORMAT_U8
15970 #define MA_SND_PCM_FORMAT_S16_LE SND_PCM_FORMAT_S16_LE
15971 #define MA_SND_PCM_FORMAT_S16_BE SND_PCM_FORMAT_S16_BE
15972 #define MA_SND_PCM_FORMAT_S24_LE SND_PCM_FORMAT_S24_LE
15973 #define MA_SND_PCM_FORMAT_S24_BE SND_PCM_FORMAT_S24_BE
15974 #define MA_SND_PCM_FORMAT_S32_LE SND_PCM_FORMAT_S32_LE
15975 #define MA_SND_PCM_FORMAT_S32_BE SND_PCM_FORMAT_S32_BE
15976 #define MA_SND_PCM_FORMAT_FLOAT_LE SND_PCM_FORMAT_FLOAT_LE
15977 #define MA_SND_PCM_FORMAT_FLOAT_BE SND_PCM_FORMAT_FLOAT_BE
15978 #define MA_SND_PCM_FORMAT_FLOAT64_LE SND_PCM_FORMAT_FLOAT64_LE
15979 #define MA_SND_PCM_FORMAT_FLOAT64_BE SND_PCM_FORMAT_FLOAT64_BE
15980 #define MA_SND_PCM_FORMAT_MU_LAW SND_PCM_FORMAT_MU_LAW
15981 #define MA_SND_PCM_FORMAT_A_LAW SND_PCM_FORMAT_A_LAW
15982 #define MA_SND_PCM_FORMAT_S24_3LE SND_PCM_FORMAT_S24_3LE
15983 #define MA_SND_PCM_FORMAT_S24_3BE SND_PCM_FORMAT_S24_3BE
15984 
15985 /* ma_snd_pcm_access_t */
15986 #define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED SND_PCM_ACCESS_MMAP_INTERLEAVED
15987 #define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED SND_PCM_ACCESS_MMAP_NONINTERLEAVED
15988 #define MA_SND_PCM_ACCESS_MMAP_COMPLEX SND_PCM_ACCESS_MMAP_COMPLEX
15989 #define MA_SND_PCM_ACCESS_RW_INTERLEAVED SND_PCM_ACCESS_RW_INTERLEAVED
15990 #define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED SND_PCM_ACCESS_RW_NONINTERLEAVED
15991 
15992 /* Channel positions. */
15993 #define MA_SND_CHMAP_UNKNOWN SND_CHMAP_UNKNOWN
15994 #define MA_SND_CHMAP_NA SND_CHMAP_NA
15995 #define MA_SND_CHMAP_MONO SND_CHMAP_MONO
15996 #define MA_SND_CHMAP_FL SND_CHMAP_FL
15997 #define MA_SND_CHMAP_FR SND_CHMAP_FR
15998 #define MA_SND_CHMAP_RL SND_CHMAP_RL
15999 #define MA_SND_CHMAP_RR SND_CHMAP_RR
16000 #define MA_SND_CHMAP_FC SND_CHMAP_FC
16001 #define MA_SND_CHMAP_LFE SND_CHMAP_LFE
16002 #define MA_SND_CHMAP_SL SND_CHMAP_SL
16003 #define MA_SND_CHMAP_SR SND_CHMAP_SR
16004 #define MA_SND_CHMAP_RC SND_CHMAP_RC
16005 #define MA_SND_CHMAP_FLC SND_CHMAP_FLC
16006 #define MA_SND_CHMAP_FRC SND_CHMAP_FRC
16007 #define MA_SND_CHMAP_RLC SND_CHMAP_RLC
16008 #define MA_SND_CHMAP_RRC SND_CHMAP_RRC
16009 #define MA_SND_CHMAP_FLW SND_CHMAP_FLW
16010 #define MA_SND_CHMAP_FRW SND_CHMAP_FRW
16011 #define MA_SND_CHMAP_FLH SND_CHMAP_FLH
16012 #define MA_SND_CHMAP_FCH SND_CHMAP_FCH
16013 #define MA_SND_CHMAP_FRH SND_CHMAP_FRH
16014 #define MA_SND_CHMAP_TC SND_CHMAP_TC
16015 #define MA_SND_CHMAP_TFL SND_CHMAP_TFL
16016 #define MA_SND_CHMAP_TFR SND_CHMAP_TFR
16017 #define MA_SND_CHMAP_TFC SND_CHMAP_TFC
16018 #define MA_SND_CHMAP_TRL SND_CHMAP_TRL
16019 #define MA_SND_CHMAP_TRR SND_CHMAP_TRR
16020 #define MA_SND_CHMAP_TRC SND_CHMAP_TRC
16021 #define MA_SND_CHMAP_TFLC SND_CHMAP_TFLC
16022 #define MA_SND_CHMAP_TFRC SND_CHMAP_TFRC
16023 #define MA_SND_CHMAP_TSL SND_CHMAP_TSL
16024 #define MA_SND_CHMAP_TSR SND_CHMAP_TSR
16025 #define MA_SND_CHMAP_LLFE SND_CHMAP_LLFE
16026 #define MA_SND_CHMAP_RLFE SND_CHMAP_RLFE
16027 #define MA_SND_CHMAP_BC SND_CHMAP_BC
16028 #define MA_SND_CHMAP_BLC SND_CHMAP_BLC
16029 #define MA_SND_CHMAP_BRC SND_CHMAP_BRC
16030 
16031 /* Open mode flags. */
16032 #define MA_SND_PCM_NO_AUTO_RESAMPLE SND_PCM_NO_AUTO_RESAMPLE
16033 #define MA_SND_PCM_NO_AUTO_CHANNELS SND_PCM_NO_AUTO_CHANNELS
16034 #define MA_SND_PCM_NO_AUTO_FORMAT SND_PCM_NO_AUTO_FORMAT
16035 #else
16036 #include <errno.h> /* For EPIPE, etc. */
16037 typedef unsigned long ma_snd_pcm_uframes_t;
16038 typedef long ma_snd_pcm_sframes_t;
16039 typedef int ma_snd_pcm_stream_t;
16040 typedef int ma_snd_pcm_format_t;
16041 typedef int ma_snd_pcm_access_t;
16042 typedef struct ma_snd_pcm_t ma_snd_pcm_t;
16043 typedef struct ma_snd_pcm_hw_params_t ma_snd_pcm_hw_params_t;
16044 typedef struct ma_snd_pcm_sw_params_t ma_snd_pcm_sw_params_t;
16045 typedef struct ma_snd_pcm_format_mask_t ma_snd_pcm_format_mask_t;
16046 typedef struct ma_snd_pcm_info_t ma_snd_pcm_info_t;
16047 typedef struct
16048 {
16049  void* addr;
16050  unsigned int first;
16051  unsigned int step;
16052 } ma_snd_pcm_channel_area_t;
16053 typedef struct
16054 {
16055  unsigned int channels;
16056  unsigned int pos[1];
16057 } ma_snd_pcm_chmap_t;
16058 
16059 /* snd_pcm_state_t */
16060 #define MA_SND_PCM_STATE_OPEN 0
16061 #define MA_SND_PCM_STATE_SETUP 1
16062 #define MA_SND_PCM_STATE_PREPARED 2
16063 #define MA_SND_PCM_STATE_RUNNING 3
16064 #define MA_SND_PCM_STATE_XRUN 4
16065 #define MA_SND_PCM_STATE_DRAINING 5
16066 #define MA_SND_PCM_STATE_PAUSED 6
16067 #define MA_SND_PCM_STATE_SUSPENDED 7
16068 #define MA_SND_PCM_STATE_DISCONNECTED 8
16069 
16070 /* snd_pcm_stream_t */
16071 #define MA_SND_PCM_STREAM_PLAYBACK 0
16072 #define MA_SND_PCM_STREAM_CAPTURE 1
16073 
16074 /* snd_pcm_format_t */
16075 #define MA_SND_PCM_FORMAT_UNKNOWN -1
16076 #define MA_SND_PCM_FORMAT_U8 1
16077 #define MA_SND_PCM_FORMAT_S16_LE 2
16078 #define MA_SND_PCM_FORMAT_S16_BE 3
16079 #define MA_SND_PCM_FORMAT_S24_LE 6
16080 #define MA_SND_PCM_FORMAT_S24_BE 7
16081 #define MA_SND_PCM_FORMAT_S32_LE 10
16082 #define MA_SND_PCM_FORMAT_S32_BE 11
16083 #define MA_SND_PCM_FORMAT_FLOAT_LE 14
16084 #define MA_SND_PCM_FORMAT_FLOAT_BE 15
16085 #define MA_SND_PCM_FORMAT_FLOAT64_LE 16
16086 #define MA_SND_PCM_FORMAT_FLOAT64_BE 17
16087 #define MA_SND_PCM_FORMAT_MU_LAW 20
16088 #define MA_SND_PCM_FORMAT_A_LAW 21
16089 #define MA_SND_PCM_FORMAT_S24_3LE 32
16090 #define MA_SND_PCM_FORMAT_S24_3BE 33
16091 
16092 /* snd_pcm_access_t */
16093 #define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED 0
16094 #define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED 1
16095 #define MA_SND_PCM_ACCESS_MMAP_COMPLEX 2
16096 #define MA_SND_PCM_ACCESS_RW_INTERLEAVED 3
16097 #define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED 4
16098 
16099 /* Channel positions. */
16100 #define MA_SND_CHMAP_UNKNOWN 0
16101 #define MA_SND_CHMAP_NA 1
16102 #define MA_SND_CHMAP_MONO 2
16103 #define MA_SND_CHMAP_FL 3
16104 #define MA_SND_CHMAP_FR 4
16105 #define MA_SND_CHMAP_RL 5
16106 #define MA_SND_CHMAP_RR 6
16107 #define MA_SND_CHMAP_FC 7
16108 #define MA_SND_CHMAP_LFE 8
16109 #define MA_SND_CHMAP_SL 9
16110 #define MA_SND_CHMAP_SR 10
16111 #define MA_SND_CHMAP_RC 11
16112 #define MA_SND_CHMAP_FLC 12
16113 #define MA_SND_CHMAP_FRC 13
16114 #define MA_SND_CHMAP_RLC 14
16115 #define MA_SND_CHMAP_RRC 15
16116 #define MA_SND_CHMAP_FLW 16
16117 #define MA_SND_CHMAP_FRW 17
16118 #define MA_SND_CHMAP_FLH 18
16119 #define MA_SND_CHMAP_FCH 19
16120 #define MA_SND_CHMAP_FRH 20
16121 #define MA_SND_CHMAP_TC 21
16122 #define MA_SND_CHMAP_TFL 22
16123 #define MA_SND_CHMAP_TFR 23
16124 #define MA_SND_CHMAP_TFC 24
16125 #define MA_SND_CHMAP_TRL 25
16126 #define MA_SND_CHMAP_TRR 26
16127 #define MA_SND_CHMAP_TRC 27
16128 #define MA_SND_CHMAP_TFLC 28
16129 #define MA_SND_CHMAP_TFRC 29
16130 #define MA_SND_CHMAP_TSL 30
16131 #define MA_SND_CHMAP_TSR 31
16132 #define MA_SND_CHMAP_LLFE 32
16133 #define MA_SND_CHMAP_RLFE 33
16134 #define MA_SND_CHMAP_BC 34
16135 #define MA_SND_CHMAP_BLC 35
16136 #define MA_SND_CHMAP_BRC 36
16137 
16138 /* Open mode flags. */
16139 #define MA_SND_PCM_NO_AUTO_RESAMPLE 0x00010000
16140 #define MA_SND_PCM_NO_AUTO_CHANNELS 0x00020000
16141 #define MA_SND_PCM_NO_AUTO_FORMAT 0x00040000
16142 #endif
16143 
16144 typedef int (* ma_snd_pcm_open_proc) (ma_snd_pcm_t **pcm, const char *name, ma_snd_pcm_stream_t stream, int mode);
16145 typedef int (* ma_snd_pcm_close_proc) (ma_snd_pcm_t *pcm);
16146 typedef size_t (* ma_snd_pcm_hw_params_sizeof_proc) (void);
16147 typedef int (* ma_snd_pcm_hw_params_any_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params);
16148 typedef int (* ma_snd_pcm_hw_params_set_format_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t val);
16149 typedef int (* ma_snd_pcm_hw_params_set_format_first_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t *format);
16150 typedef void (* ma_snd_pcm_hw_params_get_format_mask_proc) (ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_mask_t *mask);
16151 typedef int (* ma_snd_pcm_hw_params_set_channels_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val);
16152 typedef int (* ma_snd_pcm_hw_params_set_rate_resample_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val);
16153 typedef int (* ma_snd_pcm_hw_params_set_rate_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
16154 typedef int (* ma_snd_pcm_hw_params_set_buffer_size_near_proc)(ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_uframes_t *val);
16155 typedef int (* ma_snd_pcm_hw_params_set_periods_near_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
16156 typedef int (* ma_snd_pcm_hw_params_set_access_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t _access);
16157 typedef int (* ma_snd_pcm_hw_params_get_format_proc) (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t *format);
16158 typedef int (* ma_snd_pcm_hw_params_get_channels_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val);
16159 typedef int (* ma_snd_pcm_hw_params_get_channels_min_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val);
16160 typedef int (* ma_snd_pcm_hw_params_get_channels_max_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val);
16161 typedef int (* ma_snd_pcm_hw_params_get_rate_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir);
16162 typedef int (* ma_snd_pcm_hw_params_get_rate_min_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir);
16163 typedef int (* ma_snd_pcm_hw_params_get_rate_max_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir);
16164 typedef int (* ma_snd_pcm_hw_params_get_buffer_size_proc) (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_uframes_t *val);
16165 typedef int (* ma_snd_pcm_hw_params_get_periods_proc) (const ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
16166 typedef int (* ma_snd_pcm_hw_params_get_access_proc) (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t *_access);
16167 typedef int (* ma_snd_pcm_hw_params_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params);
16168 typedef size_t (* ma_snd_pcm_sw_params_sizeof_proc) (void);
16169 typedef int (* ma_snd_pcm_sw_params_current_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params);
16170 typedef int (* ma_snd_pcm_sw_params_get_boundary_proc) (ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t* val);
16171 typedef int (* ma_snd_pcm_sw_params_set_avail_min_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t val);
16172 typedef int (* ma_snd_pcm_sw_params_set_start_threshold_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t val);
16173 typedef int (* ma_snd_pcm_sw_params_set_stop_threshold_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t val);
16174 typedef int (* ma_snd_pcm_sw_params_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params);
16175 typedef size_t (* ma_snd_pcm_format_mask_sizeof_proc) (void);
16176 typedef int (* ma_snd_pcm_format_mask_test_proc) (const ma_snd_pcm_format_mask_t *mask, ma_snd_pcm_format_t val);
16177 typedef ma_snd_pcm_chmap_t * (* ma_snd_pcm_get_chmap_proc) (ma_snd_pcm_t *pcm);
16178 typedef int (* ma_snd_pcm_state_proc) (ma_snd_pcm_t *pcm);
16179 typedef int (* ma_snd_pcm_prepare_proc) (ma_snd_pcm_t *pcm);
16180 typedef int (* ma_snd_pcm_start_proc) (ma_snd_pcm_t *pcm);
16181 typedef int (* ma_snd_pcm_drop_proc) (ma_snd_pcm_t *pcm);
16182 typedef int (* ma_snd_pcm_drain_proc) (ma_snd_pcm_t *pcm);
16183 typedef int (* ma_snd_device_name_hint_proc) (int card, const char *iface, void ***hints);
16184 typedef char * (* ma_snd_device_name_get_hint_proc) (const void *hint, const char *id);
16185 typedef int (* ma_snd_card_get_index_proc) (const char *name);
16186 typedef int (* ma_snd_device_name_free_hint_proc) (void **hints);
16187 typedef int (* ma_snd_pcm_mmap_begin_proc) (ma_snd_pcm_t *pcm, const ma_snd_pcm_channel_area_t **areas, ma_snd_pcm_uframes_t *offset, ma_snd_pcm_uframes_t *frames);
16188 typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_mmap_commit_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_uframes_t offset, ma_snd_pcm_uframes_t frames);
16189 typedef int (* ma_snd_pcm_recover_proc) (ma_snd_pcm_t *pcm, int err, int silent);
16190 typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_readi_proc) (ma_snd_pcm_t *pcm, void *buffer, ma_snd_pcm_uframes_t size);
16191 typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_writei_proc) (ma_snd_pcm_t *pcm, const void *buffer, ma_snd_pcm_uframes_t size);
16192 typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_avail_proc) (ma_snd_pcm_t *pcm);
16193 typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_avail_update_proc) (ma_snd_pcm_t *pcm);
16194 typedef int (* ma_snd_pcm_wait_proc) (ma_snd_pcm_t *pcm, int timeout);
16195 typedef int (* ma_snd_pcm_info_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_info_t* info);
16196 typedef size_t (* ma_snd_pcm_info_sizeof_proc) ();
16197 typedef const char* (* ma_snd_pcm_info_get_name_proc) (const ma_snd_pcm_info_t* info);
16198 typedef int (* ma_snd_config_update_free_global_proc) ();
16199 
16200 /* This array specifies each of the common devices that can be used for both playback and capture. */
16201 static const char* g_maCommonDeviceNamesALSA[] = {
16202  "default",
16203  "null",
16204  "pulse",
16205  "jack"
16206 };
16207 
16208 /* This array allows us to blacklist specific playback devices. */
16209 static const char* g_maBlacklistedPlaybackDeviceNamesALSA[] = {
16210  ""
16211 };
16212 
16213 /* This array allows us to blacklist specific capture devices. */
16214 static const char* g_maBlacklistedCaptureDeviceNamesALSA[] = {
16215  ""
16216 };
16217 
16218 
16219 /*
16220 This array allows miniaudio to control device-specific default buffer sizes. This uses a scaling factor. Order is important. If
16221 any part of the string is present in the device's name, the associated scale will be used.
16222 */
16223 static struct
16224 {
16225  const char* name;
16226  float scale;
16227 } g_maDefaultBufferSizeScalesALSA[] = {
16228  {"bcm2835 IEC958/HDMI", 2.0f},
16229  {"bcm2835 ALSA", 2.0f}
16230 };
16231 
16232 static float ma_find_default_buffer_size_scale__alsa(const char* deviceName)
16233 {
16234  size_t i;
16235 
16236  if (deviceName == NULL) {
16237  return 1;
16238  }
16239 
16240  for (i = 0; i < ma_countof(g_maDefaultBufferSizeScalesALSA); ++i) {
16241  if (strstr(g_maDefaultBufferSizeScalesALSA[i].name, deviceName) != NULL) {
16242  return g_maDefaultBufferSizeScalesALSA[i].scale;
16243  }
16244  }
16245 
16246  return 1;
16247 }
16248 
16249 static ma_snd_pcm_format_t ma_convert_ma_format_to_alsa_format(ma_format format)
16250 {
16251  ma_snd_pcm_format_t ALSAFormats[] = {
16252  MA_SND_PCM_FORMAT_UNKNOWN, /* ma_format_unknown */
16253  MA_SND_PCM_FORMAT_U8, /* ma_format_u8 */
16254  MA_SND_PCM_FORMAT_S16_LE, /* ma_format_s16 */
16255  MA_SND_PCM_FORMAT_S24_3LE, /* ma_format_s24 */
16256  MA_SND_PCM_FORMAT_S32_LE, /* ma_format_s32 */
16257  MA_SND_PCM_FORMAT_FLOAT_LE /* ma_format_f32 */
16258  };
16259 
16260  if (ma_is_big_endian()) {
16261  ALSAFormats[0] = MA_SND_PCM_FORMAT_UNKNOWN;
16262  ALSAFormats[1] = MA_SND_PCM_FORMAT_U8;
16263  ALSAFormats[2] = MA_SND_PCM_FORMAT_S16_BE;
16264  ALSAFormats[3] = MA_SND_PCM_FORMAT_S24_3BE;
16265  ALSAFormats[4] = MA_SND_PCM_FORMAT_S32_BE;
16266  ALSAFormats[5] = MA_SND_PCM_FORMAT_FLOAT_BE;
16267  }
16268 
16269  return ALSAFormats[format];
16270 }
16271 
16272 static ma_format ma_format_from_alsa(ma_snd_pcm_format_t formatALSA)
16273 {
16274  if (ma_is_little_endian()) {
16275  switch (formatALSA) {
16276  case MA_SND_PCM_FORMAT_S16_LE: return ma_format_s16;
16277  case MA_SND_PCM_FORMAT_S24_3LE: return ma_format_s24;
16278  case MA_SND_PCM_FORMAT_S32_LE: return ma_format_s32;
16279  case MA_SND_PCM_FORMAT_FLOAT_LE: return ma_format_f32;
16280  default: break;
16281  }
16282  } else {
16283  switch (formatALSA) {
16284  case MA_SND_PCM_FORMAT_S16_BE: return ma_format_s16;
16285  case MA_SND_PCM_FORMAT_S24_3BE: return ma_format_s24;
16286  case MA_SND_PCM_FORMAT_S32_BE: return ma_format_s32;
16287  case MA_SND_PCM_FORMAT_FLOAT_BE: return ma_format_f32;
16288  default: break;
16289  }
16290  }
16291 
16292  /* Endian agnostic. */
16293  switch (formatALSA) {
16294  case MA_SND_PCM_FORMAT_U8: return ma_format_u8;
16295  default: return ma_format_unknown;
16296  }
16297 }
16298 
16299 static ma_channel ma_convert_alsa_channel_position_to_ma_channel(unsigned int alsaChannelPos)
16300 {
16301  switch (alsaChannelPos)
16302  {
16303  case MA_SND_CHMAP_MONO: return MA_CHANNEL_MONO;
16304  case MA_SND_CHMAP_FL: return MA_CHANNEL_FRONT_LEFT;
16305  case MA_SND_CHMAP_FR: return MA_CHANNEL_FRONT_RIGHT;
16306  case MA_SND_CHMAP_RL: return MA_CHANNEL_BACK_LEFT;
16307  case MA_SND_CHMAP_RR: return MA_CHANNEL_BACK_RIGHT;
16308  case MA_SND_CHMAP_FC: return MA_CHANNEL_FRONT_CENTER;
16309  case MA_SND_CHMAP_LFE: return MA_CHANNEL_LFE;
16310  case MA_SND_CHMAP_SL: return MA_CHANNEL_SIDE_LEFT;
16311  case MA_SND_CHMAP_SR: return MA_CHANNEL_SIDE_RIGHT;
16312  case MA_SND_CHMAP_RC: return MA_CHANNEL_BACK_CENTER;
16313  case MA_SND_CHMAP_FLC: return MA_CHANNEL_FRONT_LEFT_CENTER;
16314  case MA_SND_CHMAP_FRC: return MA_CHANNEL_FRONT_RIGHT_CENTER;
16315  case MA_SND_CHMAP_RLC: return 0;
16316  case MA_SND_CHMAP_RRC: return 0;
16317  case MA_SND_CHMAP_FLW: return 0;
16318  case MA_SND_CHMAP_FRW: return 0;
16319  case MA_SND_CHMAP_FLH: return 0;
16320  case MA_SND_CHMAP_FCH: return 0;
16321  case MA_SND_CHMAP_FRH: return 0;
16322  case MA_SND_CHMAP_TC: return MA_CHANNEL_TOP_CENTER;
16323  case MA_SND_CHMAP_TFL: return MA_CHANNEL_TOP_FRONT_LEFT;
16324  case MA_SND_CHMAP_TFR: return MA_CHANNEL_TOP_FRONT_RIGHT;
16325  case MA_SND_CHMAP_TFC: return MA_CHANNEL_TOP_FRONT_CENTER;
16326  case MA_SND_CHMAP_TRL: return MA_CHANNEL_TOP_BACK_LEFT;
16327  case MA_SND_CHMAP_TRR: return MA_CHANNEL_TOP_BACK_RIGHT;
16328  case MA_SND_CHMAP_TRC: return MA_CHANNEL_TOP_BACK_CENTER;
16329  default: break;
16330  }
16331 
16332  return 0;
16333 }
16334 
16335 static ma_bool32 ma_is_common_device_name__alsa(const char* name)
16336 {
16337  size_t iName;
16338  for (iName = 0; iName < ma_countof(g_maCommonDeviceNamesALSA); ++iName) {
16339  if (ma_strcmp(name, g_maCommonDeviceNamesALSA[iName]) == 0) {
16340  return MA_TRUE;
16341  }
16342  }
16343 
16344  return MA_FALSE;
16345 }
16346 
16347 
16348 static ma_bool32 ma_is_playback_device_blacklisted__alsa(const char* name)
16349 {
16350  size_t iName;
16351  for (iName = 0; iName < ma_countof(g_maBlacklistedPlaybackDeviceNamesALSA); ++iName) {
16352  if (ma_strcmp(name, g_maBlacklistedPlaybackDeviceNamesALSA[iName]) == 0) {
16353  return MA_TRUE;
16354  }
16355  }
16356 
16357  return MA_FALSE;
16358 }
16359 
16360 static ma_bool32 ma_is_capture_device_blacklisted__alsa(const char* name)
16361 {
16362  size_t iName;
16363  for (iName = 0; iName < ma_countof(g_maBlacklistedCaptureDeviceNamesALSA); ++iName) {
16364  if (ma_strcmp(name, g_maBlacklistedCaptureDeviceNamesALSA[iName]) == 0) {
16365  return MA_TRUE;
16366  }
16367  }
16368 
16369  return MA_FALSE;
16370 }
16371 
16372 static ma_bool32 ma_is_device_blacklisted__alsa(ma_device_type deviceType, const char* name)
16373 {
16374  if (deviceType == ma_device_type_playback) {
16375  return ma_is_playback_device_blacklisted__alsa(name);
16376  } else {
16377  return ma_is_capture_device_blacklisted__alsa(name);
16378  }
16379 }
16380 
16381 
16382 static const char* ma_find_char(const char* str, char c, int* index)
16383 {
16384  int i = 0;
16385  for (;;) {
16386  if (str[i] == '\0') {
16387  if (index) *index = -1;
16388  return NULL;
16389  }
16390 
16391  if (str[i] == c) {
16392  if (index) *index = i;
16393  return str + i;
16394  }
16395 
16396  i += 1;
16397  }
16398 
16399  /* Should never get here, but treat it as though the character was not found to make me feel better inside. */
16400  if (index) *index = -1;
16401  return NULL;
16402 }
16403 
16404 static ma_bool32 ma_is_device_name_in_hw_format__alsa(const char* hwid)
16405 {
16406  /* This function is just checking whether or not hwid is in "hw:%d,%d" format. */
16407 
16408  int commaPos;
16409  const char* dev;
16410  int i;
16411 
16412  if (hwid == NULL) {
16413  return MA_FALSE;
16414  }
16415 
16416  if (hwid[0] != 'h' || hwid[1] != 'w' || hwid[2] != ':') {
16417  return MA_FALSE;
16418  }
16419 
16420  hwid += 3;
16421 
16422  dev = ma_find_char(hwid, ',', &commaPos);
16423  if (dev == NULL) {
16424  return MA_FALSE;
16425  } else {
16426  dev += 1; /* Skip past the ",". */
16427  }
16428 
16429  /* Check if the part between the ":" and the "," contains only numbers. If not, return false. */
16430  for (i = 0; i < commaPos; ++i) {
16431  if (hwid[i] < '0' || hwid[i] > '9') {
16432  return MA_FALSE;
16433  }
16434  }
16435 
16436  /* Check if everything after the "," is numeric. If not, return false. */
16437  i = 0;
16438  while (dev[i] != '\0') {
16439  if (dev[i] < '0' || dev[i] > '9') {
16440  return MA_FALSE;
16441  }
16442  i += 1;
16443  }
16444 
16445  return MA_TRUE;
16446 }
16447 
16448 static int ma_convert_device_name_to_hw_format__alsa(ma_context* pContext, char* dst, size_t dstSize, const char* src) /* Returns 0 on success, non-0 on error. */
16449 {
16450  /* src should look something like this: "hw:CARD=I82801AAICH,DEV=0" */
16451 
16452  int colonPos;
16453  int commaPos;
16454  char card[256];
16455  const char* dev;
16456  int cardIndex;
16457 
16458  if (dst == NULL) {
16459  return -1;
16460  }
16461  if (dstSize < 7) {
16462  return -1; /* Absolute minimum size of the output buffer is 7 bytes. */
16463  }
16464 
16465  *dst = '\0'; /* Safety. */
16466  if (src == NULL) {
16467  return -1;
16468  }
16469 
16470  /* If the input name is already in "hw:%d,%d" format, just return that verbatim. */
16471  if (ma_is_device_name_in_hw_format__alsa(src)) {
16472  return ma_strcpy_s(dst, dstSize, src);
16473  }
16474 
16475  src = ma_find_char(src, ':', &colonPos);
16476  if (src == NULL) {
16477  return -1; /* Couldn't find a colon */
16478  }
16479 
16480  dev = ma_find_char(src, ',', &commaPos);
16481  if (dev == NULL) {
16482  dev = "0";
16483  ma_strncpy_s(card, sizeof(card), src+6, (size_t)-1); /* +6 = ":CARD=" */
16484  } else {
16485  dev = dev + 5; /* +5 = ",DEV=" */
16486  ma_strncpy_s(card, sizeof(card), src+6, commaPos-6); /* +6 = ":CARD=" */
16487  }
16488 
16489  cardIndex = ((ma_snd_card_get_index_proc)pContext->alsa.snd_card_get_index)(card);
16490  if (cardIndex < 0) {
16491  return -2; /* Failed to retrieve the card index. */
16492  }
16493 
16494  /*printf("TESTING: CARD=%s,DEV=%s\n", card, dev); */
16495 
16496 
16497  /* Construction. */
16498  dst[0] = 'h'; dst[1] = 'w'; dst[2] = ':';
16499  if (ma_itoa_s(cardIndex, dst+3, dstSize-3, 10) != 0) {
16500  return -3;
16501  }
16502  if (ma_strcat_s(dst, dstSize, ",") != 0) {
16503  return -3;
16504  }
16505  if (ma_strcat_s(dst, dstSize, dev) != 0) {
16506  return -3;
16507  }
16508 
16509  return 0;
16510 }
16511 
16512 static ma_bool32 ma_does_id_exist_in_list__alsa(ma_device_id* pUniqueIDs, ma_uint32 count, const char* pHWID)
16513 {
16514  ma_uint32 i;
16515 
16516  MA_ASSERT(pHWID != NULL);
16517 
16518  for (i = 0; i < count; ++i) {
16519  if (ma_strcmp(pUniqueIDs[i].alsa, pHWID) == 0) {
16520  return MA_TRUE;
16521  }
16522  }
16523 
16524  return MA_FALSE;
16525 }
16526 
16527 
16528 static ma_result ma_context_open_pcm__alsa(ma_context* pContext, ma_share_mode shareMode, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_snd_pcm_t** ppPCM)
16529 {
16530  ma_snd_pcm_t* pPCM;
16531  ma_snd_pcm_stream_t stream;
16532  int openMode;
16533 
16534  MA_ASSERT(pContext != NULL);
16535  MA_ASSERT(ppPCM != NULL);
16536 
16537  *ppPCM = NULL;
16538  pPCM = NULL;
16539 
16540  stream = (deviceType == ma_device_type_playback) ? MA_SND_PCM_STREAM_PLAYBACK : MA_SND_PCM_STREAM_CAPTURE;
16541  openMode = MA_SND_PCM_NO_AUTO_RESAMPLE | MA_SND_PCM_NO_AUTO_CHANNELS | MA_SND_PCM_NO_AUTO_FORMAT;
16542 
16543  if (pDeviceID == NULL) {
16544  ma_bool32 isDeviceOpen;
16545  size_t i;
16546 
16547  /*
16548  We're opening the default device. I don't know if trying anything other than "default" is necessary, but it makes
16549  me feel better to try as hard as we can get to get _something_ working.
16550  */
16551  const char* defaultDeviceNames[] = {
16552  "default",
16553  NULL,
16554  NULL,
16555  NULL,
16556  NULL,
16557  NULL,
16558  NULL
16559  };
16560 
16561  if (shareMode == ma_share_mode_exclusive) {
16562  defaultDeviceNames[1] = "hw";
16563  defaultDeviceNames[2] = "hw:0";
16564  defaultDeviceNames[3] = "hw:0,0";
16565  } else {
16566  if (deviceType == ma_device_type_playback) {
16567  defaultDeviceNames[1] = "dmix";
16568  defaultDeviceNames[2] = "dmix:0";
16569  defaultDeviceNames[3] = "dmix:0,0";
16570  } else {
16571  defaultDeviceNames[1] = "dsnoop";
16572  defaultDeviceNames[2] = "dsnoop:0";
16573  defaultDeviceNames[3] = "dsnoop:0,0";
16574  }
16575  defaultDeviceNames[4] = "hw";
16576  defaultDeviceNames[5] = "hw:0";
16577  defaultDeviceNames[6] = "hw:0,0";
16578  }
16579 
16580  isDeviceOpen = MA_FALSE;
16581  for (i = 0; i < ma_countof(defaultDeviceNames); ++i) {
16582  if (defaultDeviceNames[i] != NULL && defaultDeviceNames[i][0] != '\0') {
16583  if (((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, defaultDeviceNames[i], stream, openMode) == 0) {
16584  isDeviceOpen = MA_TRUE;
16585  break;
16586  }
16587  }
16588  }
16589 
16590  if (!isDeviceOpen) {
16591  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
16592  }
16593  } else {
16594  /*
16595  We're trying to open a specific device. There's a few things to consider here:
16596 
16597  miniaudio recongnizes a special format of device id that excludes the "hw", "dmix", etc. prefix. It looks like this: ":0,0", ":0,1", etc. When
16598  an ID of this format is specified, it indicates to miniaudio that it can try different combinations of plugins ("hw", "dmix", etc.) until it
16599  finds an appropriate one that works. This comes in very handy when trying to open a device in shared mode ("dmix"), vs exclusive mode ("hw").
16600  */
16601 
16602  /* May end up needing to make small adjustments to the ID, so make a copy. */
16603  ma_device_id deviceID = *pDeviceID;
16604  int resultALSA = -ENODEV;
16605 
16606  if (deviceID.alsa[0] != ':') {
16607  /* The ID is not in ":0,0" format. Use the ID exactly as-is. */
16608  resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, deviceID.alsa, stream, openMode);
16609  } else {
16610  char hwid[256];
16611 
16612  /* The ID is in ":0,0" format. Try different plugins depending on the shared mode. */
16613  if (deviceID.alsa[1] == '\0') {
16614  deviceID.alsa[0] = '\0'; /* An ID of ":" should be converted to "". */
16615  }
16616 
16617  if (shareMode == ma_share_mode_shared) {
16618  if (deviceType == ma_device_type_playback) {
16619  ma_strcpy_s(hwid, sizeof(hwid), "dmix");
16620  } else {
16621  ma_strcpy_s(hwid, sizeof(hwid), "dsnoop");
16622  }
16623 
16624  if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) {
16625  resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode);
16626  }
16627  }
16628 
16629  /* If at this point we still don't have an open device it means we're either preferencing exclusive mode or opening with "dmix"/"dsnoop" failed. */
16630  if (resultALSA != 0) {
16631  ma_strcpy_s(hwid, sizeof(hwid), "hw");
16632  if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) {
16633  resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode);
16634  }
16635  }
16636  }
16637 
16638  if (resultALSA < 0) {
16639  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed.", ma_result_from_errno(-resultALSA));
16640  }
16641  }
16642 
16643  *ppPCM = pPCM;
16644  return MA_SUCCESS;
16645 }
16646 
16647 
16648 static ma_bool32 ma_context_is_device_id_equal__alsa(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
16649 {
16650  MA_ASSERT(pContext != NULL);
16651  MA_ASSERT(pID0 != NULL);
16652  MA_ASSERT(pID1 != NULL);
16653  (void)pContext;
16654 
16655  return ma_strcmp(pID0->alsa, pID1->alsa) == 0;
16656 }
16657 
16658 static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
16659 {
16660  int resultALSA;
16661  ma_bool32 cbResult = MA_TRUE;
16662  char** ppDeviceHints;
16663  ma_device_id* pUniqueIDs = NULL;
16664  ma_uint32 uniqueIDCount = 0;
16665  char** ppNextDeviceHint;
16666 
16667  MA_ASSERT(pContext != NULL);
16668  MA_ASSERT(callback != NULL);
16669 
16670  ma_mutex_lock(&pContext->alsa.internalDeviceEnumLock);
16671 
16672  resultALSA = ((ma_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints);
16673  if (resultALSA < 0) {
16674  ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock);
16675  return ma_result_from_errno(-resultALSA);
16676  }
16677 
16678  ppNextDeviceHint = ppDeviceHints;
16679  while (*ppNextDeviceHint != NULL) {
16680  char* NAME = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME");
16681  char* DESC = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC");
16682  char* IOID = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID");
16684  ma_bool32 stopEnumeration = MA_FALSE;
16685  char hwid[sizeof(pUniqueIDs->alsa)];
16686  ma_device_info deviceInfo;
16687 
16688  if ((IOID == NULL || ma_strcmp(IOID, "Output") == 0)) {
16689  deviceType = ma_device_type_playback;
16690  }
16691  if ((IOID != NULL && ma_strcmp(IOID, "Input" ) == 0)) {
16692  deviceType = ma_device_type_capture;
16693  }
16694 
16695  if (NAME != NULL) {
16696  if (pContext->alsa.useVerboseDeviceEnumeration) {
16697  /* Verbose mode. Use the name exactly as-is. */
16698  ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
16699  } else {
16700  /* Simplified mode. Use ":%d,%d" format. */
16701  if (ma_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) {
16702  /*
16703  At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the
16704  plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device
16705  initialization time and is used as an indicator to try and use the most appropriate plugin depending on the
16706  device type and sharing mode.
16707  */
16708  char* dst = hwid;
16709  char* src = hwid+2;
16710  while ((*dst++ = *src++));
16711  } else {
16712  /* Conversion to "hw:%d,%d" failed. Just use the name as-is. */
16713  ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
16714  }
16715 
16716  if (ma_does_id_exist_in_list__alsa(pUniqueIDs, uniqueIDCount, hwid)) {
16717  goto next_device; /* The device has already been enumerated. Move on to the next one. */
16718  } else {
16719  /* The device has not yet been enumerated. Make sure it's added to our list so that it's not enumerated again. */
16720  size_t oldCapacity = sizeof(*pUniqueIDs) * uniqueIDCount;
16721  size_t newCapacity = sizeof(*pUniqueIDs) * (uniqueIDCount + 1);
16722  ma_device_id* pNewUniqueIDs = (ma_device_id*)ma__realloc_from_callbacks(pUniqueIDs, newCapacity, oldCapacity, &pContext->allocationCallbacks);
16723  if (pNewUniqueIDs == NULL) {
16724  goto next_device; /* Failed to allocate memory. */
16725  }
16726 
16727  pUniqueIDs = pNewUniqueIDs;
16728  MA_COPY_MEMORY(pUniqueIDs[uniqueIDCount].alsa, hwid, sizeof(hwid));
16729  uniqueIDCount += 1;
16730  }
16731  }
16732  } else {
16733  MA_ZERO_MEMORY(hwid, sizeof(hwid));
16734  }
16735 
16736  MA_ZERO_OBJECT(&deviceInfo);
16737  ma_strncpy_s(deviceInfo.id.alsa, sizeof(deviceInfo.id.alsa), hwid, (size_t)-1);
16738 
16739  /*
16740  DESC is the friendly name. We treat this slightly differently depending on whether or not we are using verbose
16741  device enumeration. In verbose mode we want to take the entire description so that the end-user can distinguish
16742  between the subdevices of each card/dev pair. In simplified mode, however, we only want the first part of the
16743  description.
16744 
16745  The value in DESC seems to be split into two lines, with the first line being the name of the device and the
16746  second line being a description of the device. I don't like having the description be across two lines because
16747  it makes formatting ugly and annoying. I'm therefore deciding to put it all on a single line with the second line
16748  being put into parentheses. In simplified mode I'm just stripping the second line entirely.
16749  */
16750  if (DESC != NULL) {
16751  int lfPos;
16752  const char* line2 = ma_find_char(DESC, '\n', &lfPos);
16753  if (line2 != NULL) {
16754  line2 += 1; /* Skip past the new-line character. */
16755 
16756  if (pContext->alsa.useVerboseDeviceEnumeration) {
16757  /* Verbose mode. Put the second line in brackets. */
16758  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos);
16759  ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), " (");
16760  ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), line2);
16761  ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), ")");
16762  } else {
16763  /* Simplified mode. Strip the second line entirely. */
16764  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos);
16765  }
16766  } else {
16767  /* There's no second line. Just copy the whole description. */
16768  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, (size_t)-1);
16769  }
16770  }
16771 
16772  if (!ma_is_device_blacklisted__alsa(deviceType, NAME)) {
16773  cbResult = callback(pContext, deviceType, &deviceInfo, pUserData);
16774  }
16775 
16776  /*
16777  Some devices are both playback and capture, but they are only enumerated by ALSA once. We need to fire the callback
16778  again for the other device type in this case. We do this for known devices.
16779  */
16780  if (cbResult) {
16781  if (ma_is_common_device_name__alsa(NAME)) {
16782  if (deviceType == ma_device_type_playback) {
16783  if (!ma_is_capture_device_blacklisted__alsa(NAME)) {
16784  cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
16785  }
16786  } else {
16787  if (!ma_is_playback_device_blacklisted__alsa(NAME)) {
16788  cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
16789  }
16790  }
16791  }
16792  }
16793 
16794  if (cbResult == MA_FALSE) {
16795  stopEnumeration = MA_TRUE;
16796  }
16797 
16798  next_device:
16799  free(NAME);
16800  free(DESC);
16801  free(IOID);
16802  ppNextDeviceHint += 1;
16803 
16804  /* We need to stop enumeration if the callback returned false. */
16805  if (stopEnumeration) {
16806  break;
16807  }
16808  }
16809 
16810  ma__free_from_callbacks(pUniqueIDs, &pContext->allocationCallbacks);
16811  ((ma_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints);
16812 
16813  ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock);
16814 
16815  return MA_SUCCESS;
16816 }
16817 
16818 
16819 typedef struct
16820 {
16821  ma_device_type deviceType;
16822  const ma_device_id* pDeviceID;
16823  ma_share_mode shareMode;
16824  ma_device_info* pDeviceInfo;
16825  ma_bool32 foundDevice;
16826 } ma_context_get_device_info_enum_callback_data__alsa;
16827 
16828 static ma_bool32 ma_context_get_device_info_enum_callback__alsa(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pDeviceInfo, void* pUserData)
16829 {
16830  ma_context_get_device_info_enum_callback_data__alsa* pData = (ma_context_get_device_info_enum_callback_data__alsa*)pUserData;
16831  MA_ASSERT(pData != NULL);
16832 
16833  if (pData->pDeviceID == NULL && ma_strcmp(pDeviceInfo->id.alsa, "default") == 0) {
16834  ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1);
16835  pData->foundDevice = MA_TRUE;
16836  } else {
16837  if (pData->deviceType == deviceType && ma_context_is_device_id_equal__alsa(pContext, pData->pDeviceID, &pDeviceInfo->id)) {
16838  ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1);
16839  pData->foundDevice = MA_TRUE;
16840  }
16841  }
16842 
16843  /* Keep enumerating until we have found the device. */
16844  return !pData->foundDevice;
16845 }
16846 
16847 static ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
16848 {
16849  ma_context_get_device_info_enum_callback_data__alsa data;
16850  ma_result result;
16851  int resultALSA;
16852  ma_snd_pcm_t* pPCM;
16853  ma_snd_pcm_hw_params_t* pHWParams;
16854  ma_snd_pcm_format_mask_t* pFormatMask;
16855  int sampleRateDir = 0;
16856 
16857  MA_ASSERT(pContext != NULL);
16858 
16859  /* We just enumerate to find basic information about the device. */
16860  data.deviceType = deviceType;
16861  data.pDeviceID = pDeviceID;
16862  data.shareMode = shareMode;
16863  data.pDeviceInfo = pDeviceInfo;
16864  data.foundDevice = MA_FALSE;
16865  result = ma_context_enumerate_devices__alsa(pContext, ma_context_get_device_info_enum_callback__alsa, &data);
16866  if (result != MA_SUCCESS) {
16867  return result;
16868  }
16869 
16870  if (!data.foundDevice) {
16871  return MA_NO_DEVICE;
16872  }
16873 
16874  /* For detailed info we need to open the device. */
16875  result = ma_context_open_pcm__alsa(pContext, shareMode, deviceType, pDeviceID, &pPCM);
16876  if (result != MA_SUCCESS) {
16877  return result;
16878  }
16879 
16880  /* We need to initialize a HW parameters object in order to know what formats are supported. */
16881  pHWParams = (ma_snd_pcm_hw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)(), &pContext->allocationCallbacks);
16882  if (pHWParams == NULL) {
16883  return MA_OUT_OF_MEMORY;
16884  }
16885 
16886  resultALSA = ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
16887  if (resultALSA < 0) {
16888  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
16889  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", ma_result_from_errno(-resultALSA));
16890  }
16891 
16892  ((ma_snd_pcm_hw_params_get_channels_min_proc)pContext->alsa.snd_pcm_hw_params_get_channels_min)(pHWParams, &pDeviceInfo->minChannels);
16893  ((ma_snd_pcm_hw_params_get_channels_max_proc)pContext->alsa.snd_pcm_hw_params_get_channels_max)(pHWParams, &pDeviceInfo->maxChannels);
16894  ((ma_snd_pcm_hw_params_get_rate_min_proc)pContext->alsa.snd_pcm_hw_params_get_rate_min)(pHWParams, &pDeviceInfo->minSampleRate, &sampleRateDir);
16895  ((ma_snd_pcm_hw_params_get_rate_max_proc)pContext->alsa.snd_pcm_hw_params_get_rate_max)(pHWParams, &pDeviceInfo->maxSampleRate, &sampleRateDir);
16896 
16897  /* Formats. */
16898  pFormatMask = (ma_snd_pcm_format_mask_t*)ma__calloc_from_callbacks(((ma_snd_pcm_format_mask_sizeof_proc)pContext->alsa.snd_pcm_format_mask_sizeof)(), &pContext->allocationCallbacks);
16899  if (pFormatMask == NULL) {
16900  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
16901  return MA_OUT_OF_MEMORY;
16902  }
16903 
16904  ((ma_snd_pcm_hw_params_get_format_mask_proc)pContext->alsa.snd_pcm_hw_params_get_format_mask)(pHWParams, pFormatMask);
16905 
16906  pDeviceInfo->formatCount = 0;
16907  if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_U8)) {
16908  pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_u8;
16909  }
16910  if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_S16_LE)) {
16911  pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s16;
16912  }
16913  if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_S24_3LE)) {
16914  pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s24;
16915  }
16916  if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_S32_LE)) {
16917  pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s32;
16918  }
16919  if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, MA_SND_PCM_FORMAT_FLOAT_LE)) {
16920  pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_f32;
16921  }
16922 
16923  ma__free_from_callbacks(pFormatMask, &pContext->allocationCallbacks);
16924  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
16925 
16926  ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM);
16927  return MA_SUCCESS;
16928 }
16929 
16930 
16931 #if 0
16932 /*
16933 Waits for a number of frames to become available for either capture or playback. The return
16934 value is the number of frames available.
16935 
16936 This will return early if the main loop is broken with ma_device__break_main_loop().
16937 */
16938 static ma_uint32 ma_device__wait_for_frames__alsa(ma_device* pDevice, ma_bool32* pRequiresRestart)
16939 {
16940  MA_ASSERT(pDevice != NULL);
16941 
16942  if (pRequiresRestart) *pRequiresRestart = MA_FALSE;
16943 
16944  /* I want it so that this function returns the period size in frames. We just wait until that number of frames are available and then return. */
16945  ma_uint32 periodSizeInFrames = pDevice->bufferSizeInFrames / pDevice->periods;
16946  while (!pDevice->alsa.breakFromMainLoop) {
16947  ma_snd_pcm_sframes_t framesAvailable = ((ma_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((ma_snd_pcm_t*)pDevice->alsa.pPCM);
16948  if (framesAvailable < 0) {
16949  if (framesAvailable == -EPIPE) {
16950  if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, framesAvailable, MA_TRUE) < 0) {
16951  return 0;
16952  }
16953 
16954  /* A device recovery means a restart for mmap mode. */
16955  if (pRequiresRestart) {
16956  *pRequiresRestart = MA_TRUE;
16957  }
16958 
16959  /* Try again, but if it fails this time just return an error. */
16960  framesAvailable = ((ma_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((ma_snd_pcm_t*)pDevice->alsa.pPCM);
16961  if (framesAvailable < 0) {
16962  return 0;
16963  }
16964  }
16965  }
16966 
16967  if (framesAvailable >= periodSizeInFrames) {
16968  return periodSizeInFrames;
16969  }
16970 
16971  if (framesAvailable < periodSizeInFrames) {
16972  /* Less than a whole period is available so keep waiting. */
16973  int waitResult = ((ma_snd_pcm_wait_proc)pDevice->pContext->alsa.snd_pcm_wait)((ma_snd_pcm_t*)pDevice->alsa.pPCM, -1);
16974  if (waitResult < 0) {
16975  if (waitResult == -EPIPE) {
16976  if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, waitResult, MA_TRUE) < 0) {
16977  return 0;
16978  }
16979 
16980  /* A device recovery means a restart for mmap mode. */
16981  if (pRequiresRestart) {
16982  *pRequiresRestart = MA_TRUE;
16983  }
16984  }
16985  }
16986  }
16987  }
16988 
16989  /* We'll get here if the loop was terminated. Just return whatever's available. */
16990  ma_snd_pcm_sframes_t framesAvailable = ((ma_snd_pcm_avail_update_proc)pDevice->pContext->alsa.snd_pcm_avail_update)((ma_snd_pcm_t*)pDevice->alsa.pPCM);
16991  if (framesAvailable < 0) {
16992  return 0;
16993  }
16994 
16995  return framesAvailable;
16996 }
16997 
16998 static ma_bool32 ma_device_read_from_client_and_write__alsa(ma_device* pDevice)
16999 {
17000  MA_ASSERT(pDevice != NULL);
17001  if (!ma_device_is_started(pDevice) && ma_device__get_state(pDevice) != MA_STATE_STARTING) {
17002  return MA_FALSE;
17003  }
17004  if (pDevice->alsa.breakFromMainLoop) {
17005  return MA_FALSE;
17006  }
17007 
17008  if (pDevice->alsa.isUsingMMap) {
17009  /* mmap. */
17010  ma_bool32 requiresRestart;
17011  ma_uint32 framesAvailable = ma_device__wait_for_frames__alsa(pDevice, &requiresRestart);
17012  if (framesAvailable == 0) {
17013  return MA_FALSE;
17014  }
17015 
17016  /* Don't bother asking the client for more audio data if we're just stopping the device anyway. */
17017  if (pDevice->alsa.breakFromMainLoop) {
17018  return MA_FALSE;
17019  }
17020 
17021  const ma_snd_pcm_channel_area_t* pAreas;
17022  ma_snd_pcm_uframes_t mappedOffset;
17023  ma_snd_pcm_uframes_t mappedFrames = framesAvailable;
17024  while (framesAvailable > 0) {
17025  int result = ((ma_snd_pcm_mmap_begin_proc)pDevice->pContext->alsa.snd_pcm_mmap_begin)((ma_snd_pcm_t*)pDevice->alsa.pPCM, &pAreas, &mappedOffset, &mappedFrames);
17026  if (result < 0) {
17027  return MA_FALSE;
17028  }
17029 
17030  if (mappedFrames > 0) {
17031  void* pBuffer = (ma_uint8*)pAreas[0].addr + ((pAreas[0].first + (mappedOffset * pAreas[0].step)) / 8);
17032  ma_device__read_frames_from_client(pDevice, mappedFrames, pBuffer);
17033  }
17034 
17035  result = ((ma_snd_pcm_mmap_commit_proc)pDevice->pContext->alsa.snd_pcm_mmap_commit)((ma_snd_pcm_t*)pDevice->alsa.pPCM, mappedOffset, mappedFrames);
17036  if (result < 0 || (ma_snd_pcm_uframes_t)result != mappedFrames) {
17037  ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, result, MA_TRUE);
17038  return MA_FALSE;
17039  }
17040 
17041  if (requiresRestart) {
17042  if (((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCM) < 0) {
17043  return MA_FALSE;
17044  }
17045  }
17046 
17047  if (framesAvailable >= mappedFrames) {
17048  framesAvailable -= mappedFrames;
17049  } else {
17050  framesAvailable = 0;
17051  }
17052  }
17053  } else {
17054  /* readi/writei. */
17055  while (!pDevice->alsa.breakFromMainLoop) {
17056  ma_uint32 framesAvailable = ma_device__wait_for_frames__alsa(pDevice, NULL);
17057  if (framesAvailable == 0) {
17058  continue;
17059  }
17060 
17061  /* Don't bother asking the client for more audio data if we're just stopping the device anyway. */
17062  if (pDevice->alsa.breakFromMainLoop) {
17063  return MA_FALSE;
17064  }
17065 
17066  ma_device__read_frames_from_client(pDevice, framesAvailable, pDevice->alsa.pIntermediaryBuffer);
17067 
17068  ma_snd_pcm_sframes_t framesWritten = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable);
17069  if (framesWritten < 0) {
17070  if (framesWritten == -EAGAIN) {
17071  continue; /* Just keep trying... */
17072  } else if (framesWritten == -EPIPE) {
17073  /* Underrun. Just recover and try writing again. */
17074  if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, framesWritten, MA_TRUE) < 0) {
17075  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after underrun.", MA_FAILED_TO_START_BACKEND_DEVICE);
17076  return MA_FALSE;
17077  }
17078 
17079  framesWritten = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable);
17080  if (framesWritten < 0) {
17081  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to write data to the internal device.", ma_result_from_errno((int)-framesWritten));
17082  return MA_FALSE;
17083  }
17084 
17085  break; /* Success. */
17086  } else {
17087  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_writei() failed when writing initial data.", ma_result_from_errno((int)-framesWritten));
17088  return MA_FALSE;
17089  }
17090  } else {
17091  break; /* Success. */
17092  }
17093  }
17094  }
17095 
17096  return MA_TRUE;
17097 }
17098 
17099 static ma_bool32 ma_device_read_and_send_to_client__alsa(ma_device* pDevice)
17100 {
17101  MA_ASSERT(pDevice != NULL);
17102  if (!ma_device_is_started(pDevice)) {
17103  return MA_FALSE;
17104  }
17105  if (pDevice->alsa.breakFromMainLoop) {
17106  return MA_FALSE;
17107  }
17108 
17109  ma_uint32 framesToSend = 0;
17110  void* pBuffer = NULL;
17111  if (pDevice->alsa.pIntermediaryBuffer == NULL) {
17112  /* mmap. */
17113  ma_bool32 requiresRestart;
17114  ma_uint32 framesAvailable = ma_device__wait_for_frames__alsa(pDevice, &requiresRestart);
17115  if (framesAvailable == 0) {
17116  return MA_FALSE;
17117  }
17118 
17119  const ma_snd_pcm_channel_area_t* pAreas;
17120  ma_snd_pcm_uframes_t mappedOffset;
17121  ma_snd_pcm_uframes_t mappedFrames = framesAvailable;
17122  while (framesAvailable > 0) {
17123  int result = ((ma_snd_pcm_mmap_begin_proc)pDevice->pContext->alsa.snd_pcm_mmap_begin)((ma_snd_pcm_t*)pDevice->alsa.pPCM, &pAreas, &mappedOffset, &mappedFrames);
17124  if (result < 0) {
17125  return MA_FALSE;
17126  }
17127 
17128  if (mappedFrames > 0) {
17129  void* pBuffer = (ma_uint8*)pAreas[0].addr + ((pAreas[0].first + (mappedOffset * pAreas[0].step)) / 8);
17130  ma_device__send_frames_to_client(pDevice, mappedFrames, pBuffer);
17131  }
17132 
17133  result = ((ma_snd_pcm_mmap_commit_proc)pDevice->pContext->alsa.snd_pcm_mmap_commit)((ma_snd_pcm_t*)pDevice->alsa.pPCM, mappedOffset, mappedFrames);
17134  if (result < 0 || (ma_snd_pcm_uframes_t)result != mappedFrames) {
17135  ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, result, MA_TRUE);
17136  return MA_FALSE;
17137  }
17138 
17139  if (requiresRestart) {
17140  if (((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCM) < 0) {
17141  return MA_FALSE;
17142  }
17143  }
17144 
17145  if (framesAvailable >= mappedFrames) {
17146  framesAvailable -= mappedFrames;
17147  } else {
17148  framesAvailable = 0;
17149  }
17150  }
17151  } else {
17152  /* readi/writei. */
17153  ma_snd_pcm_sframes_t framesRead = 0;
17154  while (!pDevice->alsa.breakFromMainLoop) {
17155  ma_uint32 framesAvailable = ma_device__wait_for_frames__alsa(pDevice, NULL);
17156  if (framesAvailable == 0) {
17157  continue;
17158  }
17159 
17160  framesRead = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable);
17161  if (framesRead < 0) {
17162  if (framesRead == -EAGAIN) {
17163  continue; /* Just keep trying... */
17164  } else if (framesRead == -EPIPE) {
17165  /* Overrun. Just recover and try reading again. */
17166  if (((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCM, framesRead, MA_TRUE) < 0) {
17167  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after overrun.", MA_FAILED_TO_START_BACKEND_DEVICE);
17168  return MA_FALSE;
17169  }
17170 
17171  framesRead = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCM, pDevice->alsa.pIntermediaryBuffer, framesAvailable);
17172  if (framesRead < 0) {
17173  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to read data from the internal device.", ma_result_from_errno((int)-framesRead));
17174  return MA_FALSE;
17175  }
17176 
17177  break; /* Success. */
17178  } else {
17179  return MA_FALSE;
17180  }
17181  } else {
17182  break; /* Success. */
17183  }
17184  }
17185 
17186  framesToSend = framesRead;
17187  pBuffer = pDevice->alsa.pIntermediaryBuffer;
17188  }
17189 
17190  if (framesToSend > 0) {
17191  ma_device__send_frames_to_client(pDevice, framesToSend, pBuffer);
17192  }
17193 
17194  return MA_TRUE;
17195 }
17196 #endif /* 0 */
17197 
17198 static void ma_device_uninit__alsa(ma_device* pDevice)
17199 {
17200  MA_ASSERT(pDevice != NULL);
17201 
17202  if ((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) {
17203  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
17204  }
17205 
17206  if ((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) {
17207  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
17208  }
17209 }
17210 
17211 static ma_result ma_device_init_by_type__alsa(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice)
17212 {
17213  ma_result result;
17214  int resultALSA;
17215  ma_snd_pcm_t* pPCM;
17216  ma_bool32 isUsingMMap;
17217  ma_snd_pcm_format_t formatALSA;
17218  ma_share_mode shareMode;
17219  ma_device_id* pDeviceID;
17220  ma_format internalFormat;
17221  ma_uint32 internalChannels;
17222  ma_uint32 internalSampleRate;
17223  ma_channel internalChannelMap[MA_MAX_CHANNELS];
17224  ma_uint32 internalPeriodSizeInFrames;
17225  ma_uint32 internalPeriods;
17226  ma_snd_pcm_hw_params_t* pHWParams;
17227  ma_snd_pcm_sw_params_t* pSWParams;
17228  ma_snd_pcm_uframes_t bufferBoundary;
17229  float bufferSizeScaleFactor;
17230 
17231  MA_ASSERT(pContext != NULL);
17232  MA_ASSERT(pConfig != NULL);
17233  MA_ASSERT(deviceType != ma_device_type_duplex); /* This function should only be called for playback _or_ capture, never duplex. */
17234  MA_ASSERT(pDevice != NULL);
17235 
17236  formatALSA = ma_convert_ma_format_to_alsa_format((deviceType == ma_device_type_capture) ? pConfig->capture.format : pConfig->playback.format);
17237  shareMode = (deviceType == ma_device_type_capture) ? pConfig->capture.shareMode : pConfig->playback.shareMode;
17238  pDeviceID = (deviceType == ma_device_type_capture) ? pConfig->capture.pDeviceID : pConfig->playback.pDeviceID;
17239 
17240  result = ma_context_open_pcm__alsa(pContext, shareMode, deviceType, pDeviceID, &pPCM);
17241  if (result != MA_SUCCESS) {
17242  return result;
17243  }
17244 
17245  /* If using the default buffer size we may want to apply some device-specific scaling for known devices that have peculiar latency characteristics */
17246  bufferSizeScaleFactor = 1;
17247  if (pDevice->usingDefaultBufferSize) {
17248  ma_snd_pcm_info_t* pInfo = (ma_snd_pcm_info_t*)ma__calloc_from_callbacks(((ma_snd_pcm_info_sizeof_proc)pContext->alsa.snd_pcm_info_sizeof)(), &pContext->allocationCallbacks);
17249  if (pInfo == NULL) {
17250  return MA_OUT_OF_MEMORY;
17251  }
17252 
17253  /* We may need to scale the size of the buffer depending on the device. */
17254  if (((ma_snd_pcm_info_proc)pContext->alsa.snd_pcm_info)(pPCM, pInfo) == 0) {
17255  const char* deviceName = ((ma_snd_pcm_info_get_name_proc)pContext->alsa.snd_pcm_info_get_name)(pInfo);
17256  if (deviceName != NULL) {
17257  if (ma_strcmp(deviceName, "default") == 0) {
17258  char** ppDeviceHints;
17259  char** ppNextDeviceHint;
17260 
17261  /* It's the default device. We need to use DESC from snd_device_name_hint(). */
17262  if (((ma_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints) < 0) {
17263  ma__free_from_callbacks(pInfo, &pContext->allocationCallbacks);
17264  return MA_NO_BACKEND;
17265  }
17266 
17267  ppNextDeviceHint = ppDeviceHints;
17268  while (*ppNextDeviceHint != NULL) {
17269  char* NAME = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME");
17270  char* DESC = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC");
17271  char* IOID = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID");
17272 
17273  ma_bool32 foundDevice = MA_FALSE;
17274  if ((deviceType == ma_device_type_playback && (IOID == NULL || ma_strcmp(IOID, "Output") == 0)) ||
17275  (deviceType == ma_device_type_capture && (IOID != NULL && ma_strcmp(IOID, "Input" ) == 0))) {
17276  if (ma_strcmp(NAME, deviceName) == 0) {
17277  bufferSizeScaleFactor = ma_find_default_buffer_size_scale__alsa(DESC);
17278  foundDevice = MA_TRUE;
17279  }
17280  }
17281 
17282  free(NAME);
17283  free(DESC);
17284  free(IOID);
17285  ppNextDeviceHint += 1;
17286 
17287  if (foundDevice) {
17288  break;
17289  }
17290  }
17291 
17292  ((ma_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints);
17293  } else {
17294  bufferSizeScaleFactor = ma_find_default_buffer_size_scale__alsa(deviceName);
17295  }
17296  }
17297  }
17298 
17299  ma__free_from_callbacks(pInfo, &pContext->allocationCallbacks);
17300  }
17301 
17302 
17303  /* Hardware parameters. */
17304  pHWParams = (ma_snd_pcm_hw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)(), &pContext->allocationCallbacks);
17305  if (pHWParams == NULL) {
17306  return MA_OUT_OF_MEMORY;
17307  }
17308 
17309  resultALSA = ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
17310  if (resultALSA < 0) {
17311  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17312  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17313  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", ma_result_from_errno(-resultALSA));
17314  }
17315 
17316  /* MMAP Mode. Try using interleaved MMAP access. If this fails, fall back to standard readi/writei. */
17317  isUsingMMap = MA_FALSE;
17318 #if 0 /* NOTE: MMAP mode temporarily disabled. */
17319  if (deviceType != ma_device_type_capture) { /* <-- Disabling MMAP mode for capture devices because I apparently do not have a device that supports it which means I can't test it... Contributions welcome. */
17320  if (!pConfig->alsa.noMMap && ma_device__is_async(pDevice)) {
17321  if (((ma_snd_pcm_hw_params_set_access_proc)pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_MMAP_INTERLEAVED) == 0) {
17322  pDevice->alsa.isUsingMMap = MA_TRUE;
17323  }
17324  }
17325  }
17326 #endif
17327 
17328  if (!isUsingMMap) {
17329  resultALSA = ((ma_snd_pcm_hw_params_set_access_proc)pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_RW_INTERLEAVED);
17330  if (resultALSA < 0) {
17331  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17332  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17333  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set access mode to neither SND_PCM_ACCESS_MMAP_INTERLEAVED nor SND_PCM_ACCESS_RW_INTERLEAVED. snd_pcm_hw_params_set_access() failed.", ma_result_from_errno(-resultALSA));
17334  }
17335  }
17336 
17337  /*
17338  Most important properties first. The documentation for OSS (yes, I know this is ALSA!) recommends format, channels, then sample rate. I can't
17339  find any documentation for ALSA specifically, so I'm going to copy the recommendation for OSS.
17340  */
17341 
17342  /* Format. */
17343  {
17344  ma_snd_pcm_format_mask_t* pFormatMask;
17345 
17346  /* Try getting every supported format first. */
17347  pFormatMask = (ma_snd_pcm_format_mask_t*)ma__calloc_from_callbacks(((ma_snd_pcm_format_mask_sizeof_proc)pContext->alsa.snd_pcm_format_mask_sizeof)(), &pContext->allocationCallbacks);
17348  if (pFormatMask == NULL) {
17349  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17350  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17351  return MA_OUT_OF_MEMORY;
17352  }
17353 
17354  ((ma_snd_pcm_hw_params_get_format_mask_proc)pContext->alsa.snd_pcm_hw_params_get_format_mask)(pHWParams, pFormatMask);
17355 
17356  /*
17357  At this point we should have a list of supported formats, so now we need to find the best one. We first check if the requested format is
17358  supported, and if so, use that one. If it's not supported, we just run though a list of formats and try to find the best one.
17359  */
17360  if (!((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, formatALSA)) {
17361  size_t i;
17362 
17363  /* The requested format is not supported so now try running through the list of formats and return the best one. */
17364  ma_snd_pcm_format_t preferredFormatsALSA[] = {
17365  MA_SND_PCM_FORMAT_S16_LE, /* ma_format_s16 */
17366  MA_SND_PCM_FORMAT_FLOAT_LE, /* ma_format_f32 */
17367  MA_SND_PCM_FORMAT_S32_LE, /* ma_format_s32 */
17368  MA_SND_PCM_FORMAT_S24_3LE, /* ma_format_s24 */
17369  MA_SND_PCM_FORMAT_U8 /* ma_format_u8 */
17370  };
17371 
17372  if (ma_is_big_endian()) {
17373  preferredFormatsALSA[0] = MA_SND_PCM_FORMAT_S16_BE;
17374  preferredFormatsALSA[1] = MA_SND_PCM_FORMAT_FLOAT_BE;
17375  preferredFormatsALSA[2] = MA_SND_PCM_FORMAT_S32_BE;
17376  preferredFormatsALSA[3] = MA_SND_PCM_FORMAT_S24_3BE;
17377  preferredFormatsALSA[4] = MA_SND_PCM_FORMAT_U8;
17378  }
17379 
17380  formatALSA = MA_SND_PCM_FORMAT_UNKNOWN;
17381  for (i = 0; i < (sizeof(preferredFormatsALSA) / sizeof(preferredFormatsALSA[0])); ++i) {
17382  if (((ma_snd_pcm_format_mask_test_proc)pContext->alsa.snd_pcm_format_mask_test)(pFormatMask, preferredFormatsALSA[i])) {
17383  formatALSA = preferredFormatsALSA[i];
17384  break;
17385  }
17386  }
17387 
17388  if (formatALSA == MA_SND_PCM_FORMAT_UNKNOWN) {
17389  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17390  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17391  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. The device does not support any miniaudio formats.", MA_FORMAT_NOT_SUPPORTED);
17392  }
17393  }
17394 
17395  ma__free_from_callbacks(pFormatMask, &pContext->allocationCallbacks);
17396  pFormatMask = NULL;
17397 
17398  resultALSA = ((ma_snd_pcm_hw_params_set_format_proc)pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, formatALSA);
17399  if (resultALSA < 0) {
17400  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17401  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17402  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed.", ma_result_from_errno(-resultALSA));
17403  }
17404 
17405  internalFormat = ma_format_from_alsa(formatALSA);
17406  if (internalFormat == ma_format_unknown) {
17407  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17408  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17409  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] The chosen format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED);
17410  }
17411  }
17412 
17413  /* Channels. */
17414  {
17415  unsigned int channels = (deviceType == ma_device_type_capture) ? pConfig->capture.channels : pConfig->playback.channels;
17416  resultALSA = ((ma_snd_pcm_hw_params_set_channels_near_proc)pContext->alsa.snd_pcm_hw_params_set_channels_near)(pPCM, pHWParams, &channels);
17417  if (resultALSA < 0) {
17418  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17419  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17420  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed.", ma_result_from_errno(-resultALSA));
17421  }
17422  internalChannels = (ma_uint32)channels;
17423  }
17424 
17425  /* Sample Rate */
17426  {
17427  unsigned int sampleRate;
17428 
17429  /*
17430  It appears there's either a bug in ALSA, a bug in some drivers, or I'm doing something silly; but having resampling enabled causes
17431  problems with some device configurations when used in conjunction with MMAP access mode. To fix this problem we need to disable
17432  resampling.
17433 
17434  To reproduce this problem, open the "plug:dmix" device, and set the sample rate to 44100. Internally, it looks like dmix uses a
17435  sample rate of 48000. The hardware parameters will get set correctly with no errors, but it looks like the 44100 -> 48000 resampling
17436  doesn't work properly - but only with MMAP access mode. You will notice skipping/crackling in the audio, and it'll run at a slightly
17437  faster rate.
17438 
17439  miniaudio has built-in support for sample rate conversion (albeit low quality at the moment), so disabling resampling should be fine
17440  for us. The only problem is that it won't be taking advantage of any kind of hardware-accelerated resampling and it won't be very
17441  good quality until I get a chance to improve the quality of miniaudio's software sample rate conversion.
17442 
17443  I don't currently know if the dmix plugin is the only one with this error. Indeed, this is the only one I've been able to reproduce
17444  this error with. In the future, we may want to restrict the disabling of resampling to only known bad plugins.
17445  */
17446  ((ma_snd_pcm_hw_params_set_rate_resample_proc)pContext->alsa.snd_pcm_hw_params_set_rate_resample)(pPCM, pHWParams, 0);
17447 
17448  sampleRate = pConfig->sampleRate;
17449  resultALSA = ((ma_snd_pcm_hw_params_set_rate_near_proc)pContext->alsa.snd_pcm_hw_params_set_rate_near)(pPCM, pHWParams, &sampleRate, 0);
17450  if (resultALSA < 0) {
17451  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17452  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17453  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed.", ma_result_from_errno(-resultALSA));
17454  }
17455  internalSampleRate = (ma_uint32)sampleRate;
17456  }
17457 
17458  /* Periods. */
17459  {
17460  ma_uint32 periods = pConfig->periods;
17461  resultALSA = ((ma_snd_pcm_hw_params_set_periods_near_proc)pContext->alsa.snd_pcm_hw_params_set_periods_near)(pPCM, pHWParams, &periods, NULL);
17462  if (resultALSA < 0) {
17463  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17464  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17465  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed.", ma_result_from_errno(-resultALSA));
17466  }
17467  internalPeriods = periods;
17468  }
17469 
17470  /* Buffer Size */
17471  {
17472  ma_snd_pcm_uframes_t actualBufferSizeInFrames = pConfig->periodSizeInFrames * internalPeriods;
17473  if (actualBufferSizeInFrames == 0) {
17474  actualBufferSizeInFrames = ma_scale_buffer_size(ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, internalSampleRate), bufferSizeScaleFactor) * internalPeriods;
17475  }
17476 
17477  resultALSA = ((ma_snd_pcm_hw_params_set_buffer_size_near_proc)pContext->alsa.snd_pcm_hw_params_set_buffer_size_near)(pPCM, pHWParams, &actualBufferSizeInFrames);
17478  if (resultALSA < 0) {
17479  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17480  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17481  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed.", ma_result_from_errno(-resultALSA));
17482  }
17483  internalPeriodSizeInFrames = actualBufferSizeInFrames / internalPeriods;
17484  }
17485 
17486  /* Apply hardware parameters. */
17487  resultALSA = ((ma_snd_pcm_hw_params_proc)pContext->alsa.snd_pcm_hw_params)(pPCM, pHWParams);
17488  if (resultALSA < 0) {
17489  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17490  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17491  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed.", ma_result_from_errno(-resultALSA));
17492  }
17493 
17494  ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
17495  pHWParams = NULL;
17496 
17497 
17498  /* Software parameters. */
17499  pSWParams = (ma_snd_pcm_sw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_sw_params_sizeof_proc)pContext->alsa.snd_pcm_sw_params_sizeof)(), &pContext->allocationCallbacks);
17500  if (pSWParams == NULL) {
17501  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17502  return MA_OUT_OF_MEMORY;
17503  }
17504 
17505  resultALSA = ((ma_snd_pcm_sw_params_current_proc)pContext->alsa.snd_pcm_sw_params_current)(pPCM, pSWParams);
17506  if (resultALSA < 0) {
17507  ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
17508  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17509  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed.", ma_result_from_errno(-resultALSA));
17510  }
17511 
17512  resultALSA = ((ma_snd_pcm_sw_params_set_avail_min_proc)pContext->alsa.snd_pcm_sw_params_set_avail_min)(pPCM, pSWParams, ma_prev_power_of_2(internalPeriodSizeInFrames));
17513  if (resultALSA < 0) {
17514  ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
17515  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17516  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_sw_params_set_avail_min() failed.", ma_result_from_errno(-resultALSA));
17517  }
17518 
17519  resultALSA = ((ma_snd_pcm_sw_params_get_boundary_proc)pContext->alsa.snd_pcm_sw_params_get_boundary)(pSWParams, &bufferBoundary);
17520  if (resultALSA < 0) {
17521  bufferBoundary = internalPeriodSizeInFrames * internalPeriods;
17522  }
17523 
17524  /*printf("TRACE: bufferBoundary=%ld\n", bufferBoundary);*/
17525 
17526  if (deviceType == ma_device_type_playback && !isUsingMMap) { /* Only playback devices in writei/readi mode need a start threshold. */
17527  /*
17528  Subtle detail here with the start threshold. When in playback-only mode (no full-duplex) we can set the start threshold to
17529  the size of a period. But for full-duplex we need to set it such that it is at least two periods.
17530  */
17531  resultALSA = ((ma_snd_pcm_sw_params_set_start_threshold_proc)pContext->alsa.snd_pcm_sw_params_set_start_threshold)(pPCM, pSWParams, internalPeriodSizeInFrames*2);
17532  if (resultALSA < 0) {
17533  ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
17534  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17535  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.", ma_result_from_errno(-resultALSA));
17536  }
17537 
17538  resultALSA = ((ma_snd_pcm_sw_params_set_stop_threshold_proc)pContext->alsa.snd_pcm_sw_params_set_stop_threshold)(pPCM, pSWParams, bufferBoundary);
17539  if (resultALSA < 0) { /* Set to boundary to loop instead of stop in the event of an xrun. */
17540  ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
17541  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17542  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set stop threshold for playback device. snd_pcm_sw_params_set_stop_threshold() failed.", ma_result_from_errno(-resultALSA));
17543  }
17544  }
17545 
17546  resultALSA = ((ma_snd_pcm_sw_params_proc)pContext->alsa.snd_pcm_sw_params)(pPCM, pSWParams);
17547  if (resultALSA < 0) {
17548  ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
17549  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17550  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed.", ma_result_from_errno(-resultALSA));
17551  }
17552 
17553  ma__free_from_callbacks(pSWParams, &pContext->allocationCallbacks);
17554  pSWParams = NULL;
17555 
17556 
17557  /* Grab the internal channel map. For now we're not going to bother trying to change the channel map and instead just do it ourselves. */
17558  {
17559  ma_snd_pcm_chmap_t* pChmap = ((ma_snd_pcm_get_chmap_proc)pContext->alsa.snd_pcm_get_chmap)(pPCM);
17560  if (pChmap != NULL) {
17561  ma_uint32 iChannel;
17562 
17563  /* There are cases where the returned channel map can have a different channel count than was returned by snd_pcm_hw_params_set_channels_near(). */
17564  if (pChmap->channels >= internalChannels) {
17565  /* Drop excess channels. */
17566  for (iChannel = 0; iChannel < internalChannels; ++iChannel) {
17567  internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]);
17568  }
17569  } else {
17570  ma_uint32 i;
17571 
17572  /*
17573  Excess channels use defaults. Do an initial fill with defaults, overwrite the first pChmap->channels, validate to ensure there are no duplicate
17574  channels. If validation fails, fall back to defaults.
17575  */
17576  ma_bool32 isValid = MA_TRUE;
17577 
17578  /* Fill with defaults. */
17579  ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap);
17580 
17581  /* Overwrite first pChmap->channels channels. */
17582  for (iChannel = 0; iChannel < pChmap->channels; ++iChannel) {
17583  internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]);
17584  }
17585 
17586  /* Validate. */
17587  for (i = 0; i < internalChannels && isValid; ++i) {
17588  ma_uint32 j;
17589  for (j = i+1; j < internalChannels; ++j) {
17590  if (internalChannelMap[i] == internalChannelMap[j]) {
17591  isValid = MA_FALSE;
17592  break;
17593  }
17594  }
17595  }
17596 
17597  /* If our channel map is invalid, fall back to defaults. */
17598  if (!isValid) {
17599  ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap);
17600  }
17601  }
17602 
17603  free(pChmap);
17604  pChmap = NULL;
17605  } else {
17606  /* Could not retrieve the channel map. Fall back to a hard-coded assumption. */
17607  ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap);
17608  }
17609  }
17610 
17611 
17612  /* We're done. Prepare the device. */
17613  resultALSA = ((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)(pPCM);
17614  if (resultALSA < 0) {
17615  ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
17616  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to prepare device.", ma_result_from_errno(-resultALSA));
17617  }
17618 
17619 
17620  if (deviceType == ma_device_type_capture) {
17621  pDevice->alsa.pPCMCapture = (ma_ptr)pPCM;
17622  pDevice->alsa.isUsingMMapCapture = isUsingMMap;
17623  pDevice->capture.internalFormat = internalFormat;
17624  pDevice->capture.internalChannels = internalChannels;
17625  pDevice->capture.internalSampleRate = internalSampleRate;
17626  ma_channel_map_copy(pDevice->capture.internalChannelMap, internalChannelMap, internalChannels);
17627  pDevice->capture.internalPeriodSizeInFrames = internalPeriodSizeInFrames;
17628  pDevice->capture.internalPeriods = internalPeriods;
17629  } else {
17630  pDevice->alsa.pPCMPlayback = (ma_ptr)pPCM;
17631  pDevice->alsa.isUsingMMapPlayback = isUsingMMap;
17632  pDevice->playback.internalFormat = internalFormat;
17633  pDevice->playback.internalChannels = internalChannels;
17634  pDevice->playback.internalSampleRate = internalSampleRate;
17635  ma_channel_map_copy(pDevice->playback.internalChannelMap, internalChannelMap, internalChannels);
17636  pDevice->playback.internalPeriodSizeInFrames = internalPeriodSizeInFrames;
17637  pDevice->playback.internalPeriods = internalPeriods;
17638  }
17639 
17640  return MA_SUCCESS;
17641 }
17642 
17643 static ma_result ma_device_init__alsa(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
17644 {
17645  MA_ASSERT(pDevice != NULL);
17646 
17647  MA_ZERO_OBJECT(&pDevice->alsa);
17648 
17649  if (pConfig->deviceType == ma_device_type_loopback) {
17651  }
17652 
17653  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
17654  ma_result result = ma_device_init_by_type__alsa(pContext, pConfig, ma_device_type_capture, pDevice);
17655  if (result != MA_SUCCESS) {
17656  return result;
17657  }
17658  }
17659 
17660  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
17661  ma_result result = ma_device_init_by_type__alsa(pContext, pConfig, ma_device_type_playback, pDevice);
17662  if (result != MA_SUCCESS) {
17663  return result;
17664  }
17665  }
17666 
17667  return MA_SUCCESS;
17668 }
17669 
17670 static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead)
17671 {
17672  ma_snd_pcm_sframes_t resultALSA;
17673 
17674  MA_ASSERT(pDevice != NULL);
17675  MA_ASSERT(pFramesOut != NULL);
17676 
17677  if (pFramesRead != NULL) {
17678  *pFramesRead = 0;
17679  }
17680 
17681  for (;;) {
17682  resultALSA = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, pFramesOut, frameCount);
17683  if (resultALSA >= 0) {
17684  break; /* Success. */
17685  } else {
17686  if (resultALSA == -EAGAIN) {
17687  /*printf("TRACE: EGAIN (read)\n");*/
17688  continue; /* Try again. */
17689  } else if (resultALSA == -EPIPE) {
17690  #if defined(MA_DEBUG_OUTPUT)
17691  printf("TRACE: EPIPE (read)\n");
17692  #endif
17693 
17694  /* Overrun. Recover and try again. If this fails we need to return an error. */
17695  resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, resultALSA, MA_TRUE);
17696  if (resultALSA < 0) {
17697  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after overrun.", ma_result_from_errno((int)-resultALSA));
17698  }
17699 
17700  resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
17701  if (resultALSA < 0) {
17702  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.", ma_result_from_errno((int)-resultALSA));
17703  }
17704 
17705  resultALSA = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, pFramesOut, frameCount);
17706  if (resultALSA < 0) {
17707  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to read data from the internal device.", ma_result_from_errno((int)-resultALSA));
17708  }
17709  }
17710  }
17711  }
17712 
17713  if (pFramesRead != NULL) {
17714  *pFramesRead = resultALSA;
17715  }
17716 
17717  return MA_SUCCESS;
17718 }
17719 
17720 static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
17721 {
17722  ma_snd_pcm_sframes_t resultALSA;
17723 
17724  MA_ASSERT(pDevice != NULL);
17725  MA_ASSERT(pFrames != NULL);
17726 
17727  if (pFramesWritten != NULL) {
17728  *pFramesWritten = 0;
17729  }
17730 
17731  for (;;) {
17732  resultALSA = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, pFrames, frameCount);
17733  if (resultALSA >= 0) {
17734  break; /* Success. */
17735  } else {
17736  if (resultALSA == -EAGAIN) {
17737  /*printf("TRACE: EGAIN (write)\n");*/
17738  continue; /* Try again. */
17739  } else if (resultALSA == -EPIPE) {
17740  #if defined(MA_DEBUG_OUTPUT)
17741  printf("TRACE: EPIPE (write)\n");
17742  #endif
17743 
17744  /* Underrun. Recover and try again. If this fails we need to return an error. */
17745  resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, resultALSA, MA_TRUE);
17746  if (resultALSA < 0) { /* MA_TRUE=silent (don't print anything on error). */
17747  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after underrun.", ma_result_from_errno((int)-resultALSA));
17748  }
17749 
17750  /*
17751  In my testing I have had a situation where writei() does not automatically restart the device even though I've set it
17752  up as such in the software parameters. What will happen is writei() will block indefinitely even though the number of
17753  frames is well beyond the auto-start threshold. To work around this I've needed to add an explicit start here. Not sure
17754  if this is me just being stupid and not recovering the device properly, but this definitely feels like something isn't
17755  quite right here.
17756  */
17757  resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
17758  if (resultALSA < 0) {
17759  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.", ma_result_from_errno((int)-resultALSA));
17760  }
17761 
17762  resultALSA = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, pFrames, frameCount);
17763  if (resultALSA < 0) {
17764  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to write data to device after underrun.", ma_result_from_errno((int)-resultALSA));
17765  }
17766  }
17767  }
17768  }
17769 
17770  if (pFramesWritten != NULL) {
17771  *pFramesWritten = resultALSA;
17772  }
17773 
17774  return MA_SUCCESS;
17775 }
17776 
17777 static ma_result ma_device_main_loop__alsa(ma_device* pDevice)
17778 {
17779  ma_result result = MA_SUCCESS;
17780  int resultALSA;
17781  ma_bool32 exitLoop = MA_FALSE;
17782 
17783  MA_ASSERT(pDevice != NULL);
17784 
17785  /* Capture devices need to be started immediately. */
17786  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
17787  resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
17788  if (resultALSA < 0) {
17789  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device in preparation for reading.", ma_result_from_errno(-resultALSA));
17790  }
17791  }
17792 
17793  while (ma_device__get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
17794  switch (pDevice->type)
17795  {
17796  case ma_device_type_duplex:
17797  {
17798  if (pDevice->alsa.isUsingMMapCapture || pDevice->alsa.isUsingMMapPlayback) {
17799  /* MMAP */
17800  return MA_INVALID_OPERATION; /* Not yet implemented. */
17801  } else {
17802  /* readi() and writei() */
17803 
17804  /* The process is: device_read -> convert -> callback -> convert -> device_write */
17805  ma_uint32 totalCapturedDeviceFramesProcessed = 0;
17806  ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
17807 
17808  while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
17809  ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17810  ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17811  ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
17812  ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
17813  ma_uint32 capturedDeviceFramesRemaining;
17814  ma_uint32 capturedDeviceFramesProcessed;
17815  ma_uint32 capturedDeviceFramesToProcess;
17816  ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed;
17817  if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) {
17818  capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames;
17819  }
17820 
17821  result = ma_device_read__alsa(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess);
17822  if (result != MA_SUCCESS) {
17823  exitLoop = MA_TRUE;
17824  break;
17825  }
17826 
17827  capturedDeviceFramesRemaining = capturedDeviceFramesToProcess;
17828  capturedDeviceFramesProcessed = 0;
17829 
17830  for (;;) {
17831  ma_uint8 capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17832  ma_uint8 playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17833  ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
17834  ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
17835  ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames);
17836  ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining;
17837  ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
17838 
17839  /* Convert capture data from device format to client format. */
17840  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration);
17841  if (result != MA_SUCCESS) {
17842  break;
17843  }
17844 
17845  /*
17846  If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small
17847  which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
17848  */
17849  if (capturedClientFramesToProcessThisIteration == 0) {
17850  break;
17851  }
17852 
17853  ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/
17854 
17855  capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
17856  capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
17857 
17858  /* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */
17859  for (;;) {
17860  ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration;
17861  ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames;
17862  result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount);
17863  if (result != MA_SUCCESS) {
17864  break;
17865  }
17866 
17867  result = ma_device_write__alsa(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL); /* Safe cast. */
17868  if (result != MA_SUCCESS) {
17869  exitLoop = MA_TRUE;
17870  break;
17871  }
17872 
17873  capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount; /* Safe cast. */
17874  if (capturedClientFramesToProcessThisIteration == 0) {
17875  break;
17876  }
17877  }
17878 
17879  /* In case an error happened from ma_device_write__alsa()... */
17880  if (result != MA_SUCCESS) {
17881  exitLoop = MA_TRUE;
17882  break;
17883  }
17884  }
17885 
17886  totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed;
17887  }
17888  }
17889  } break;
17890 
17892  {
17893  if (pDevice->alsa.isUsingMMapCapture) {
17894  /* MMAP */
17895  return MA_INVALID_OPERATION; /* Not yet implemented. */
17896  } else {
17897  /* readi() */
17898 
17899  /* We read in chunks of the period size, but use a stack allocated buffer for the intermediary. */
17900  ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17901  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
17902  ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
17903  ma_uint32 framesReadThisPeriod = 0;
17904  while (framesReadThisPeriod < periodSizeInFrames) {
17905  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
17906  ma_uint32 framesProcessed;
17907  ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
17908  if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
17909  framesToReadThisIteration = intermediaryBufferSizeInFrames;
17910  }
17911 
17912  result = ma_device_read__alsa(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
17913  if (result != MA_SUCCESS) {
17914  exitLoop = MA_TRUE;
17915  break;
17916  }
17917 
17918  ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
17919 
17920  framesReadThisPeriod += framesProcessed;
17921  }
17922  }
17923  } break;
17924 
17926  {
17927  if (pDevice->alsa.isUsingMMapPlayback) {
17928  /* MMAP */
17929  return MA_INVALID_OPERATION; /* Not yet implemented. */
17930  } else {
17931  /* writei() */
17932 
17933  /* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
17934  ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17935  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
17936  ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
17937  ma_uint32 framesWrittenThisPeriod = 0;
17938  while (framesWrittenThisPeriod < periodSizeInFrames) {
17939  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
17940  ma_uint32 framesProcessed;
17941  ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
17942  if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
17943  framesToWriteThisIteration = intermediaryBufferSizeInFrames;
17944  }
17945 
17946  ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
17947 
17948  result = ma_device_write__alsa(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
17949  if (result != MA_SUCCESS) {
17950  exitLoop = MA_TRUE;
17951  break;
17952  }
17953 
17954  framesWrittenThisPeriod += framesProcessed;
17955  }
17956  }
17957  } break;
17958 
17959  /* To silence a warning. Will never hit this. */
17961  default: break;
17962  }
17963  }
17964 
17965  /* Here is where the device needs to be stopped. */
17966  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
17967  ((ma_snd_pcm_drain_proc)pDevice->pContext->alsa.snd_pcm_drain)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
17968 
17969  /* We need to prepare the device again, otherwise we won't be able to restart the device. */
17970  if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) < 0) {
17971  #ifdef MA_DEBUG_OUTPUT
17972  printf("[ALSA] Failed to prepare capture device after stopping.\n");
17973  #endif
17974  }
17975  }
17976 
17977  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
17978  ((ma_snd_pcm_drain_proc)pDevice->pContext->alsa.snd_pcm_drain)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
17979 
17980  /* We need to prepare the device again, otherwise we won't be able to restart the device. */
17981  if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) < 0) {
17982  #ifdef MA_DEBUG_OUTPUT
17983  printf("[ALSA] Failed to prepare playback device after stopping.\n");
17984  #endif
17985  }
17986  }
17987 
17988  return result;
17989 }
17990 
17991 static ma_result ma_context_uninit__alsa(ma_context* pContext)
17992 {
17993  MA_ASSERT(pContext != NULL);
17994  MA_ASSERT(pContext->backend == ma_backend_alsa);
17995 
17996  /* Clean up memory for memory leak checkers. */
17997  ((ma_snd_config_update_free_global_proc)pContext->alsa.snd_config_update_free_global)();
17998 
17999 #ifndef MA_NO_RUNTIME_LINKING
18000  ma_dlclose(pContext, pContext->alsa.asoundSO);
18001 #endif
18002 
18003  ma_mutex_uninit(&pContext->alsa.internalDeviceEnumLock);
18004 
18005  return MA_SUCCESS;
18006 }
18007 
18008 static ma_result ma_context_init__alsa(const ma_context_config* pConfig, ma_context* pContext)
18009 {
18010 #ifndef MA_NO_RUNTIME_LINKING
18011  const char* libasoundNames[] = {
18012  "libasound.so.2",
18013  "libasound.so"
18014  };
18015  size_t i;
18016 
18017  for (i = 0; i < ma_countof(libasoundNames); ++i) {
18018  pContext->alsa.asoundSO = ma_dlopen(pContext, libasoundNames[i]);
18019  if (pContext->alsa.asoundSO != NULL) {
18020  break;
18021  }
18022  }
18023 
18024  if (pContext->alsa.asoundSO == NULL) {
18025 #ifdef MA_DEBUG_OUTPUT
18026  printf("[ALSA] Failed to open shared object.\n");
18027 #endif
18028  return MA_NO_BACKEND;
18029  }
18030 
18031  pContext->alsa.snd_pcm_open = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_open");
18032  pContext->alsa.snd_pcm_close = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_close");
18033  pContext->alsa.snd_pcm_hw_params_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_sizeof");
18034  pContext->alsa.snd_pcm_hw_params_any = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_any");
18035  pContext->alsa.snd_pcm_hw_params_set_format = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format");
18036  pContext->alsa.snd_pcm_hw_params_set_format_first = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format_first");
18037  pContext->alsa.snd_pcm_hw_params_get_format_mask = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format_mask");
18038  pContext->alsa.snd_pcm_hw_params_set_channels_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_near");
18039  pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_resample");
18040  pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_near");
18041  pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_buffer_size_near");
18042  pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_periods_near");
18043  pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_access");
18044  pContext->alsa.snd_pcm_hw_params_get_format = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format");
18045  pContext->alsa.snd_pcm_hw_params_get_channels = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels");
18046  pContext->alsa.snd_pcm_hw_params_get_channels_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_min");
18047  pContext->alsa.snd_pcm_hw_params_get_channels_max = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_max");
18048  pContext->alsa.snd_pcm_hw_params_get_rate = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate");
18049  pContext->alsa.snd_pcm_hw_params_get_rate_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_min");
18050  pContext->alsa.snd_pcm_hw_params_get_rate_max = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_max");
18051  pContext->alsa.snd_pcm_hw_params_get_buffer_size = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_buffer_size");
18052  pContext->alsa.snd_pcm_hw_params_get_periods = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_periods");
18053  pContext->alsa.snd_pcm_hw_params_get_access = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_access");
18054  pContext->alsa.snd_pcm_hw_params = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params");
18055  pContext->alsa.snd_pcm_sw_params_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_sizeof");
18056  pContext->alsa.snd_pcm_sw_params_current = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_current");
18057  pContext->alsa.snd_pcm_sw_params_get_boundary = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_get_boundary");
18058  pContext->alsa.snd_pcm_sw_params_set_avail_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_avail_min");
18059  pContext->alsa.snd_pcm_sw_params_set_start_threshold = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_start_threshold");
18060  pContext->alsa.snd_pcm_sw_params_set_stop_threshold = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_stop_threshold");
18061  pContext->alsa.snd_pcm_sw_params = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params");
18062  pContext->alsa.snd_pcm_format_mask_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_sizeof");
18063  pContext->alsa.snd_pcm_format_mask_test = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_test");
18064  pContext->alsa.snd_pcm_get_chmap = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_get_chmap");
18065  pContext->alsa.snd_pcm_state = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_state");
18066  pContext->alsa.snd_pcm_prepare = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_prepare");
18067  pContext->alsa.snd_pcm_start = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_start");
18068  pContext->alsa.snd_pcm_drop = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drop");
18069  pContext->alsa.snd_pcm_drain = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drain");
18070  pContext->alsa.snd_device_name_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_hint");
18071  pContext->alsa.snd_device_name_get_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_get_hint");
18072  pContext->alsa.snd_card_get_index = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_card_get_index");
18073  pContext->alsa.snd_device_name_free_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_free_hint");
18074  pContext->alsa.snd_pcm_mmap_begin = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_begin");
18075  pContext->alsa.snd_pcm_mmap_commit = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_commit");
18076  pContext->alsa.snd_pcm_recover = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_recover");
18077  pContext->alsa.snd_pcm_readi = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_readi");
18078  pContext->alsa.snd_pcm_writei = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_writei");
18079  pContext->alsa.snd_pcm_avail = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail");
18080  pContext->alsa.snd_pcm_avail_update = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail_update");
18081  pContext->alsa.snd_pcm_wait = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_wait");
18082  pContext->alsa.snd_pcm_info = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info");
18083  pContext->alsa.snd_pcm_info_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_sizeof");
18084  pContext->alsa.snd_pcm_info_get_name = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_get_name");
18085  pContext->alsa.snd_config_update_free_global = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_config_update_free_global");
18086 #else
18087  /* The system below is just for type safety. */
18088  ma_snd_pcm_open_proc _snd_pcm_open = snd_pcm_open;
18089  ma_snd_pcm_close_proc _snd_pcm_close = snd_pcm_close;
18090  ma_snd_pcm_hw_params_sizeof_proc _snd_pcm_hw_params_sizeof = snd_pcm_hw_params_sizeof;
18091  ma_snd_pcm_hw_params_any_proc _snd_pcm_hw_params_any = snd_pcm_hw_params_any;
18092  ma_snd_pcm_hw_params_set_format_proc _snd_pcm_hw_params_set_format = snd_pcm_hw_params_set_format;
18093  ma_snd_pcm_hw_params_set_format_first_proc _snd_pcm_hw_params_set_format_first = snd_pcm_hw_params_set_format_first;
18094  ma_snd_pcm_hw_params_get_format_mask_proc _snd_pcm_hw_params_get_format_mask = snd_pcm_hw_params_get_format_mask;
18095  ma_snd_pcm_hw_params_set_channels_near_proc _snd_pcm_hw_params_set_channels_near = snd_pcm_hw_params_set_channels_near;
18096  ma_snd_pcm_hw_params_set_rate_resample_proc _snd_pcm_hw_params_set_rate_resample = snd_pcm_hw_params_set_rate_resample;
18097  ma_snd_pcm_hw_params_set_rate_near_proc _snd_pcm_hw_params_set_rate_near = snd_pcm_hw_params_set_rate_near;
18098  ma_snd_pcm_hw_params_set_buffer_size_near_proc _snd_pcm_hw_params_set_buffer_size_near = snd_pcm_hw_params_set_buffer_size_near;
18099  ma_snd_pcm_hw_params_set_periods_near_proc _snd_pcm_hw_params_set_periods_near = snd_pcm_hw_params_set_periods_near;
18100  ma_snd_pcm_hw_params_set_access_proc _snd_pcm_hw_params_set_access = snd_pcm_hw_params_set_access;
18101  ma_snd_pcm_hw_params_get_format_proc _snd_pcm_hw_params_get_format = snd_pcm_hw_params_get_format;
18102  ma_snd_pcm_hw_params_get_channels_proc _snd_pcm_hw_params_get_channels = snd_pcm_hw_params_get_channels;
18103  ma_snd_pcm_hw_params_get_channels_min_proc _snd_pcm_hw_params_get_channels_min = snd_pcm_hw_params_get_channels_min;
18104  ma_snd_pcm_hw_params_get_channels_max_proc _snd_pcm_hw_params_get_channels_max = snd_pcm_hw_params_get_channels_max;
18105  ma_snd_pcm_hw_params_get_rate_proc _snd_pcm_hw_params_get_rate = snd_pcm_hw_params_get_rate;
18106  ma_snd_pcm_hw_params_get_rate_min_proc _snd_pcm_hw_params_get_rate_min = snd_pcm_hw_params_get_rate_min;
18107  ma_snd_pcm_hw_params_get_rate_max_proc _snd_pcm_hw_params_get_rate_max = snd_pcm_hw_params_get_rate_max;
18108  ma_snd_pcm_hw_params_get_buffer_size_proc _snd_pcm_hw_params_get_buffer_size = snd_pcm_hw_params_get_buffer_size;
18109  ma_snd_pcm_hw_params_get_periods_proc _snd_pcm_hw_params_get_periods = snd_pcm_hw_params_get_periods;
18110  ma_snd_pcm_hw_params_get_access_proc _snd_pcm_hw_params_get_access = snd_pcm_hw_params_get_access;
18111  ma_snd_pcm_hw_params_proc _snd_pcm_hw_params = snd_pcm_hw_params;
18112  ma_snd_pcm_sw_params_sizeof_proc _snd_pcm_sw_params_sizeof = snd_pcm_sw_params_sizeof;
18113  ma_snd_pcm_sw_params_current_proc _snd_pcm_sw_params_current = snd_pcm_sw_params_current;
18114  ma_snd_pcm_sw_params_get_boundary_proc _snd_pcm_sw_params_get_boundary = snd_pcm_sw_params_get_boundary;
18115  ma_snd_pcm_sw_params_set_avail_min_proc _snd_pcm_sw_params_set_avail_min = snd_pcm_sw_params_set_avail_min;
18116  ma_snd_pcm_sw_params_set_start_threshold_proc _snd_pcm_sw_params_set_start_threshold = snd_pcm_sw_params_set_start_threshold;
18117  ma_snd_pcm_sw_params_set_stop_threshold_proc _snd_pcm_sw_params_set_stop_threshold = snd_pcm_sw_params_set_stop_threshold;
18118  ma_snd_pcm_sw_params_proc _snd_pcm_sw_params = snd_pcm_sw_params;
18119  ma_snd_pcm_format_mask_sizeof_proc _snd_pcm_format_mask_sizeof = snd_pcm_format_mask_sizeof;
18120  ma_snd_pcm_format_mask_test_proc _snd_pcm_format_mask_test = snd_pcm_format_mask_test;
18121  ma_snd_pcm_get_chmap_proc _snd_pcm_get_chmap = snd_pcm_get_chmap;
18122  ma_snd_pcm_state_proc _snd_pcm_state = snd_pcm_state;
18123  ma_snd_pcm_prepare_proc _snd_pcm_prepare = snd_pcm_prepare;
18124  ma_snd_pcm_start_proc _snd_pcm_start = snd_pcm_start;
18125  ma_snd_pcm_drop_proc _snd_pcm_drop = snd_pcm_drop;
18126  ma_snd_pcm_drain_proc _snd_pcm_drain = snd_pcm_drain;
18127  ma_snd_device_name_hint_proc _snd_device_name_hint = snd_device_name_hint;
18128  ma_snd_device_name_get_hint_proc _snd_device_name_get_hint = snd_device_name_get_hint;
18129  ma_snd_card_get_index_proc _snd_card_get_index = snd_card_get_index;
18130  ma_snd_device_name_free_hint_proc _snd_device_name_free_hint = snd_device_name_free_hint;
18131  ma_snd_pcm_mmap_begin_proc _snd_pcm_mmap_begin = snd_pcm_mmap_begin;
18132  ma_snd_pcm_mmap_commit_proc _snd_pcm_mmap_commit = snd_pcm_mmap_commit;
18133  ma_snd_pcm_recover_proc _snd_pcm_recover = snd_pcm_recover;
18134  ma_snd_pcm_readi_proc _snd_pcm_readi = snd_pcm_readi;
18135  ma_snd_pcm_writei_proc _snd_pcm_writei = snd_pcm_writei;
18136  ma_snd_pcm_avail_proc _snd_pcm_avail = snd_pcm_avail;
18137  ma_snd_pcm_avail_update_proc _snd_pcm_avail_update = snd_pcm_avail_update;
18138  ma_snd_pcm_wait_proc _snd_pcm_wait = snd_pcm_wait;
18139  ma_snd_pcm_info_proc _snd_pcm_info = snd_pcm_info;
18140  ma_snd_pcm_info_sizeof_proc _snd_pcm_info_sizeof = snd_pcm_info_sizeof;
18141  ma_snd_pcm_info_get_name_proc _snd_pcm_info_get_name = snd_pcm_info_get_name;
18142  ma_snd_config_update_free_global_proc _snd_config_update_free_global = snd_config_update_free_global;
18143 
18144  pContext->alsa.snd_pcm_open = (ma_proc)_snd_pcm_open;
18145  pContext->alsa.snd_pcm_close = (ma_proc)_snd_pcm_close;
18146  pContext->alsa.snd_pcm_hw_params_sizeof = (ma_proc)_snd_pcm_hw_params_sizeof;
18147  pContext->alsa.snd_pcm_hw_params_any = (ma_proc)_snd_pcm_hw_params_any;
18148  pContext->alsa.snd_pcm_hw_params_set_format = (ma_proc)_snd_pcm_hw_params_set_format;
18149  pContext->alsa.snd_pcm_hw_params_set_format_first = (ma_proc)_snd_pcm_hw_params_set_format_first;
18150  pContext->alsa.snd_pcm_hw_params_get_format_mask = (ma_proc)_snd_pcm_hw_params_get_format_mask;
18151  pContext->alsa.snd_pcm_hw_params_set_channels_near = (ma_proc)_snd_pcm_hw_params_set_channels_near;
18152  pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)_snd_pcm_hw_params_set_rate_resample;
18153  pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)_snd_pcm_hw_params_set_rate_near;
18154  pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)_snd_pcm_hw_params_set_buffer_size_near;
18155  pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)_snd_pcm_hw_params_set_periods_near;
18156  pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)_snd_pcm_hw_params_set_access;
18157  pContext->alsa.snd_pcm_hw_params_get_format = (ma_proc)_snd_pcm_hw_params_get_format;
18158  pContext->alsa.snd_pcm_hw_params_get_channels = (ma_proc)_snd_pcm_hw_params_get_channels;
18159  pContext->alsa.snd_pcm_hw_params_get_channels_min = (ma_proc)_snd_pcm_hw_params_get_channels_min;
18160  pContext->alsa.snd_pcm_hw_params_get_channels_max = (ma_proc)_snd_pcm_hw_params_get_channels_max;
18161  pContext->alsa.snd_pcm_hw_params_get_rate = (ma_proc)_snd_pcm_hw_params_get_rate;
18162  pContext->alsa.snd_pcm_hw_params_get_buffer_size = (ma_proc)_snd_pcm_hw_params_get_buffer_size;
18163  pContext->alsa.snd_pcm_hw_params_get_periods = (ma_proc)_snd_pcm_hw_params_get_periods;
18164  pContext->alsa.snd_pcm_hw_params_get_access = (ma_proc)_snd_pcm_hw_params_get_access;
18165  pContext->alsa.snd_pcm_hw_params = (ma_proc)_snd_pcm_hw_params;
18166  pContext->alsa.snd_pcm_sw_params_sizeof = (ma_proc)_snd_pcm_sw_params_sizeof;
18167  pContext->alsa.snd_pcm_sw_params_current = (ma_proc)_snd_pcm_sw_params_current;
18168  pContext->alsa.snd_pcm_sw_params_get_boundary = (ma_proc)_snd_pcm_sw_params_get_boundary;
18169  pContext->alsa.snd_pcm_sw_params_set_avail_min = (ma_proc)_snd_pcm_sw_params_set_avail_min;
18170  pContext->alsa.snd_pcm_sw_params_set_start_threshold = (ma_proc)_snd_pcm_sw_params_set_start_threshold;
18171  pContext->alsa.snd_pcm_sw_params_set_stop_threshold = (ma_proc)_snd_pcm_sw_params_set_stop_threshold;
18172  pContext->alsa.snd_pcm_sw_params = (ma_proc)_snd_pcm_sw_params;
18173  pContext->alsa.snd_pcm_format_mask_sizeof = (ma_proc)_snd_pcm_format_mask_sizeof;
18174  pContext->alsa.snd_pcm_format_mask_test = (ma_proc)_snd_pcm_format_mask_test;
18175  pContext->alsa.snd_pcm_get_chmap = (ma_proc)_snd_pcm_get_chmap;
18176  pContext->alsa.snd_pcm_state = (ma_proc)_snd_pcm_state;
18177  pContext->alsa.snd_pcm_prepare = (ma_proc)_snd_pcm_prepare;
18178  pContext->alsa.snd_pcm_start = (ma_proc)_snd_pcm_start;
18179  pContext->alsa.snd_pcm_drop = (ma_proc)_snd_pcm_drop;
18180  pContext->alsa.snd_pcm_drain = (ma_proc)_snd_pcm_drain;
18181  pContext->alsa.snd_device_name_hint = (ma_proc)_snd_device_name_hint;
18182  pContext->alsa.snd_device_name_get_hint = (ma_proc)_snd_device_name_get_hint;
18183  pContext->alsa.snd_card_get_index = (ma_proc)_snd_card_get_index;
18184  pContext->alsa.snd_device_name_free_hint = (ma_proc)_snd_device_name_free_hint;
18185  pContext->alsa.snd_pcm_mmap_begin = (ma_proc)_snd_pcm_mmap_begin;
18186  pContext->alsa.snd_pcm_mmap_commit = (ma_proc)_snd_pcm_mmap_commit;
18187  pContext->alsa.snd_pcm_recover = (ma_proc)_snd_pcm_recover;
18188  pContext->alsa.snd_pcm_readi = (ma_proc)_snd_pcm_readi;
18189  pContext->alsa.snd_pcm_writei = (ma_proc)_snd_pcm_writei;
18190  pContext->alsa.snd_pcm_avail = (ma_proc)_snd_pcm_avail;
18191  pContext->alsa.snd_pcm_avail_update = (ma_proc)_snd_pcm_avail_update;
18192  pContext->alsa.snd_pcm_wait = (ma_proc)_snd_pcm_wait;
18193  pContext->alsa.snd_pcm_info = (ma_proc)_snd_pcm_info;
18194  pContext->alsa.snd_pcm_info_sizeof = (ma_proc)_snd_pcm_info_sizeof;
18195  pContext->alsa.snd_pcm_info_get_name = (ma_proc)_snd_pcm_info_get_name;
18196  pContext->alsa.snd_config_update_free_global = (ma_proc)_snd_config_update_free_global;
18197 #endif
18198 
18199  pContext->alsa.useVerboseDeviceEnumeration = pConfig->alsa.useVerboseDeviceEnumeration;
18200 
18201  if (ma_mutex_init(pContext, &pContext->alsa.internalDeviceEnumLock) != MA_SUCCESS) {
18202  ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] WARNING: Failed to initialize mutex for internal device enumeration.", MA_ERROR);
18203  }
18204 
18205  pContext->onUninit = ma_context_uninit__alsa;
18206  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__alsa;
18207  pContext->onEnumDevices = ma_context_enumerate_devices__alsa;
18208  pContext->onGetDeviceInfo = ma_context_get_device_info__alsa;
18209  pContext->onDeviceInit = ma_device_init__alsa;
18210  pContext->onDeviceUninit = ma_device_uninit__alsa;
18211  pContext->onDeviceStart = NULL; /* Not used. Started in the main loop. */
18212  pContext->onDeviceStop = NULL; /* Not used. Started in the main loop. */
18213  pContext->onDeviceMainLoop = ma_device_main_loop__alsa;
18214 
18215  return MA_SUCCESS;
18216 }
18217 #endif /* ALSA */
18218 
18219 
18220 
18221 /******************************************************************************
18222 
18223 PulseAudio Backend
18224 
18225 ******************************************************************************/
18226 #ifdef MA_HAS_PULSEAUDIO
18227 /*
18228 It is assumed pulseaudio.h is available when compile-time linking is being used. We use this for type safety when using
18229 compile time linking (we don't have this luxury when using runtime linking without headers).
18230 
18231 When using compile time linking, each of our ma_* equivalents should use the sames types as defined by the header. The
18232 reason for this is that it allow us to take advantage of proper type safety.
18233 */
18234 #ifdef MA_NO_RUNTIME_LINKING
18235 #include <pulse/pulseaudio.h>
18236 
18237 #define MA_PA_OK PA_OK
18238 #define MA_PA_ERR_ACCESS PA_ERR_ACCESS
18239 #define MA_PA_ERR_INVALID PA_ERR_INVALID
18240 #define MA_PA_ERR_NOENTITY PA_ERR_NOENTITY
18241 
18242 #define MA_PA_CHANNELS_MAX PA_CHANNELS_MAX
18243 #define MA_PA_RATE_MAX PA_RATE_MAX
18244 
18245 typedef pa_context_flags_t ma_pa_context_flags_t;
18246 #define MA_PA_CONTEXT_NOFLAGS PA_CONTEXT_NOFLAGS
18247 #define MA_PA_CONTEXT_NOAUTOSPAWN PA_CONTEXT_NOAUTOSPAWN
18248 #define MA_PA_CONTEXT_NOFAIL PA_CONTEXT_NOFAIL
18249 
18250 typedef pa_stream_flags_t ma_pa_stream_flags_t;
18251 #define MA_PA_STREAM_NOFLAGS PA_STREAM_NOFLAGS
18252 #define MA_PA_STREAM_START_CORKED PA_STREAM_START_CORKED
18253 #define MA_PA_STREAM_INTERPOLATE_TIMING PA_STREAM_INTERPOLATE_TIMING
18254 #define MA_PA_STREAM_NOT_MONOTONIC PA_STREAM_NOT_MONOTONIC
18255 #define MA_PA_STREAM_AUTO_TIMING_UPDATE PA_STREAM_AUTO_TIMING_UPDATE
18256 #define MA_PA_STREAM_NO_REMAP_CHANNELS PA_STREAM_NO_REMAP_CHANNELS
18257 #define MA_PA_STREAM_NO_REMIX_CHANNELS PA_STREAM_NO_REMIX_CHANNELS
18258 #define MA_PA_STREAM_FIX_FORMAT PA_STREAM_FIX_FORMAT
18259 #define MA_PA_STREAM_FIX_RATE PA_STREAM_FIX_RATE
18260 #define MA_PA_STREAM_FIX_CHANNELS PA_STREAM_FIX_CHANNELS
18261 #define MA_PA_STREAM_DONT_MOVE PA_STREAM_DONT_MOVE
18262 #define MA_PA_STREAM_VARIABLE_RATE PA_STREAM_VARIABLE_RATE
18263 #define MA_PA_STREAM_PEAK_DETECT PA_STREAM_PEAK_DETECT
18264 #define MA_PA_STREAM_START_MUTED PA_STREAM_START_MUTED
18265 #define MA_PA_STREAM_ADJUST_LATENCY PA_STREAM_ADJUST_LATENCY
18266 #define MA_PA_STREAM_EARLY_REQUESTS PA_STREAM_EARLY_REQUESTS
18267 #define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND
18268 #define MA_PA_STREAM_START_UNMUTED PA_STREAM_START_UNMUTED
18269 #define MA_PA_STREAM_FAIL_ON_SUSPEND PA_STREAM_FAIL_ON_SUSPEND
18270 #define MA_PA_STREAM_RELATIVE_VOLUME PA_STREAM_RELATIVE_VOLUME
18271 #define MA_PA_STREAM_PASSTHROUGH PA_STREAM_PASSTHROUGH
18272 
18273 typedef pa_sink_flags_t ma_pa_sink_flags_t;
18274 #define MA_PA_SINK_NOFLAGS PA_SINK_NOFLAGS
18275 #define MA_PA_SINK_HW_VOLUME_CTRL PA_SINK_HW_VOLUME_CTRL
18276 #define MA_PA_SINK_LATENCY PA_SINK_LATENCY
18277 #define MA_PA_SINK_HARDWARE PA_SINK_HARDWARE
18278 #define MA_PA_SINK_NETWORK PA_SINK_NETWORK
18279 #define MA_PA_SINK_HW_MUTE_CTRL PA_SINK_HW_MUTE_CTRL
18280 #define MA_PA_SINK_DECIBEL_VOLUME PA_SINK_DECIBEL_VOLUME
18281 #define MA_PA_SINK_FLAT_VOLUME PA_SINK_FLAT_VOLUME
18282 #define MA_PA_SINK_DYNAMIC_LATENCY PA_SINK_DYNAMIC_LATENCY
18283 #define MA_PA_SINK_SET_FORMATS PA_SINK_SET_FORMATS
18284 
18285 typedef pa_source_flags_t ma_pa_source_flags_t;
18286 #define MA_PA_SOURCE_NOFLAGS PA_SOURCE_NOFLAGS
18287 #define MA_PA_SOURCE_HW_VOLUME_CTRL PA_SOURCE_HW_VOLUME_CTRL
18288 #define MA_PA_SOURCE_LATENCY PA_SOURCE_LATENCY
18289 #define MA_PA_SOURCE_HARDWARE PA_SOURCE_HARDWARE
18290 #define MA_PA_SOURCE_NETWORK PA_SOURCE_NETWORK
18291 #define MA_PA_SOURCE_HW_MUTE_CTRL PA_SOURCE_HW_MUTE_CTRL
18292 #define MA_PA_SOURCE_DECIBEL_VOLUME PA_SOURCE_DECIBEL_VOLUME
18293 #define MA_PA_SOURCE_DYNAMIC_LATENCY PA_SOURCE_DYNAMIC_LATENCY
18294 #define MA_PA_SOURCE_FLAT_VOLUME PA_SOURCE_FLAT_VOLUME
18295 
18296 typedef pa_context_state_t ma_pa_context_state_t;
18297 #define MA_PA_CONTEXT_UNCONNECTED PA_CONTEXT_UNCONNECTED
18298 #define MA_PA_CONTEXT_CONNECTING PA_CONTEXT_CONNECTING
18299 #define MA_PA_CONTEXT_AUTHORIZING PA_CONTEXT_AUTHORIZING
18300 #define MA_PA_CONTEXT_SETTING_NAME PA_CONTEXT_SETTING_NAME
18301 #define MA_PA_CONTEXT_READY PA_CONTEXT_READY
18302 #define MA_PA_CONTEXT_FAILED PA_CONTEXT_FAILED
18303 #define MA_PA_CONTEXT_TERMINATED PA_CONTEXT_TERMINATED
18304 
18305 typedef pa_stream_state_t ma_pa_stream_state_t;
18306 #define MA_PA_STREAM_UNCONNECTED PA_STREAM_UNCONNECTED
18307 #define MA_PA_STREAM_CREATING PA_STREAM_CREATING
18308 #define MA_PA_STREAM_READY PA_STREAM_READY
18309 #define MA_PA_STREAM_FAILED PA_STREAM_FAILED
18310 #define MA_PA_STREAM_TERMINATED PA_STREAM_TERMINATED
18311 
18312 typedef pa_operation_state_t ma_pa_operation_state_t;
18313 #define MA_PA_OPERATION_RUNNING PA_OPERATION_RUNNING
18314 #define MA_PA_OPERATION_DONE PA_OPERATION_DONE
18315 #define MA_PA_OPERATION_CANCELLED PA_OPERATION_CANCELLED
18316 
18317 typedef pa_sink_state_t ma_pa_sink_state_t;
18318 #define MA_PA_SINK_INVALID_STATE PA_SINK_INVALID_STATE
18319 #define MA_PA_SINK_RUNNING PA_SINK_RUNNING
18320 #define MA_PA_SINK_IDLE PA_SINK_IDLE
18321 #define MA_PA_SINK_SUSPENDED PA_SINK_SUSPENDED
18322 
18323 typedef pa_source_state_t ma_pa_source_state_t;
18324 #define MA_PA_SOURCE_INVALID_STATE PA_SOURCE_INVALID_STATE
18325 #define MA_PA_SOURCE_RUNNING PA_SOURCE_RUNNING
18326 #define MA_PA_SOURCE_IDLE PA_SOURCE_IDLE
18327 #define MA_PA_SOURCE_SUSPENDED PA_SOURCE_SUSPENDED
18328 
18329 typedef pa_seek_mode_t ma_pa_seek_mode_t;
18330 #define MA_PA_SEEK_RELATIVE PA_SEEK_RELATIVE
18331 #define MA_PA_SEEK_ABSOLUTE PA_SEEK_ABSOLUTE
18332 #define MA_PA_SEEK_RELATIVE_ON_READ PA_SEEK_RELATIVE_ON_READ
18333 #define MA_PA_SEEK_RELATIVE_END PA_SEEK_RELATIVE_END
18334 
18335 typedef pa_channel_position_t ma_pa_channel_position_t;
18336 #define MA_PA_CHANNEL_POSITION_INVALID PA_CHANNEL_POSITION_INVALID
18337 #define MA_PA_CHANNEL_POSITION_MONO PA_CHANNEL_POSITION_MONO
18338 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT PA_CHANNEL_POSITION_FRONT_LEFT
18339 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT PA_CHANNEL_POSITION_FRONT_RIGHT
18340 #define MA_PA_CHANNEL_POSITION_FRONT_CENTER PA_CHANNEL_POSITION_FRONT_CENTER
18341 #define MA_PA_CHANNEL_POSITION_REAR_CENTER PA_CHANNEL_POSITION_REAR_CENTER
18342 #define MA_PA_CHANNEL_POSITION_REAR_LEFT PA_CHANNEL_POSITION_REAR_LEFT
18343 #define MA_PA_CHANNEL_POSITION_REAR_RIGHT PA_CHANNEL_POSITION_REAR_RIGHT
18344 #define MA_PA_CHANNEL_POSITION_LFE PA_CHANNEL_POSITION_LFE
18345 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
18346 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
18347 #define MA_PA_CHANNEL_POSITION_SIDE_LEFT PA_CHANNEL_POSITION_SIDE_LEFT
18348 #define MA_PA_CHANNEL_POSITION_SIDE_RIGHT PA_CHANNEL_POSITION_SIDE_RIGHT
18349 #define MA_PA_CHANNEL_POSITION_AUX0 PA_CHANNEL_POSITION_AUX0
18350 #define MA_PA_CHANNEL_POSITION_AUX1 PA_CHANNEL_POSITION_AUX1
18351 #define MA_PA_CHANNEL_POSITION_AUX2 PA_CHANNEL_POSITION_AUX2
18352 #define MA_PA_CHANNEL_POSITION_AUX3 PA_CHANNEL_POSITION_AUX3
18353 #define MA_PA_CHANNEL_POSITION_AUX4 PA_CHANNEL_POSITION_AUX4
18354 #define MA_PA_CHANNEL_POSITION_AUX5 PA_CHANNEL_POSITION_AUX5
18355 #define MA_PA_CHANNEL_POSITION_AUX6 PA_CHANNEL_POSITION_AUX6
18356 #define MA_PA_CHANNEL_POSITION_AUX7 PA_CHANNEL_POSITION_AUX7
18357 #define MA_PA_CHANNEL_POSITION_AUX8 PA_CHANNEL_POSITION_AUX8
18358 #define MA_PA_CHANNEL_POSITION_AUX9 PA_CHANNEL_POSITION_AUX9
18359 #define MA_PA_CHANNEL_POSITION_AUX10 PA_CHANNEL_POSITION_AUX10
18360 #define MA_PA_CHANNEL_POSITION_AUX11 PA_CHANNEL_POSITION_AUX11
18361 #define MA_PA_CHANNEL_POSITION_AUX12 PA_CHANNEL_POSITION_AUX12
18362 #define MA_PA_CHANNEL_POSITION_AUX13 PA_CHANNEL_POSITION_AUX13
18363 #define MA_PA_CHANNEL_POSITION_AUX14 PA_CHANNEL_POSITION_AUX14
18364 #define MA_PA_CHANNEL_POSITION_AUX15 PA_CHANNEL_POSITION_AUX15
18365 #define MA_PA_CHANNEL_POSITION_AUX16 PA_CHANNEL_POSITION_AUX16
18366 #define MA_PA_CHANNEL_POSITION_AUX17 PA_CHANNEL_POSITION_AUX17
18367 #define MA_PA_CHANNEL_POSITION_AUX18 PA_CHANNEL_POSITION_AUX18
18368 #define MA_PA_CHANNEL_POSITION_AUX19 PA_CHANNEL_POSITION_AUX19
18369 #define MA_PA_CHANNEL_POSITION_AUX20 PA_CHANNEL_POSITION_AUX20
18370 #define MA_PA_CHANNEL_POSITION_AUX21 PA_CHANNEL_POSITION_AUX21
18371 #define MA_PA_CHANNEL_POSITION_AUX22 PA_CHANNEL_POSITION_AUX22
18372 #define MA_PA_CHANNEL_POSITION_AUX23 PA_CHANNEL_POSITION_AUX23
18373 #define MA_PA_CHANNEL_POSITION_AUX24 PA_CHANNEL_POSITION_AUX24
18374 #define MA_PA_CHANNEL_POSITION_AUX25 PA_CHANNEL_POSITION_AUX25
18375 #define MA_PA_CHANNEL_POSITION_AUX26 PA_CHANNEL_POSITION_AUX26
18376 #define MA_PA_CHANNEL_POSITION_AUX27 PA_CHANNEL_POSITION_AUX27
18377 #define MA_PA_CHANNEL_POSITION_AUX28 PA_CHANNEL_POSITION_AUX28
18378 #define MA_PA_CHANNEL_POSITION_AUX29 PA_CHANNEL_POSITION_AUX29
18379 #define MA_PA_CHANNEL_POSITION_AUX30 PA_CHANNEL_POSITION_AUX30
18380 #define MA_PA_CHANNEL_POSITION_AUX31 PA_CHANNEL_POSITION_AUX31
18381 #define MA_PA_CHANNEL_POSITION_TOP_CENTER PA_CHANNEL_POSITION_TOP_CENTER
18382 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT PA_CHANNEL_POSITION_TOP_FRONT_LEFT
18383 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
18384 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER PA_CHANNEL_POSITION_TOP_FRONT_CENTER
18385 #define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT PA_CHANNEL_POSITION_TOP_REAR_LEFT
18386 #define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT PA_CHANNEL_POSITION_TOP_REAR_RIGHT
18387 #define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER PA_CHANNEL_POSITION_TOP_REAR_CENTER
18388 #define MA_PA_CHANNEL_POSITION_LEFT PA_CHANNEL_POSITION_LEFT
18389 #define MA_PA_CHANNEL_POSITION_RIGHT PA_CHANNEL_POSITION_RIGHT
18390 #define MA_PA_CHANNEL_POSITION_CENTER PA_CHANNEL_POSITION_CENTER
18391 #define MA_PA_CHANNEL_POSITION_SUBWOOFER PA_CHANNEL_POSITION_SUBWOOFER
18392 
18393 typedef pa_channel_map_def_t ma_pa_channel_map_def_t;
18394 #define MA_PA_CHANNEL_MAP_AIFF PA_CHANNEL_MAP_AIFF
18395 #define MA_PA_CHANNEL_MAP_ALSA PA_CHANNEL_MAP_ALSA
18396 #define MA_PA_CHANNEL_MAP_AUX PA_CHANNEL_MAP_AUX
18397 #define MA_PA_CHANNEL_MAP_WAVEEX PA_CHANNEL_MAP_WAVEEX
18398 #define MA_PA_CHANNEL_MAP_OSS PA_CHANNEL_MAP_OSS
18399 #define MA_PA_CHANNEL_MAP_DEFAULT PA_CHANNEL_MAP_DEFAULT
18400 
18401 typedef pa_sample_format_t ma_pa_sample_format_t;
18402 #define MA_PA_SAMPLE_INVALID PA_SAMPLE_INVALID
18403 #define MA_PA_SAMPLE_U8 PA_SAMPLE_U8
18404 #define MA_PA_SAMPLE_ALAW PA_SAMPLE_ALAW
18405 #define MA_PA_SAMPLE_ULAW PA_SAMPLE_ULAW
18406 #define MA_PA_SAMPLE_S16LE PA_SAMPLE_S16LE
18407 #define MA_PA_SAMPLE_S16BE PA_SAMPLE_S16BE
18408 #define MA_PA_SAMPLE_FLOAT32LE PA_SAMPLE_FLOAT32LE
18409 #define MA_PA_SAMPLE_FLOAT32BE PA_SAMPLE_FLOAT32BE
18410 #define MA_PA_SAMPLE_S32LE PA_SAMPLE_S32LE
18411 #define MA_PA_SAMPLE_S32BE PA_SAMPLE_S32BE
18412 #define MA_PA_SAMPLE_S24LE PA_SAMPLE_S24LE
18413 #define MA_PA_SAMPLE_S24BE PA_SAMPLE_S24BE
18414 #define MA_PA_SAMPLE_S24_32LE PA_SAMPLE_S24_32LE
18415 #define MA_PA_SAMPLE_S24_32BE PA_SAMPLE_S24_32BE
18416 
18417 typedef pa_mainloop ma_pa_mainloop;
18418 typedef pa_mainloop_api ma_pa_mainloop_api;
18419 typedef pa_context ma_pa_context;
18420 typedef pa_operation ma_pa_operation;
18421 typedef pa_stream ma_pa_stream;
18422 typedef pa_spawn_api ma_pa_spawn_api;
18423 typedef pa_buffer_attr ma_pa_buffer_attr;
18424 typedef pa_channel_map ma_pa_channel_map;
18425 typedef pa_cvolume ma_pa_cvolume;
18426 typedef pa_sample_spec ma_pa_sample_spec;
18427 typedef pa_sink_info ma_pa_sink_info;
18428 typedef pa_source_info ma_pa_source_info;
18429 
18430 typedef pa_context_notify_cb_t ma_pa_context_notify_cb_t;
18431 typedef pa_sink_info_cb_t ma_pa_sink_info_cb_t;
18432 typedef pa_source_info_cb_t ma_pa_source_info_cb_t;
18433 typedef pa_stream_success_cb_t ma_pa_stream_success_cb_t;
18434 typedef pa_stream_request_cb_t ma_pa_stream_request_cb_t;
18435 typedef pa_free_cb_t ma_pa_free_cb_t;
18436 #else
18437 #define MA_PA_OK 0
18438 #define MA_PA_ERR_ACCESS 1
18439 #define MA_PA_ERR_INVALID 2
18440 #define MA_PA_ERR_NOENTITY 5
18441 
18442 #define MA_PA_CHANNELS_MAX 32
18443 #define MA_PA_RATE_MAX 384000
18444 
18445 typedef int ma_pa_context_flags_t;
18446 #define MA_PA_CONTEXT_NOFLAGS 0x00000000
18447 #define MA_PA_CONTEXT_NOAUTOSPAWN 0x00000001
18448 #define MA_PA_CONTEXT_NOFAIL 0x00000002
18449 
18450 typedef int ma_pa_stream_flags_t;
18451 #define MA_PA_STREAM_NOFLAGS 0x00000000
18452 #define MA_PA_STREAM_START_CORKED 0x00000001
18453 #define MA_PA_STREAM_INTERPOLATE_TIMING 0x00000002
18454 #define MA_PA_STREAM_NOT_MONOTONIC 0x00000004
18455 #define MA_PA_STREAM_AUTO_TIMING_UPDATE 0x00000008
18456 #define MA_PA_STREAM_NO_REMAP_CHANNELS 0x00000010
18457 #define MA_PA_STREAM_NO_REMIX_CHANNELS 0x00000020
18458 #define MA_PA_STREAM_FIX_FORMAT 0x00000040
18459 #define MA_PA_STREAM_FIX_RATE 0x00000080
18460 #define MA_PA_STREAM_FIX_CHANNELS 0x00000100
18461 #define MA_PA_STREAM_DONT_MOVE 0x00000200
18462 #define MA_PA_STREAM_VARIABLE_RATE 0x00000400
18463 #define MA_PA_STREAM_PEAK_DETECT 0x00000800
18464 #define MA_PA_STREAM_START_MUTED 0x00001000
18465 #define MA_PA_STREAM_ADJUST_LATENCY 0x00002000
18466 #define MA_PA_STREAM_EARLY_REQUESTS 0x00004000
18467 #define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND 0x00008000
18468 #define MA_PA_STREAM_START_UNMUTED 0x00010000
18469 #define MA_PA_STREAM_FAIL_ON_SUSPEND 0x00020000
18470 #define MA_PA_STREAM_RELATIVE_VOLUME 0x00040000
18471 #define MA_PA_STREAM_PASSTHROUGH 0x00080000
18472 
18473 typedef int ma_pa_sink_flags_t;
18474 #define MA_PA_SINK_NOFLAGS 0x00000000
18475 #define MA_PA_SINK_HW_VOLUME_CTRL 0x00000001
18476 #define MA_PA_SINK_LATENCY 0x00000002
18477 #define MA_PA_SINK_HARDWARE 0x00000004
18478 #define MA_PA_SINK_NETWORK 0x00000008
18479 #define MA_PA_SINK_HW_MUTE_CTRL 0x00000010
18480 #define MA_PA_SINK_DECIBEL_VOLUME 0x00000020
18481 #define MA_PA_SINK_FLAT_VOLUME 0x00000040
18482 #define MA_PA_SINK_DYNAMIC_LATENCY 0x00000080
18483 #define MA_PA_SINK_SET_FORMATS 0x00000100
18484 
18485 typedef int ma_pa_source_flags_t;
18486 #define MA_PA_SOURCE_NOFLAGS 0x00000000
18487 #define MA_PA_SOURCE_HW_VOLUME_CTRL 0x00000001
18488 #define MA_PA_SOURCE_LATENCY 0x00000002
18489 #define MA_PA_SOURCE_HARDWARE 0x00000004
18490 #define MA_PA_SOURCE_NETWORK 0x00000008
18491 #define MA_PA_SOURCE_HW_MUTE_CTRL 0x00000010
18492 #define MA_PA_SOURCE_DECIBEL_VOLUME 0x00000020
18493 #define MA_PA_SOURCE_DYNAMIC_LATENCY 0x00000040
18494 #define MA_PA_SOURCE_FLAT_VOLUME 0x00000080
18495 
18496 typedef int ma_pa_context_state_t;
18497 #define MA_PA_CONTEXT_UNCONNECTED 0
18498 #define MA_PA_CONTEXT_CONNECTING 1
18499 #define MA_PA_CONTEXT_AUTHORIZING 2
18500 #define MA_PA_CONTEXT_SETTING_NAME 3
18501 #define MA_PA_CONTEXT_READY 4
18502 #define MA_PA_CONTEXT_FAILED 5
18503 #define MA_PA_CONTEXT_TERMINATED 6
18504 
18505 typedef int ma_pa_stream_state_t;
18506 #define MA_PA_STREAM_UNCONNECTED 0
18507 #define MA_PA_STREAM_CREATING 1
18508 #define MA_PA_STREAM_READY 2
18509 #define MA_PA_STREAM_FAILED 3
18510 #define MA_PA_STREAM_TERMINATED 4
18511 
18512 typedef int ma_pa_operation_state_t;
18513 #define MA_PA_OPERATION_RUNNING 0
18514 #define MA_PA_OPERATION_DONE 1
18515 #define MA_PA_OPERATION_CANCELLED 2
18516 
18517 typedef int ma_pa_sink_state_t;
18518 #define MA_PA_SINK_INVALID_STATE -1
18519 #define MA_PA_SINK_RUNNING 0
18520 #define MA_PA_SINK_IDLE 1
18521 #define MA_PA_SINK_SUSPENDED 2
18522 
18523 typedef int ma_pa_source_state_t;
18524 #define MA_PA_SOURCE_INVALID_STATE -1
18525 #define MA_PA_SOURCE_RUNNING 0
18526 #define MA_PA_SOURCE_IDLE 1
18527 #define MA_PA_SOURCE_SUSPENDED 2
18528 
18529 typedef int ma_pa_seek_mode_t;
18530 #define MA_PA_SEEK_RELATIVE 0
18531 #define MA_PA_SEEK_ABSOLUTE 1
18532 #define MA_PA_SEEK_RELATIVE_ON_READ 2
18533 #define MA_PA_SEEK_RELATIVE_END 3
18534 
18535 typedef int ma_pa_channel_position_t;
18536 #define MA_PA_CHANNEL_POSITION_INVALID -1
18537 #define MA_PA_CHANNEL_POSITION_MONO 0
18538 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT 1
18539 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT 2
18540 #define MA_PA_CHANNEL_POSITION_FRONT_CENTER 3
18541 #define MA_PA_CHANNEL_POSITION_REAR_CENTER 4
18542 #define MA_PA_CHANNEL_POSITION_REAR_LEFT 5
18543 #define MA_PA_CHANNEL_POSITION_REAR_RIGHT 6
18544 #define MA_PA_CHANNEL_POSITION_LFE 7
18545 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER 8
18546 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER 9
18547 #define MA_PA_CHANNEL_POSITION_SIDE_LEFT 10
18548 #define MA_PA_CHANNEL_POSITION_SIDE_RIGHT 11
18549 #define MA_PA_CHANNEL_POSITION_AUX0 12
18550 #define MA_PA_CHANNEL_POSITION_AUX1 13
18551 #define MA_PA_CHANNEL_POSITION_AUX2 14
18552 #define MA_PA_CHANNEL_POSITION_AUX3 15
18553 #define MA_PA_CHANNEL_POSITION_AUX4 16
18554 #define MA_PA_CHANNEL_POSITION_AUX5 17
18555 #define MA_PA_CHANNEL_POSITION_AUX6 18
18556 #define MA_PA_CHANNEL_POSITION_AUX7 19
18557 #define MA_PA_CHANNEL_POSITION_AUX8 20
18558 #define MA_PA_CHANNEL_POSITION_AUX9 21
18559 #define MA_PA_CHANNEL_POSITION_AUX10 22
18560 #define MA_PA_CHANNEL_POSITION_AUX11 23
18561 #define MA_PA_CHANNEL_POSITION_AUX12 24
18562 #define MA_PA_CHANNEL_POSITION_AUX13 25
18563 #define MA_PA_CHANNEL_POSITION_AUX14 26
18564 #define MA_PA_CHANNEL_POSITION_AUX15 27
18565 #define MA_PA_CHANNEL_POSITION_AUX16 28
18566 #define MA_PA_CHANNEL_POSITION_AUX17 29
18567 #define MA_PA_CHANNEL_POSITION_AUX18 30
18568 #define MA_PA_CHANNEL_POSITION_AUX19 31
18569 #define MA_PA_CHANNEL_POSITION_AUX20 32
18570 #define MA_PA_CHANNEL_POSITION_AUX21 33
18571 #define MA_PA_CHANNEL_POSITION_AUX22 34
18572 #define MA_PA_CHANNEL_POSITION_AUX23 35
18573 #define MA_PA_CHANNEL_POSITION_AUX24 36
18574 #define MA_PA_CHANNEL_POSITION_AUX25 37
18575 #define MA_PA_CHANNEL_POSITION_AUX26 38
18576 #define MA_PA_CHANNEL_POSITION_AUX27 39
18577 #define MA_PA_CHANNEL_POSITION_AUX28 40
18578 #define MA_PA_CHANNEL_POSITION_AUX29 41
18579 #define MA_PA_CHANNEL_POSITION_AUX30 42
18580 #define MA_PA_CHANNEL_POSITION_AUX31 43
18581 #define MA_PA_CHANNEL_POSITION_TOP_CENTER 44
18582 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT 45
18583 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT 46
18584 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER 47
18585 #define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT 48
18586 #define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT 49
18587 #define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER 50
18588 #define MA_PA_CHANNEL_POSITION_LEFT MA_PA_CHANNEL_POSITION_FRONT_LEFT
18589 #define MA_PA_CHANNEL_POSITION_RIGHT MA_PA_CHANNEL_POSITION_FRONT_RIGHT
18590 #define MA_PA_CHANNEL_POSITION_CENTER MA_PA_CHANNEL_POSITION_FRONT_CENTER
18591 #define MA_PA_CHANNEL_POSITION_SUBWOOFER MA_PA_CHANNEL_POSITION_LFE
18592 
18593 typedef int ma_pa_channel_map_def_t;
18594 #define MA_PA_CHANNEL_MAP_AIFF 0
18595 #define MA_PA_CHANNEL_MAP_ALSA 1
18596 #define MA_PA_CHANNEL_MAP_AUX 2
18597 #define MA_PA_CHANNEL_MAP_WAVEEX 3
18598 #define MA_PA_CHANNEL_MAP_OSS 4
18599 #define MA_PA_CHANNEL_MAP_DEFAULT MA_PA_CHANNEL_MAP_AIFF
18600 
18601 typedef int ma_pa_sample_format_t;
18602 #define MA_PA_SAMPLE_INVALID -1
18603 #define MA_PA_SAMPLE_U8 0
18604 #define MA_PA_SAMPLE_ALAW 1
18605 #define MA_PA_SAMPLE_ULAW 2
18606 #define MA_PA_SAMPLE_S16LE 3
18607 #define MA_PA_SAMPLE_S16BE 4
18608 #define MA_PA_SAMPLE_FLOAT32LE 5
18609 #define MA_PA_SAMPLE_FLOAT32BE 6
18610 #define MA_PA_SAMPLE_S32LE 7
18611 #define MA_PA_SAMPLE_S32BE 8
18612 #define MA_PA_SAMPLE_S24LE 9
18613 #define MA_PA_SAMPLE_S24BE 10
18614 #define MA_PA_SAMPLE_S24_32LE 11
18615 #define MA_PA_SAMPLE_S24_32BE 12
18616 
18617 typedef struct ma_pa_mainloop ma_pa_mainloop;
18618 typedef struct ma_pa_mainloop_api ma_pa_mainloop_api;
18619 typedef struct ma_pa_context ma_pa_context;
18620 typedef struct ma_pa_operation ma_pa_operation;
18621 typedef struct ma_pa_stream ma_pa_stream;
18622 typedef struct ma_pa_spawn_api ma_pa_spawn_api;
18623 
18624 typedef struct
18625 {
18626  ma_uint32 maxlength;
18627  ma_uint32 tlength;
18628  ma_uint32 prebuf;
18629  ma_uint32 minreq;
18630  ma_uint32 fragsize;
18631 } ma_pa_buffer_attr;
18632 
18633 typedef struct
18634 {
18635  ma_uint8 channels;
18636  ma_pa_channel_position_t map[MA_PA_CHANNELS_MAX];
18637 } ma_pa_channel_map;
18638 
18639 typedef struct
18640 {
18641  ma_uint8 channels;
18642  ma_uint32 values[MA_PA_CHANNELS_MAX];
18643 } ma_pa_cvolume;
18644 
18645 typedef struct
18646 {
18647  ma_pa_sample_format_t format;
18648  ma_uint32 rate;
18649  ma_uint8 channels;
18650 } ma_pa_sample_spec;
18651 
18652 typedef struct
18653 {
18654  const char* name;
18655  ma_uint32 index;
18656  const char* description;
18657  ma_pa_sample_spec sample_spec;
18658  ma_pa_channel_map channel_map;
18659  ma_uint32 owner_module;
18660  ma_pa_cvolume volume;
18661  int mute;
18662  ma_uint32 monitor_source;
18663  const char* monitor_source_name;
18664  ma_uint64 latency;
18665  const char* driver;
18666  ma_pa_sink_flags_t flags;
18667  void* proplist;
18668  ma_uint64 configured_latency;
18669  ma_uint32 base_volume;
18670  ma_pa_sink_state_t state;
18671  ma_uint32 n_volume_steps;
18672  ma_uint32 card;
18673  ma_uint32 n_ports;
18674  void** ports;
18675  void* active_port;
18676  ma_uint8 n_formats;
18677  void** formats;
18678 } ma_pa_sink_info;
18679 
18680 typedef struct
18681 {
18682  const char *name;
18683  ma_uint32 index;
18684  const char *description;
18685  ma_pa_sample_spec sample_spec;
18686  ma_pa_channel_map channel_map;
18687  ma_uint32 owner_module;
18688  ma_pa_cvolume volume;
18689  int mute;
18690  ma_uint32 monitor_of_sink;
18691  const char *monitor_of_sink_name;
18692  ma_uint64 latency;
18693  const char *driver;
18694  ma_pa_source_flags_t flags;
18695  void* proplist;
18696  ma_uint64 configured_latency;
18697  ma_uint32 base_volume;
18698  ma_pa_source_state_t state;
18699  ma_uint32 n_volume_steps;
18700  ma_uint32 card;
18701  ma_uint32 n_ports;
18702  void** ports;
18703  void* active_port;
18704  ma_uint8 n_formats;
18705  void** formats;
18706 } ma_pa_source_info;
18707 
18708 typedef void (* ma_pa_context_notify_cb_t)(ma_pa_context* c, void* userdata);
18709 typedef void (* ma_pa_sink_info_cb_t) (ma_pa_context* c, const ma_pa_sink_info* i, int eol, void* userdata);
18710 typedef void (* ma_pa_source_info_cb_t) (ma_pa_context* c, const ma_pa_source_info* i, int eol, void* userdata);
18711 typedef void (* ma_pa_stream_success_cb_t)(ma_pa_stream* s, int success, void* userdata);
18712 typedef void (* ma_pa_stream_request_cb_t)(ma_pa_stream* s, size_t nbytes, void* userdata);
18713 typedef void (* ma_pa_free_cb_t) (void* p);
18714 #endif
18715 
18716 
18717 typedef ma_pa_mainloop* (* ma_pa_mainloop_new_proc) ();
18718 typedef void (* ma_pa_mainloop_free_proc) (ma_pa_mainloop* m);
18719 typedef ma_pa_mainloop_api* (* ma_pa_mainloop_get_api_proc) (ma_pa_mainloop* m);
18720 typedef int (* ma_pa_mainloop_iterate_proc) (ma_pa_mainloop* m, int block, int* retval);
18721 typedef void (* ma_pa_mainloop_wakeup_proc) (ma_pa_mainloop* m);
18722 typedef ma_pa_context* (* ma_pa_context_new_proc) (ma_pa_mainloop_api* mainloop, const char* name);
18723 typedef void (* ma_pa_context_unref_proc) (ma_pa_context* c);
18724 typedef int (* ma_pa_context_connect_proc) (ma_pa_context* c, const char* server, ma_pa_context_flags_t flags, const ma_pa_spawn_api* api);
18725 typedef void (* ma_pa_context_disconnect_proc) (ma_pa_context* c);
18726 typedef void (* ma_pa_context_set_state_callback_proc) (ma_pa_context* c, ma_pa_context_notify_cb_t cb, void* userdata);
18727 typedef ma_pa_context_state_t (* ma_pa_context_get_state_proc) (ma_pa_context* c);
18728 typedef ma_pa_operation* (* ma_pa_context_get_sink_info_list_proc) (ma_pa_context* c, ma_pa_sink_info_cb_t cb, void* userdata);
18729 typedef ma_pa_operation* (* ma_pa_context_get_source_info_list_proc) (ma_pa_context* c, ma_pa_source_info_cb_t cb, void* userdata);
18730 typedef ma_pa_operation* (* ma_pa_context_get_sink_info_by_name_proc) (ma_pa_context* c, const char* name, ma_pa_sink_info_cb_t cb, void* userdata);
18731 typedef ma_pa_operation* (* ma_pa_context_get_source_info_by_name_proc)(ma_pa_context* c, const char* name, ma_pa_source_info_cb_t cb, void* userdata);
18732 typedef void (* ma_pa_operation_unref_proc) (ma_pa_operation* o);
18733 typedef ma_pa_operation_state_t (* ma_pa_operation_get_state_proc) (ma_pa_operation* o);
18734 typedef ma_pa_channel_map* (* ma_pa_channel_map_init_extend_proc) (ma_pa_channel_map* m, unsigned channels, ma_pa_channel_map_def_t def);
18735 typedef int (* ma_pa_channel_map_valid_proc) (const ma_pa_channel_map* m);
18736 typedef int (* ma_pa_channel_map_compatible_proc) (const ma_pa_channel_map* m, const ma_pa_sample_spec* ss);
18737 typedef ma_pa_stream* (* ma_pa_stream_new_proc) (ma_pa_context* c, const char* name, const ma_pa_sample_spec* ss, const ma_pa_channel_map* map);
18738 typedef void (* ma_pa_stream_unref_proc) (ma_pa_stream* s);
18739 typedef int (* ma_pa_stream_connect_playback_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags, const ma_pa_cvolume* volume, ma_pa_stream* sync_stream);
18740 typedef int (* ma_pa_stream_connect_record_proc) (ma_pa_stream* s, const char* dev, const ma_pa_buffer_attr* attr, ma_pa_stream_flags_t flags);
18741 typedef int (* ma_pa_stream_disconnect_proc) (ma_pa_stream* s);
18742 typedef ma_pa_stream_state_t (* ma_pa_stream_get_state_proc) (ma_pa_stream* s);
18743 typedef const ma_pa_sample_spec* (* ma_pa_stream_get_sample_spec_proc) (ma_pa_stream* s);
18744 typedef const ma_pa_channel_map* (* ma_pa_stream_get_channel_map_proc) (ma_pa_stream* s);
18745 typedef const ma_pa_buffer_attr* (* ma_pa_stream_get_buffer_attr_proc) (ma_pa_stream* s);
18746 typedef ma_pa_operation* (* ma_pa_stream_set_buffer_attr_proc) (ma_pa_stream* s, const ma_pa_buffer_attr* attr, ma_pa_stream_success_cb_t cb, void* userdata);
18747 typedef const char* (* ma_pa_stream_get_device_name_proc) (ma_pa_stream* s);
18748 typedef void (* ma_pa_stream_set_write_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata);
18749 typedef void (* ma_pa_stream_set_read_callback_proc) (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata);
18750 typedef ma_pa_operation* (* ma_pa_stream_flush_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata);
18751 typedef ma_pa_operation* (* ma_pa_stream_drain_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata);
18752 typedef int (* ma_pa_stream_is_corked_proc) (ma_pa_stream* s);
18753 typedef ma_pa_operation* (* ma_pa_stream_cork_proc) (ma_pa_stream* s, int b, ma_pa_stream_success_cb_t cb, void* userdata);
18754 typedef ma_pa_operation* (* ma_pa_stream_trigger_proc) (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata);
18755 typedef int (* ma_pa_stream_begin_write_proc) (ma_pa_stream* s, void** data, size_t* nbytes);
18756 typedef int (* ma_pa_stream_write_proc) (ma_pa_stream* s, const void* data, size_t nbytes, ma_pa_free_cb_t free_cb, int64_t offset, ma_pa_seek_mode_t seek);
18757 typedef int (* ma_pa_stream_peek_proc) (ma_pa_stream* s, const void** data, size_t* nbytes);
18758 typedef int (* ma_pa_stream_drop_proc) (ma_pa_stream* s);
18759 typedef size_t (* ma_pa_stream_writable_size_proc) (ma_pa_stream* s);
18760 typedef size_t (* ma_pa_stream_readable_size_proc) (ma_pa_stream* s);
18761 
18762 typedef struct
18763 {
18764  ma_uint32 count;
18765  ma_uint32 capacity;
18766  ma_device_info* pInfo;
18767 } ma_pulse_device_enum_data;
18768 
18769 static ma_result ma_result_from_pulse(int result)
18770 {
18771  switch (result) {
18772  case MA_PA_OK: return MA_SUCCESS;
18773  case MA_PA_ERR_ACCESS: return MA_ACCESS_DENIED;
18774  case MA_PA_ERR_INVALID: return MA_INVALID_ARGS;
18775  case MA_PA_ERR_NOENTITY: return MA_NO_DEVICE;
18776  default: return MA_ERROR;
18777  }
18778 }
18779 
18780 #if 0
18781 static ma_pa_sample_format_t ma_format_to_pulse(ma_format format)
18782 {
18783  if (ma_is_little_endian()) {
18784  switch (format) {
18785  case ma_format_s16: return MA_PA_SAMPLE_S16LE;
18786  case ma_format_s24: return MA_PA_SAMPLE_S24LE;
18787  case ma_format_s32: return MA_PA_SAMPLE_S32LE;
18788  case ma_format_f32: return MA_PA_SAMPLE_FLOAT32LE;
18789  default: break;
18790  }
18791  } else {
18792  switch (format) {
18793  case ma_format_s16: return MA_PA_SAMPLE_S16BE;
18794  case ma_format_s24: return MA_PA_SAMPLE_S24BE;
18795  case ma_format_s32: return MA_PA_SAMPLE_S32BE;
18796  case ma_format_f32: return MA_PA_SAMPLE_FLOAT32BE;
18797  default: break;
18798  }
18799  }
18800 
18801  /* Endian agnostic. */
18802  switch (format) {
18803  case ma_format_u8: return MA_PA_SAMPLE_U8;
18804  default: return MA_PA_SAMPLE_INVALID;
18805  }
18806 }
18807 #endif
18808 
18809 static ma_format ma_format_from_pulse(ma_pa_sample_format_t format)
18810 {
18811  if (ma_is_little_endian()) {
18812  switch (format) {
18813  case MA_PA_SAMPLE_S16LE: return ma_format_s16;
18814  case MA_PA_SAMPLE_S24LE: return ma_format_s24;
18815  case MA_PA_SAMPLE_S32LE: return ma_format_s32;
18816  case MA_PA_SAMPLE_FLOAT32LE: return ma_format_f32;
18817  default: break;
18818  }
18819  } else {
18820  switch (format) {
18821  case MA_PA_SAMPLE_S16BE: return ma_format_s16;
18822  case MA_PA_SAMPLE_S24BE: return ma_format_s24;
18823  case MA_PA_SAMPLE_S32BE: return ma_format_s32;
18824  case MA_PA_SAMPLE_FLOAT32BE: return ma_format_f32;
18825  default: break;
18826  }
18827  }
18828 
18829  /* Endian agnostic. */
18830  switch (format) {
18831  case MA_PA_SAMPLE_U8: return ma_format_u8;
18832  default: return ma_format_unknown;
18833  }
18834 }
18835 
18836 static ma_channel ma_channel_position_from_pulse(ma_pa_channel_position_t position)
18837 {
18838  switch (position)
18839  {
18840  case MA_PA_CHANNEL_POSITION_INVALID: return MA_CHANNEL_NONE;
18841  case MA_PA_CHANNEL_POSITION_MONO: return MA_CHANNEL_MONO;
18842  case MA_PA_CHANNEL_POSITION_FRONT_LEFT: return MA_CHANNEL_FRONT_LEFT;
18843  case MA_PA_CHANNEL_POSITION_FRONT_RIGHT: return MA_CHANNEL_FRONT_RIGHT;
18844  case MA_PA_CHANNEL_POSITION_FRONT_CENTER: return MA_CHANNEL_FRONT_CENTER;
18845  case MA_PA_CHANNEL_POSITION_REAR_CENTER: return MA_CHANNEL_BACK_CENTER;
18846  case MA_PA_CHANNEL_POSITION_REAR_LEFT: return MA_CHANNEL_BACK_LEFT;
18847  case MA_PA_CHANNEL_POSITION_REAR_RIGHT: return MA_CHANNEL_BACK_RIGHT;
18848  case MA_PA_CHANNEL_POSITION_LFE: return MA_CHANNEL_LFE;
18849  case MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: return MA_CHANNEL_FRONT_LEFT_CENTER;
18850  case MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER;
18851  case MA_PA_CHANNEL_POSITION_SIDE_LEFT: return MA_CHANNEL_SIDE_LEFT;
18852  case MA_PA_CHANNEL_POSITION_SIDE_RIGHT: return MA_CHANNEL_SIDE_RIGHT;
18853  case MA_PA_CHANNEL_POSITION_AUX0: return MA_CHANNEL_AUX_0;
18854  case MA_PA_CHANNEL_POSITION_AUX1: return MA_CHANNEL_AUX_1;
18855  case MA_PA_CHANNEL_POSITION_AUX2: return MA_CHANNEL_AUX_2;
18856  case MA_PA_CHANNEL_POSITION_AUX3: return MA_CHANNEL_AUX_3;
18857  case MA_PA_CHANNEL_POSITION_AUX4: return MA_CHANNEL_AUX_4;
18858  case MA_PA_CHANNEL_POSITION_AUX5: return MA_CHANNEL_AUX_5;
18859  case MA_PA_CHANNEL_POSITION_AUX6: return MA_CHANNEL_AUX_6;
18860  case MA_PA_CHANNEL_POSITION_AUX7: return MA_CHANNEL_AUX_7;
18861  case MA_PA_CHANNEL_POSITION_AUX8: return MA_CHANNEL_AUX_8;
18862  case MA_PA_CHANNEL_POSITION_AUX9: return MA_CHANNEL_AUX_9;
18863  case MA_PA_CHANNEL_POSITION_AUX10: return MA_CHANNEL_AUX_10;
18864  case MA_PA_CHANNEL_POSITION_AUX11: return MA_CHANNEL_AUX_11;
18865  case MA_PA_CHANNEL_POSITION_AUX12: return MA_CHANNEL_AUX_12;
18866  case MA_PA_CHANNEL_POSITION_AUX13: return MA_CHANNEL_AUX_13;
18867  case MA_PA_CHANNEL_POSITION_AUX14: return MA_CHANNEL_AUX_14;
18868  case MA_PA_CHANNEL_POSITION_AUX15: return MA_CHANNEL_AUX_15;
18869  case MA_PA_CHANNEL_POSITION_AUX16: return MA_CHANNEL_AUX_16;
18870  case MA_PA_CHANNEL_POSITION_AUX17: return MA_CHANNEL_AUX_17;
18871  case MA_PA_CHANNEL_POSITION_AUX18: return MA_CHANNEL_AUX_18;
18872  case MA_PA_CHANNEL_POSITION_AUX19: return MA_CHANNEL_AUX_19;
18873  case MA_PA_CHANNEL_POSITION_AUX20: return MA_CHANNEL_AUX_20;
18874  case MA_PA_CHANNEL_POSITION_AUX21: return MA_CHANNEL_AUX_21;
18875  case MA_PA_CHANNEL_POSITION_AUX22: return MA_CHANNEL_AUX_22;
18876  case MA_PA_CHANNEL_POSITION_AUX23: return MA_CHANNEL_AUX_23;
18877  case MA_PA_CHANNEL_POSITION_AUX24: return MA_CHANNEL_AUX_24;
18878  case MA_PA_CHANNEL_POSITION_AUX25: return MA_CHANNEL_AUX_25;
18879  case MA_PA_CHANNEL_POSITION_AUX26: return MA_CHANNEL_AUX_26;
18880  case MA_PA_CHANNEL_POSITION_AUX27: return MA_CHANNEL_AUX_27;
18881  case MA_PA_CHANNEL_POSITION_AUX28: return MA_CHANNEL_AUX_28;
18882  case MA_PA_CHANNEL_POSITION_AUX29: return MA_CHANNEL_AUX_29;
18883  case MA_PA_CHANNEL_POSITION_AUX30: return MA_CHANNEL_AUX_30;
18884  case MA_PA_CHANNEL_POSITION_AUX31: return MA_CHANNEL_AUX_31;
18885  case MA_PA_CHANNEL_POSITION_TOP_CENTER: return MA_CHANNEL_TOP_CENTER;
18886  case MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT: return MA_CHANNEL_TOP_FRONT_LEFT;
18887  case MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: return MA_CHANNEL_TOP_FRONT_RIGHT;
18888  case MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER: return MA_CHANNEL_TOP_FRONT_CENTER;
18889  case MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT: return MA_CHANNEL_TOP_BACK_LEFT;
18890  case MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT: return MA_CHANNEL_TOP_BACK_RIGHT;
18891  case MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER: return MA_CHANNEL_TOP_BACK_CENTER;
18892  default: return MA_CHANNEL_NONE;
18893  }
18894 }
18895 
18896 #if 0
18897 static ma_pa_channel_position_t ma_channel_position_to_pulse(ma_channel position)
18898 {
18899  switch (position)
18900  {
18901  case MA_CHANNEL_NONE: return MA_PA_CHANNEL_POSITION_INVALID;
18902  case MA_CHANNEL_FRONT_LEFT: return MA_PA_CHANNEL_POSITION_FRONT_LEFT;
18903  case MA_CHANNEL_FRONT_RIGHT: return MA_PA_CHANNEL_POSITION_FRONT_RIGHT;
18904  case MA_CHANNEL_FRONT_CENTER: return MA_PA_CHANNEL_POSITION_FRONT_CENTER;
18905  case MA_CHANNEL_LFE: return MA_PA_CHANNEL_POSITION_LFE;
18906  case MA_CHANNEL_BACK_LEFT: return MA_PA_CHANNEL_POSITION_REAR_LEFT;
18907  case MA_CHANNEL_BACK_RIGHT: return MA_PA_CHANNEL_POSITION_REAR_RIGHT;
18908  case MA_CHANNEL_FRONT_LEFT_CENTER: return MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
18909  case MA_CHANNEL_FRONT_RIGHT_CENTER: return MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
18910  case MA_CHANNEL_BACK_CENTER: return MA_PA_CHANNEL_POSITION_REAR_CENTER;
18911  case MA_CHANNEL_SIDE_LEFT: return MA_PA_CHANNEL_POSITION_SIDE_LEFT;
18912  case MA_CHANNEL_SIDE_RIGHT: return MA_PA_CHANNEL_POSITION_SIDE_RIGHT;
18913  case MA_CHANNEL_TOP_CENTER: return MA_PA_CHANNEL_POSITION_TOP_CENTER;
18914  case MA_CHANNEL_TOP_FRONT_LEFT: return MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
18915  case MA_CHANNEL_TOP_FRONT_CENTER: return MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
18916  case MA_CHANNEL_TOP_FRONT_RIGHT: return MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
18917  case MA_CHANNEL_TOP_BACK_LEFT: return MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT;
18918  case MA_CHANNEL_TOP_BACK_CENTER: return MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER;
18919  case MA_CHANNEL_TOP_BACK_RIGHT: return MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
18920  case MA_CHANNEL_19: return MA_PA_CHANNEL_POSITION_AUX18;
18921  case MA_CHANNEL_20: return MA_PA_CHANNEL_POSITION_AUX19;
18922  case MA_CHANNEL_21: return MA_PA_CHANNEL_POSITION_AUX20;
18923  case MA_CHANNEL_22: return MA_PA_CHANNEL_POSITION_AUX21;
18924  case MA_CHANNEL_23: return MA_PA_CHANNEL_POSITION_AUX22;
18925  case MA_CHANNEL_24: return MA_PA_CHANNEL_POSITION_AUX23;
18926  case MA_CHANNEL_25: return MA_PA_CHANNEL_POSITION_AUX24;
18927  case MA_CHANNEL_26: return MA_PA_CHANNEL_POSITION_AUX25;
18928  case MA_CHANNEL_27: return MA_PA_CHANNEL_POSITION_AUX26;
18929  case MA_CHANNEL_28: return MA_PA_CHANNEL_POSITION_AUX27;
18930  case MA_CHANNEL_29: return MA_PA_CHANNEL_POSITION_AUX28;
18931  case MA_CHANNEL_30: return MA_PA_CHANNEL_POSITION_AUX29;
18932  case MA_CHANNEL_31: return MA_PA_CHANNEL_POSITION_AUX30;
18933  case MA_CHANNEL_32: return MA_PA_CHANNEL_POSITION_AUX31;
18934  default: return (ma_pa_channel_position_t)position;
18935  }
18936 }
18937 #endif
18938 
18939 static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_pa_mainloop* pMainLoop, ma_pa_operation* pOP)
18940 {
18941  MA_ASSERT(pContext != NULL);
18942  MA_ASSERT(pMainLoop != NULL);
18943  MA_ASSERT(pOP != NULL);
18944 
18945  while (((ma_pa_operation_get_state_proc)pContext->pulse.pa_operation_get_state)(pOP) == MA_PA_OPERATION_RUNNING) {
18946  int error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)(pMainLoop, 1, NULL);
18947  if (error < 0) {
18948  return ma_result_from_pulse(error);
18949  }
18950  }
18951 
18952  return MA_SUCCESS;
18953 }
18954 
18955 static ma_result ma_device__wait_for_operation__pulse(ma_device* pDevice, ma_pa_operation* pOP)
18956 {
18957  MA_ASSERT(pDevice != NULL);
18958  MA_ASSERT(pOP != NULL);
18959 
18960  return ma_wait_for_operation__pulse(pDevice->pContext, (ma_pa_mainloop*)pDevice->pulse.pMainLoop, pOP);
18961 }
18962 
18963 
18964 static ma_bool32 ma_context_is_device_id_equal__pulse(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
18965 {
18966  MA_ASSERT(pContext != NULL);
18967  MA_ASSERT(pID0 != NULL);
18968  MA_ASSERT(pID1 != NULL);
18969  (void)pContext;
18970 
18971  return ma_strcmp(pID0->pulse, pID1->pulse) == 0;
18972 }
18973 
18974 
18975 typedef struct
18976 {
18977  ma_context* pContext;
18979  void* pUserData;
18980  ma_bool32 isTerminated;
18981 } ma_context_enumerate_devices_callback_data__pulse;
18982 
18983 static void ma_context_enumerate_devices_sink_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_sink_info* pSinkInfo, int endOfList, void* pUserData)
18984 {
18985  ma_context_enumerate_devices_callback_data__pulse* pData = (ma_context_enumerate_devices_callback_data__pulse*)pUserData;
18986  ma_device_info deviceInfo;
18987 
18988  MA_ASSERT(pData != NULL);
18989 
18990  if (endOfList || pData->isTerminated) {
18991  return;
18992  }
18993 
18994  MA_ZERO_OBJECT(&deviceInfo);
18995 
18996  /* The name from PulseAudio is the ID for miniaudio. */
18997  if (pSinkInfo->name != NULL) {
18998  ma_strncpy_s(deviceInfo.id.pulse, sizeof(deviceInfo.id.pulse), pSinkInfo->name, (size_t)-1);
18999  }
19000 
19001  /* The description from PulseAudio is the name for miniaudio. */
19002  if (pSinkInfo->description != NULL) {
19003  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), pSinkInfo->description, (size_t)-1);
19004  }
19005 
19006  pData->isTerminated = !pData->callback(pData->pContext, ma_device_type_playback, &deviceInfo, pData->pUserData);
19007 
19008  (void)pPulseContext; /* Unused. */
19009 }
19010 
19011 static void ma_context_enumerate_devices_source_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_source_info* pSinkInfo, int endOfList, void* pUserData)
19012 {
19013  ma_context_enumerate_devices_callback_data__pulse* pData = (ma_context_enumerate_devices_callback_data__pulse*)pUserData;
19014  ma_device_info deviceInfo;
19015 
19016  MA_ASSERT(pData != NULL);
19017 
19018  if (endOfList || pData->isTerminated) {
19019  return;
19020  }
19021 
19022  MA_ZERO_OBJECT(&deviceInfo);
19023 
19024  /* The name from PulseAudio is the ID for miniaudio. */
19025  if (pSinkInfo->name != NULL) {
19026  ma_strncpy_s(deviceInfo.id.pulse, sizeof(deviceInfo.id.pulse), pSinkInfo->name, (size_t)-1);
19027  }
19028 
19029  /* The description from PulseAudio is the name for miniaudio. */
19030  if (pSinkInfo->description != NULL) {
19031  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), pSinkInfo->description, (size_t)-1);
19032  }
19033 
19034  pData->isTerminated = !pData->callback(pData->pContext, ma_device_type_capture, &deviceInfo, pData->pUserData);
19035 
19036  (void)pPulseContext; /* Unused. */
19037 }
19038 
19039 static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
19040 {
19041  ma_result result = MA_SUCCESS;
19042  ma_context_enumerate_devices_callback_data__pulse callbackData;
19043  ma_pa_operation* pOP = NULL;
19044  ma_pa_mainloop* pMainLoop;
19045  ma_pa_mainloop_api* pAPI;
19046  ma_pa_context* pPulseContext;
19047  int error;
19048 
19049  MA_ASSERT(pContext != NULL);
19050  MA_ASSERT(callback != NULL);
19051 
19052  callbackData.pContext = pContext;
19053  callbackData.callback = callback;
19054  callbackData.pUserData = pUserData;
19055  callbackData.isTerminated = MA_FALSE;
19056 
19057  pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)();
19058  if (pMainLoop == NULL) {
19060  }
19061 
19062  pAPI = ((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)(pMainLoop);
19063  if (pAPI == NULL) {
19064  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
19066  }
19067 
19068  pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->pulse.pApplicationName);
19069  if (pPulseContext == NULL) {
19070  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
19072  }
19073 
19074  error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->pulse.pServerName, (pContext->pulse.tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL);
19075  if (error != MA_PA_OK) {
19076  ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext);
19077  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
19078  return ma_result_from_pulse(error);
19079  }
19080 
19081  for (;;) {
19082  ma_pa_context_state_t state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)(pPulseContext);
19083  if (state == MA_PA_CONTEXT_READY) {
19084  break; /* Success. */
19085  }
19086  if (state == MA_PA_CONTEXT_CONNECTING || state == MA_PA_CONTEXT_AUTHORIZING || state == MA_PA_CONTEXT_SETTING_NAME) {
19087  error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)(pMainLoop, 1, NULL);
19088  if (error < 0) {
19089  result = ma_result_from_pulse(error);
19090  goto done;
19091  }
19092 
19093 #ifdef MA_DEBUG_OUTPUT
19094  printf("[PulseAudio] pa_context_get_state() returned %d. Waiting.\n", state);
19095 #endif
19096  continue; /* Keep trying. */
19097  }
19098  if (state == MA_PA_CONTEXT_UNCONNECTED || state == MA_PA_CONTEXT_FAILED || state == MA_PA_CONTEXT_TERMINATED) {
19099 #ifdef MA_DEBUG_OUTPUT
19100  printf("[PulseAudio] pa_context_get_state() returned %d. Failed.\n", state);
19101 #endif
19102  goto done; /* Failed. */
19103  }
19104  }
19105 
19106 
19107  /* Playback. */
19108  if (!callbackData.isTerminated) {
19109  pOP = ((ma_pa_context_get_sink_info_list_proc)pContext->pulse.pa_context_get_sink_info_list)(pPulseContext, ma_context_enumerate_devices_sink_callback__pulse, &callbackData);
19110  if (pOP == NULL) {
19111  result = MA_ERROR;
19112  goto done;
19113  }
19114 
19115  result = ma_wait_for_operation__pulse(pContext, pMainLoop, pOP);
19116  ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
19117  if (result != MA_SUCCESS) {
19118  goto done;
19119  }
19120  }
19121 
19122 
19123  /* Capture. */
19124  if (!callbackData.isTerminated) {
19125  pOP = ((ma_pa_context_get_source_info_list_proc)pContext->pulse.pa_context_get_source_info_list)(pPulseContext, ma_context_enumerate_devices_source_callback__pulse, &callbackData);
19126  if (pOP == NULL) {
19127  result = MA_ERROR;
19128  goto done;
19129  }
19130 
19131  result = ma_wait_for_operation__pulse(pContext, pMainLoop, pOP);
19132  ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
19133  if (result != MA_SUCCESS) {
19134  goto done;
19135  }
19136  }
19137 
19138 done:
19139  ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)(pPulseContext);
19140  ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext);
19141  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
19142  return result;
19143 }
19144 
19145 
19146 typedef struct
19147 {
19148  ma_device_info* pDeviceInfo;
19149  ma_bool32 foundDevice;
19150 } ma_context_get_device_info_callback_data__pulse;
19151 
19152 static void ma_context_get_device_info_sink_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData)
19153 {
19154  ma_context_get_device_info_callback_data__pulse* pData = (ma_context_get_device_info_callback_data__pulse*)pUserData;
19155 
19156  if (endOfList > 0) {
19157  return;
19158  }
19159 
19160  MA_ASSERT(pData != NULL);
19161  pData->foundDevice = MA_TRUE;
19162 
19163  if (pInfo->name != NULL) {
19164  ma_strncpy_s(pData->pDeviceInfo->id.pulse, sizeof(pData->pDeviceInfo->id.pulse), pInfo->name, (size_t)-1);
19165  }
19166 
19167  if (pInfo->description != NULL) {
19168  ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pInfo->description, (size_t)-1);
19169  }
19170 
19171  pData->pDeviceInfo->minChannels = pInfo->sample_spec.channels;
19172  pData->pDeviceInfo->maxChannels = pInfo->sample_spec.channels;
19173  pData->pDeviceInfo->minSampleRate = pInfo->sample_spec.rate;
19174  pData->pDeviceInfo->maxSampleRate = pInfo->sample_spec.rate;
19175  pData->pDeviceInfo->formatCount = 1;
19176  pData->pDeviceInfo->formats[0] = ma_format_from_pulse(pInfo->sample_spec.format);
19177 
19178  (void)pPulseContext; /* Unused. */
19179 }
19180 
19181 static void ma_context_get_device_info_source_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData)
19182 {
19183  ma_context_get_device_info_callback_data__pulse* pData = (ma_context_get_device_info_callback_data__pulse*)pUserData;
19184 
19185  if (endOfList > 0) {
19186  return;
19187  }
19188 
19189  MA_ASSERT(pData != NULL);
19190  pData->foundDevice = MA_TRUE;
19191 
19192  if (pInfo->name != NULL) {
19193  ma_strncpy_s(pData->pDeviceInfo->id.pulse, sizeof(pData->pDeviceInfo->id.pulse), pInfo->name, (size_t)-1);
19194  }
19195 
19196  if (pInfo->description != NULL) {
19197  ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pInfo->description, (size_t)-1);
19198  }
19199 
19200  pData->pDeviceInfo->minChannels = pInfo->sample_spec.channels;
19201  pData->pDeviceInfo->maxChannels = pInfo->sample_spec.channels;
19202  pData->pDeviceInfo->minSampleRate = pInfo->sample_spec.rate;
19203  pData->pDeviceInfo->maxSampleRate = pInfo->sample_spec.rate;
19204  pData->pDeviceInfo->formatCount = 1;
19205  pData->pDeviceInfo->formats[0] = ma_format_from_pulse(pInfo->sample_spec.format);
19206 
19207  (void)pPulseContext; /* Unused. */
19208 }
19209 
19210 static ma_result ma_context_get_device_info__pulse(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
19211 {
19212  ma_result result = MA_SUCCESS;
19213  ma_context_get_device_info_callback_data__pulse callbackData;
19214  ma_pa_operation* pOP = NULL;
19215  ma_pa_mainloop* pMainLoop;
19216  ma_pa_mainloop_api* pAPI;
19217  ma_pa_context* pPulseContext;
19218  int error;
19219 
19220  MA_ASSERT(pContext != NULL);
19221 
19222  /* No exclusive mode with the PulseAudio backend. */
19223  if (shareMode == ma_share_mode_exclusive) {
19225  }
19226 
19227  callbackData.pDeviceInfo = pDeviceInfo;
19228  callbackData.foundDevice = MA_FALSE;
19229 
19230  pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)();
19231  if (pMainLoop == NULL) {
19233  }
19234 
19235  pAPI = ((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)(pMainLoop);
19236  if (pAPI == NULL) {
19237  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
19239  }
19240 
19241  pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->pulse.pApplicationName);
19242  if (pPulseContext == NULL) {
19243  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
19245  }
19246 
19247  error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->pulse.pServerName, 0, NULL);
19248  if (error != MA_PA_OK) {
19249  ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext);
19250  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
19251  return ma_result_from_pulse(error);
19252  }
19253 
19254  for (;;) {
19255  ma_pa_context_state_t state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)(pPulseContext);
19256  if (state == MA_PA_CONTEXT_READY) {
19257  break; /* Success. */
19258  }
19259  if (state == MA_PA_CONTEXT_CONNECTING || state == MA_PA_CONTEXT_AUTHORIZING || state == MA_PA_CONTEXT_SETTING_NAME) {
19260  error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)(pMainLoop, 1, NULL);
19261  if (error < 0) {
19262  result = ma_result_from_pulse(error);
19263  goto done;
19264  }
19265 
19266 #ifdef MA_DEBUG_OUTPUT
19267  printf("[PulseAudio] pa_context_get_state() returned %d. Waiting.\n", state);
19268 #endif
19269  continue; /* Keep trying. */
19270  }
19271  if (state == MA_PA_CONTEXT_UNCONNECTED || state == MA_PA_CONTEXT_FAILED || state == MA_PA_CONTEXT_TERMINATED) {
19272 #ifdef MA_DEBUG_OUTPUT
19273  printf("[PulseAudio] pa_context_get_state() returned %d. Failed.\n", state);
19274 #endif
19275  goto done; /* Failed. */
19276  }
19277  }
19278 
19279  if (deviceType == ma_device_type_playback) {
19280  pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)(pPulseContext, pDeviceID->pulse, ma_context_get_device_info_sink_callback__pulse, &callbackData);
19281  } else {
19282  pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)(pPulseContext, pDeviceID->pulse, ma_context_get_device_info_source_callback__pulse, &callbackData);
19283  }
19284 
19285  if (pOP != NULL) {
19286  ma_wait_for_operation__pulse(pContext, pMainLoop, pOP);
19287  ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
19288  } else {
19289  result = MA_ERROR;
19290  goto done;
19291  }
19292 
19293  if (!callbackData.foundDevice) {
19294  result = MA_NO_DEVICE;
19295  goto done;
19296  }
19297 
19298 
19299 done:
19300  ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)(pPulseContext);
19301  ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext);
19302  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
19303  return result;
19304 }
19305 
19306 
19307 static void ma_pulse_device_state_callback(ma_pa_context* pPulseContext, void* pUserData)
19308 {
19309  ma_device* pDevice;
19310  ma_context* pContext;
19311 
19312  pDevice = (ma_device*)pUserData;
19313  MA_ASSERT(pDevice != NULL);
19314 
19315  pContext = pDevice->pContext;
19316  MA_ASSERT(pContext != NULL);
19317 
19318  pDevice->pulse.pulseContextState = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)(pPulseContext);
19319 }
19320 
19321 void ma_device_sink_info_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData)
19322 {
19323  ma_pa_sink_info* pInfoOut;
19324 
19325  if (endOfList > 0) {
19326  return;
19327  }
19328 
19329  pInfoOut = (ma_pa_sink_info*)pUserData;
19330  MA_ASSERT(pInfoOut != NULL);
19331 
19332  *pInfoOut = *pInfo;
19333 
19334  (void)pPulseContext; /* Unused. */
19335 }
19336 
19337 static void ma_device_source_info_callback(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData)
19338 {
19339  ma_pa_source_info* pInfoOut;
19340 
19341  if (endOfList > 0) {
19342  return;
19343  }
19344 
19345  pInfoOut = (ma_pa_source_info*)pUserData;
19346  MA_ASSERT(pInfoOut != NULL);
19347 
19348  *pInfoOut = *pInfo;
19349 
19350  (void)pPulseContext; /* Unused. */
19351 }
19352 
19353 static void ma_device_sink_name_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData)
19354 {
19355  ma_device* pDevice;
19356 
19357  if (endOfList > 0) {
19358  return;
19359  }
19360 
19361  pDevice = (ma_device*)pUserData;
19362  MA_ASSERT(pDevice != NULL);
19363 
19364  ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), pInfo->description, (size_t)-1);
19365 
19366  (void)pPulseContext; /* Unused. */
19367 }
19368 
19369 static void ma_device_source_name_callback(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData)
19370 {
19371  ma_device* pDevice;
19372 
19373  if (endOfList > 0) {
19374  return;
19375  }
19376 
19377  pDevice = (ma_device*)pUserData;
19378  MA_ASSERT(pDevice != NULL);
19379 
19380  ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), pInfo->description, (size_t)-1);
19381 
19382  (void)pPulseContext; /* Unused. */
19383 }
19384 
19385 static void ma_device_uninit__pulse(ma_device* pDevice)
19386 {
19387  ma_context* pContext;
19388 
19389  MA_ASSERT(pDevice != NULL);
19390 
19391  pContext = pDevice->pContext;
19392  MA_ASSERT(pContext != NULL);
19393 
19394  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
19395  ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
19396  ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
19397  }
19398  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
19399  ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
19400  ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
19401  }
19402 
19403  ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pDevice->pulse.pPulseContext);
19404  ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pDevice->pulse.pPulseContext);
19405  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pDevice->pulse.pMainLoop);
19406 }
19407 
19408 static ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 periodSizeInFrames, ma_uint32 periods, const ma_pa_sample_spec* ss)
19409 {
19410  ma_pa_buffer_attr attr;
19411  attr.maxlength = periodSizeInFrames * periods * ma_get_bytes_per_frame(ma_format_from_pulse(ss->format), ss->channels);
19412  attr.tlength = attr.maxlength / periods;
19413  attr.prebuf = (ma_uint32)-1;
19414  attr.minreq = (ma_uint32)-1;
19415  attr.fragsize = attr.maxlength / periods;
19416 
19417  return attr;
19418 }
19419 
19420 static ma_pa_stream* ma_device__pa_stream_new__pulse(ma_device* pDevice, const char* pStreamName, const ma_pa_sample_spec* ss, const ma_pa_channel_map* cmap)
19421 {
19422  static int g_StreamCounter = 0;
19423  char actualStreamName[256];
19424 
19425  if (pStreamName != NULL) {
19426  ma_strncpy_s(actualStreamName, sizeof(actualStreamName), pStreamName, (size_t)-1);
19427  } else {
19428  ma_strcpy_s(actualStreamName, sizeof(actualStreamName), "miniaudio:");
19429  ma_itoa_s(g_StreamCounter, actualStreamName + 8, sizeof(actualStreamName)-8, 10); /* 8 = strlen("miniaudio:") */
19430  }
19431  g_StreamCounter += 1;
19432 
19433  return ((ma_pa_stream_new_proc)pDevice->pContext->pulse.pa_stream_new)((ma_pa_context*)pDevice->pulse.pPulseContext, actualStreamName, ss, cmap);
19434 }
19435 
19436 static ma_result ma_device_init__pulse(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
19437 {
19438  ma_result result = MA_SUCCESS;
19439  int error = 0;
19440  const char* devPlayback = NULL;
19441  const char* devCapture = NULL;
19442  ma_uint32 periodSizeInMilliseconds;
19443  ma_pa_sink_info sinkInfo;
19444  ma_pa_source_info sourceInfo;
19445  ma_pa_operation* pOP = NULL;
19446  ma_pa_sample_spec ss;
19447  ma_pa_channel_map cmap;
19448  ma_pa_buffer_attr attr;
19449  const ma_pa_sample_spec* pActualSS = NULL;
19450  const ma_pa_channel_map* pActualCMap = NULL;
19451  const ma_pa_buffer_attr* pActualAttr = NULL;
19452  ma_uint32 iChannel;
19453  ma_pa_stream_flags_t streamFlags;
19454 
19455  MA_ASSERT(pDevice != NULL);
19456  MA_ZERO_OBJECT(&pDevice->pulse);
19457 
19458  if (pConfig->deviceType == ma_device_type_loopback) {
19460  }
19461 
19462  /* No exclusive mode with the PulseAudio backend. */
19466  }
19467 
19468  if ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID != NULL) {
19469  devPlayback = pConfig->playback.pDeviceID->pulse;
19470  }
19471  if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID != NULL) {
19472  devCapture = pConfig->capture.pDeviceID->pulse;
19473  }
19474 
19475  periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
19476  if (periodSizeInMilliseconds == 0) {
19477  periodSizeInMilliseconds = ma_calculate_buffer_size_in_milliseconds_from_frames(pConfig->periodSizeInFrames, pConfig->sampleRate);
19478  }
19479 
19480  pDevice->pulse.pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)();
19481  if (pDevice->pulse.pMainLoop == NULL) {
19482  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create main loop for device.", MA_FAILED_TO_INIT_BACKEND);
19483  goto on_error0;
19484  }
19485 
19486  pDevice->pulse.pAPI = ((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)((ma_pa_mainloop*)pDevice->pulse.pMainLoop);
19487  if (pDevice->pulse.pAPI == NULL) {
19488  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve PulseAudio main loop.", MA_FAILED_TO_INIT_BACKEND);
19489  goto on_error1;
19490  }
19491 
19492  pDevice->pulse.pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)((ma_pa_mainloop_api*)pDevice->pulse.pAPI, pContext->pulse.pApplicationName);
19493  if (pDevice->pulse.pPulseContext == NULL) {
19494  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio context for device.", MA_FAILED_TO_INIT_BACKEND);
19495  goto on_error1;
19496  }
19497 
19498  error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pDevice->pulse.pPulseContext, pContext->pulse.pServerName, (pContext->pulse.tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL);
19499  if (error != MA_PA_OK) {
19500  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context.", ma_result_from_pulse(error));
19501  goto on_error2;
19502  }
19503 
19504 
19505  pDevice->pulse.pulseContextState = MA_PA_CONTEXT_UNCONNECTED;
19506  ((ma_pa_context_set_state_callback_proc)pContext->pulse.pa_context_set_state_callback)((ma_pa_context*)pDevice->pulse.pPulseContext, ma_pulse_device_state_callback, pDevice);
19507 
19508  /* Wait for PulseAudio to get itself ready before returning. */
19509  for (;;) {
19510  if (pDevice->pulse.pulseContextState == MA_PA_CONTEXT_READY) {
19511  break;
19512  }
19513 
19514  /* An error may have occurred. */
19515  if (pDevice->pulse.pulseContextState == MA_PA_CONTEXT_FAILED || pDevice->pulse.pulseContextState == MA_PA_CONTEXT_TERMINATED) {
19516  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio context.", MA_ERROR);
19517  goto on_error3;
19518  }
19519 
19520  error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 1, NULL);
19521  if (error < 0) {
19522  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] The PulseAudio main loop returned an error while connecting the PulseAudio context.", ma_result_from_pulse(error));
19523  goto on_error3;
19524  }
19525  }
19526 
19527  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
19528  pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devCapture, ma_device_source_info_callback, &sourceInfo);
19529  if (pOP != NULL) {
19530  ma_device__wait_for_operation__pulse(pDevice, pOP);
19531  ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
19532  } else {
19533  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve source info for capture device.", ma_result_from_pulse(error));
19534  goto on_error3;
19535  }
19536 
19537  ss = sourceInfo.sample_spec;
19538  cmap = sourceInfo.channel_map;
19539 
19540  pDevice->capture.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(periodSizeInMilliseconds, ss.rate);
19541  pDevice->capture.internalPeriods = pConfig->periods;
19542 
19543  attr = ma_device__pa_buffer_attr_new(pDevice->capture.internalPeriodSizeInFrames, pConfig->periods, &ss);
19544  #ifdef MA_DEBUG_OUTPUT
19545  printf("[PulseAudio] Capture attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->capture.internalPeriodSizeInFrames);
19546  #endif
19547 
19548  pDevice->pulse.pStreamCapture = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNameCapture, &ss, &cmap);
19549  if (pDevice->pulse.pStreamCapture == NULL) {
19550  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
19551  goto on_error3;
19552  }
19553 
19554  streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS;
19555  if (devCapture != NULL) {
19556  streamFlags |= MA_PA_STREAM_DONT_MOVE;
19557  }
19558 
19559  error = ((ma_pa_stream_connect_record_proc)pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags);
19560  if (error != MA_PA_OK) {
19561  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream.", ma_result_from_pulse(error));
19562  goto on_error4;
19563  }
19564 
19565  while (((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)((ma_pa_stream*)pDevice->pulse.pStreamCapture) != MA_PA_STREAM_READY) {
19566  error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 1, NULL);
19567  if (error < 0) {
19568  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] The PulseAudio main loop returned an error while connecting the PulseAudio capture stream.", ma_result_from_pulse(error));
19569  goto on_error5;
19570  }
19571  }
19572 
19573  /* Internal format. */
19574  pActualSS = ((ma_pa_stream_get_sample_spec_proc)pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
19575  if (pActualSS != NULL) {
19576  /* If anything has changed between the requested and the actual sample spec, we need to update the buffer. */
19577  if (ss.format != pActualSS->format || ss.channels != pActualSS->channels || ss.rate != pActualSS->rate) {
19578  attr = ma_device__pa_buffer_attr_new(pDevice->capture.internalPeriodSizeInFrames, pConfig->periods, pActualSS);
19579 
19580  pOP = ((ma_pa_stream_set_buffer_attr_proc)pContext->pulse.pa_stream_set_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamCapture, &attr, NULL, NULL);
19581  if (pOP != NULL) {
19582  ma_device__wait_for_operation__pulse(pDevice, pOP);
19583  ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
19584  }
19585  }
19586 
19587  ss = *pActualSS;
19588  }
19589 
19590  pDevice->capture.internalFormat = ma_format_from_pulse(ss.format);
19591  pDevice->capture.internalChannels = ss.channels;
19592  pDevice->capture.internalSampleRate = ss.rate;
19593 
19594  /* Internal channel map. */
19595  pActualCMap = ((ma_pa_stream_get_channel_map_proc)pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
19596  if (pActualCMap != NULL) {
19597  cmap = *pActualCMap;
19598  }
19599  for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) {
19600  pDevice->capture.internalChannelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]);
19601  }
19602 
19603  /* Buffer. */
19604  pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
19605  if (pActualAttr != NULL) {
19606  attr = *pActualAttr;
19607  }
19608  pDevice->capture.internalPeriods = attr.maxlength / attr.fragsize;
19610  #ifdef MA_DEBUG_OUTPUT
19611  printf("[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->capture.internalPeriodSizeInFrames);
19612  #endif
19613 
19614  /* Name. */
19615  devCapture = ((ma_pa_stream_get_device_name_proc)pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
19616  if (devCapture != NULL) {
19617  ma_pa_operation* pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devCapture, ma_device_source_name_callback, pDevice);
19618  if (pOP != NULL) {
19619  ma_device__wait_for_operation__pulse(pDevice, pOP);
19620  ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
19621  }
19622  }
19623  }
19624 
19625  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
19626  pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devPlayback, ma_device_sink_info_callback, &sinkInfo);
19627  if (pOP != NULL) {
19628  ma_device__wait_for_operation__pulse(pDevice, pOP);
19629  ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
19630  } else {
19631  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device.", ma_result_from_pulse(error));
19632  goto on_error3;
19633  }
19634 
19635  ss = sinkInfo.sample_spec;
19636  cmap = sinkInfo.channel_map;
19637 
19639  pDevice->playback.internalPeriods = pConfig->periods;
19640 
19641  attr = ma_device__pa_buffer_attr_new(pDevice->playback.internalPeriodSizeInFrames, pConfig->periods, &ss);
19642  #ifdef MA_DEBUG_OUTPUT
19643  printf("[PulseAudio] Playback attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->playback.internalPeriodSizeInFrames);
19644  #endif
19645 
19646  pDevice->pulse.pStreamPlayback = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNamePlayback, &ss, &cmap);
19647  if (pDevice->pulse.pStreamPlayback == NULL) {
19648  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
19649  goto on_error3;
19650  }
19651 
19652  streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS;
19653  if (devPlayback != NULL) {
19654  streamFlags |= MA_PA_STREAM_DONT_MOVE;
19655  }
19656 
19657  error = ((ma_pa_stream_connect_playback_proc)pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL);
19658  if (error != MA_PA_OK) {
19659  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream.", ma_result_from_pulse(error));
19660  goto on_error6;
19661  }
19662 
19663  while (((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)((ma_pa_stream*)pDevice->pulse.pStreamPlayback) != MA_PA_STREAM_READY) {
19664  error = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 1, NULL);
19665  if (error < 0) {
19666  result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] The PulseAudio main loop returned an error while connecting the PulseAudio playback stream.", ma_result_from_pulse(error));
19667  goto on_error7;
19668  }
19669  }
19670 
19671  /* Internal format. */
19672  pActualSS = ((ma_pa_stream_get_sample_spec_proc)pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
19673  if (pActualSS != NULL) {
19674  /* If anything has changed between the requested and the actual sample spec, we need to update the buffer. */
19675  if (ss.format != pActualSS->format || ss.channels != pActualSS->channels || ss.rate != pActualSS->rate) {
19676  attr = ma_device__pa_buffer_attr_new(pDevice->playback.internalPeriodSizeInFrames, pConfig->periods, pActualSS);
19677 
19678  pOP = ((ma_pa_stream_set_buffer_attr_proc)pContext->pulse.pa_stream_set_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, &attr, NULL, NULL);
19679  if (pOP != NULL) {
19680  ma_device__wait_for_operation__pulse(pDevice, pOP);
19681  ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
19682  }
19683  }
19684 
19685  ss = *pActualSS;
19686  }
19687 
19688  pDevice->playback.internalFormat = ma_format_from_pulse(ss.format);
19689  pDevice->playback.internalChannels = ss.channels;
19690  pDevice->playback.internalSampleRate = ss.rate;
19691 
19692  /* Internal channel map. */
19693  pActualCMap = ((ma_pa_stream_get_channel_map_proc)pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
19694  if (pActualCMap != NULL) {
19695  cmap = *pActualCMap;
19696  }
19697  for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) {
19698  pDevice->playback.internalChannelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]);
19699  }
19700 
19701  /* Buffer. */
19702  pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
19703  if (pActualAttr != NULL) {
19704  attr = *pActualAttr;
19705  }
19706  pDevice->playback.internalPeriods = attr.maxlength / attr.tlength;
19708  #ifdef MA_DEBUG_OUTPUT
19709  printf("[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->playback.internalPeriodSizeInFrames);
19710  #endif
19711 
19712  /* Name. */
19713  devPlayback = ((ma_pa_stream_get_device_name_proc)pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
19714  if (devPlayback != NULL) {
19715  ma_pa_operation* pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devPlayback, ma_device_sink_name_callback, pDevice);
19716  if (pOP != NULL) {
19717  ma_device__wait_for_operation__pulse(pDevice, pOP);
19718  ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
19719  }
19720  }
19721  }
19722 
19723  return MA_SUCCESS;
19724 
19725 
19726 on_error7:
19727  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
19728  ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
19729  }
19730 on_error6:
19731  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
19732  ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
19733  }
19734 on_error5:
19735  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
19736  ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
19737  }
19738 on_error4:
19739  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
19740  ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
19741  }
19742 on_error3: ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pDevice->pulse.pPulseContext);
19743 on_error2: ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pDevice->pulse.pPulseContext);
19744 on_error1: ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pDevice->pulse.pMainLoop);
19745 on_error0:
19746  return result;
19747 }
19748 
19749 
19750 static void ma_pulse_operation_complete_callback(ma_pa_stream* pStream, int success, void* pUserData)
19751 {
19752  ma_bool32* pIsSuccessful = (ma_bool32*)pUserData;
19753  MA_ASSERT(pIsSuccessful != NULL);
19754 
19755  *pIsSuccessful = (ma_bool32)success;
19756 
19757  (void)pStream; /* Unused. */
19758 }
19759 
19760 static ma_result ma_device__cork_stream__pulse(ma_device* pDevice, ma_device_type deviceType, int cork)
19761 {
19762  ma_context* pContext = pDevice->pContext;
19763  ma_bool32 wasSuccessful;
19764  ma_pa_stream* pStream;
19765  ma_pa_operation* pOP;
19766  ma_result result;
19767 
19768  /* This should not be called with a duplex device type. */
19769  if (deviceType == ma_device_type_duplex) {
19770  return MA_INVALID_ARGS;
19771  }
19772 
19773  wasSuccessful = MA_FALSE;
19774 
19775  pStream = (ma_pa_stream*)((deviceType == ma_device_type_capture) ? pDevice->pulse.pStreamCapture : pDevice->pulse.pStreamPlayback);
19776  MA_ASSERT(pStream != NULL);
19777 
19778  pOP = ((ma_pa_stream_cork_proc)pContext->pulse.pa_stream_cork)(pStream, cork, ma_pulse_operation_complete_callback, &wasSuccessful);
19779  if (pOP == NULL) {
19780  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to cork PulseAudio stream.", (cork == 0) ? MA_FAILED_TO_START_BACKEND_DEVICE : MA_FAILED_TO_STOP_BACKEND_DEVICE);
19781  }
19782 
19783  result = ma_device__wait_for_operation__pulse(pDevice, pOP);
19784  ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
19785 
19786  if (result != MA_SUCCESS) {
19787  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while waiting for the PulseAudio stream to cork.", result);
19788  }
19789 
19790  if (!wasSuccessful) {
19791  if (cork) {
19792  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to stop PulseAudio stream.", MA_FAILED_TO_STOP_BACKEND_DEVICE);
19793  } else {
19794  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to start PulseAudio stream.", MA_FAILED_TO_START_BACKEND_DEVICE);
19795  }
19796  }
19797 
19798  return MA_SUCCESS;
19799 }
19800 
19801 static ma_result ma_device_stop__pulse(ma_device* pDevice)
19802 {
19803  ma_result result;
19804  ma_bool32 wasSuccessful;
19805  ma_pa_operation* pOP;
19806 
19807  MA_ASSERT(pDevice != NULL);
19808 
19809  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
19810  result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 1);
19811  if (result != MA_SUCCESS) {
19812  return result;
19813  }
19814  }
19815 
19816  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
19817  /* The stream needs to be drained if it's a playback device. */
19818  pOP = ((ma_pa_stream_drain_proc)pDevice->pContext->pulse.pa_stream_drain)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_pulse_operation_complete_callback, &wasSuccessful);
19819  if (pOP != NULL) {
19820  ma_device__wait_for_operation__pulse(pDevice, pOP);
19821  ((ma_pa_operation_unref_proc)pDevice->pContext->pulse.pa_operation_unref)(pOP);
19822  }
19823 
19824  result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 1);
19825  if (result != MA_SUCCESS) {
19826  return result;
19827  }
19828  }
19829 
19830  return MA_SUCCESS;
19831 }
19832 
19833 static ma_result ma_device_write__pulse(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
19834 {
19835  ma_uint32 totalFramesWritten;
19836 
19837  MA_ASSERT(pDevice != NULL);
19838  MA_ASSERT(pPCMFrames != NULL);
19839  MA_ASSERT(frameCount > 0);
19840 
19841  if (pFramesWritten != NULL) {
19842  *pFramesWritten = 0;
19843  }
19844 
19845  totalFramesWritten = 0;
19846  while (totalFramesWritten < frameCount) {
19847  if (ma_device__get_state(pDevice) != MA_STATE_STARTED) {
19848  return MA_DEVICE_NOT_STARTED;
19849  }
19850 
19851  /* Place the data into the mapped buffer if we have one. */
19852  if (pDevice->pulse.pMappedBufferPlayback != NULL && pDevice->pulse.mappedBufferFramesRemainingPlayback > 0) {
19854  ma_uint32 mappedBufferFramesConsumed = pDevice->pulse.mappedBufferFramesCapacityPlayback - pDevice->pulse.mappedBufferFramesRemainingPlayback;
19855 
19856  void* pDst = (ma_uint8*)pDevice->pulse.pMappedBufferPlayback + (mappedBufferFramesConsumed * bpf);
19857  const void* pSrc = (const ma_uint8*)pPCMFrames + (totalFramesWritten * bpf);
19858  ma_uint32 framesToCopy = ma_min(pDevice->pulse.mappedBufferFramesRemainingPlayback, (frameCount - totalFramesWritten));
19859  MA_COPY_MEMORY(pDst, pSrc, framesToCopy * bpf);
19860 
19861  pDevice->pulse.mappedBufferFramesRemainingPlayback -= framesToCopy;
19862  totalFramesWritten += framesToCopy;
19863  }
19864 
19865  /*
19866  Getting here means we've run out of data in the currently mapped chunk. We need to write this to the device and then try
19867  mapping another chunk. If this fails we need to wait for space to become available.
19868  */
19869  if (pDevice->pulse.mappedBufferFramesCapacityPlayback > 0 && pDevice->pulse.mappedBufferFramesRemainingPlayback == 0) {
19870  size_t nbytes = pDevice->pulse.mappedBufferFramesCapacityPlayback * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
19871 
19872  int error = ((ma_pa_stream_write_proc)pDevice->pContext->pulse.pa_stream_write)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, pDevice->pulse.pMappedBufferPlayback, nbytes, NULL, 0, MA_PA_SEEK_RELATIVE);
19873  if (error < 0) {
19874  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to write data to the PulseAudio stream.", ma_result_from_pulse(error));
19875  }
19876 
19877  pDevice->pulse.pMappedBufferPlayback = NULL;
19878  pDevice->pulse.mappedBufferFramesRemainingPlayback = 0;
19879  pDevice->pulse.mappedBufferFramesCapacityPlayback = 0;
19880  }
19881 
19882  MA_ASSERT(totalFramesWritten <= frameCount);
19883  if (totalFramesWritten == frameCount) {
19884  break;
19885  }
19886 
19887  /* Getting here means we need to map a new buffer. If we don't have enough space we need to wait for more. */
19888  for (;;) {
19889  size_t writableSizeInBytes;
19890 
19891  /* If the device has been corked, don't try to continue. */
19892  if (((ma_pa_stream_is_corked_proc)pDevice->pContext->pulse.pa_stream_is_corked)((ma_pa_stream*)pDevice->pulse.pStreamPlayback)) {
19893  break;
19894  }
19895 
19896  writableSizeInBytes = ((ma_pa_stream_writable_size_proc)pDevice->pContext->pulse.pa_stream_writable_size)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
19897  if (writableSizeInBytes != (size_t)-1) {
19898  if (writableSizeInBytes > 0) {
19899  /* Data is avaialable. */
19900  size_t bytesToMap = writableSizeInBytes;
19901  int error = ((ma_pa_stream_begin_write_proc)pDevice->pContext->pulse.pa_stream_begin_write)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, &pDevice->pulse.pMappedBufferPlayback, &bytesToMap);
19902  if (error < 0) {
19903  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to map write buffer.", ma_result_from_pulse(error));
19904  }
19905 
19906  pDevice->pulse.mappedBufferFramesCapacityPlayback = bytesToMap / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
19907  pDevice->pulse.mappedBufferFramesRemainingPlayback = pDevice->pulse.mappedBufferFramesCapacityPlayback;
19908 
19909  break;
19910  } else {
19911  /* No data available. Need to wait for more. */
19912  int error = ((ma_pa_mainloop_iterate_proc)pDevice->pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 1, NULL);
19913  if (error < 0) {
19914  return ma_result_from_pulse(error);
19915  }
19916 
19917  continue;
19918  }
19919  } else {
19920  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to query the stream's writable size.", MA_ERROR);
19921  }
19922  }
19923  }
19924 
19925  if (pFramesWritten != NULL) {
19926  *pFramesWritten = totalFramesWritten;
19927  }
19928 
19929  return MA_SUCCESS;
19930 }
19931 
19932 static ma_result ma_device_read__pulse(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
19933 {
19934  ma_uint32 totalFramesRead;
19935 
19936  MA_ASSERT(pDevice != NULL);
19937  MA_ASSERT(pPCMFrames != NULL);
19938  MA_ASSERT(frameCount > 0);
19939 
19940  if (pFramesRead != NULL) {
19941  *pFramesRead = 0;
19942  }
19943 
19944  totalFramesRead = 0;
19945  while (totalFramesRead < frameCount) {
19946  if (ma_device__get_state(pDevice) != MA_STATE_STARTED) {
19947  return MA_DEVICE_NOT_STARTED;
19948  }
19949 
19950  /*
19951  If a buffer is mapped we need to read from that first. Once it's consumed we need to drop it. Note that pDevice->pulse.pMappedBufferCapture can be null in which
19952  case it could be a hole. In this case we just write zeros into the output buffer.
19953  */
19954  if (pDevice->pulse.mappedBufferFramesRemainingCapture > 0) {
19956  ma_uint32 mappedBufferFramesConsumed = pDevice->pulse.mappedBufferFramesCapacityCapture - pDevice->pulse.mappedBufferFramesRemainingCapture;
19957 
19958  ma_uint32 framesToCopy = ma_min(pDevice->pulse.mappedBufferFramesRemainingCapture, (frameCount - totalFramesRead));
19959  void* pDst = (ma_uint8*)pPCMFrames + (totalFramesRead * bpf);
19960 
19961  /*
19962  This little bit of logic here is specifically for PulseAudio and it's hole management. The buffer pointer will be set to NULL
19963  when the current fragment is a hole. For a hole we just output silence.
19964  */
19965  if (pDevice->pulse.pMappedBufferCapture != NULL) {
19966  const void* pSrc = (const ma_uint8*)pDevice->pulse.pMappedBufferCapture + (mappedBufferFramesConsumed * bpf);
19967  MA_COPY_MEMORY(pDst, pSrc, framesToCopy * bpf);
19968  } else {
19969  MA_ZERO_MEMORY(pDst, framesToCopy * bpf);
19970  #if defined(MA_DEBUG_OUTPUT)
19971  printf("[PulseAudio] ma_device_read__pulse: Filling hole with silence.\n");
19972  #endif
19973  }
19974 
19975  pDevice->pulse.mappedBufferFramesRemainingCapture -= framesToCopy;
19976  totalFramesRead += framesToCopy;
19977  }
19978 
19979  /*
19980  Getting here means we've run out of data in the currently mapped chunk. We need to drop this from the device and then try
19981  mapping another chunk. If this fails we need to wait for data to become available.
19982  */
19983  if (pDevice->pulse.mappedBufferFramesCapacityCapture > 0 && pDevice->pulse.mappedBufferFramesRemainingCapture == 0) {
19984  int error;
19985 
19986  #if defined(MA_DEBUG_OUTPUT)
19987  printf("[PulseAudio] ma_device_read__pulse: Call pa_stream_drop()\n");
19988  #endif
19989 
19990  error = ((ma_pa_stream_drop_proc)pDevice->pContext->pulse.pa_stream_drop)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
19991  if (error != 0) {
19992  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to drop fragment.", ma_result_from_pulse(error));
19993  }
19994 
19995  pDevice->pulse.pMappedBufferCapture = NULL;
19996  pDevice->pulse.mappedBufferFramesRemainingCapture = 0;
19997  pDevice->pulse.mappedBufferFramesCapacityCapture = 0;
19998  }
19999 
20000  MA_ASSERT(totalFramesRead <= frameCount);
20001  if (totalFramesRead == frameCount) {
20002  break;
20003  }
20004 
20005  /* Getting here means we need to map a new buffer. If we don't have enough data we wait for more. */
20006  for (;;) {
20007  int error;
20008  size_t bytesMapped;
20009 
20010  if (ma_device__get_state(pDevice) != MA_STATE_STARTED) {
20011  break;
20012  }
20013 
20014  /* If the device has been corked, don't try to continue. */
20015  if (((ma_pa_stream_is_corked_proc)pDevice->pContext->pulse.pa_stream_is_corked)((ma_pa_stream*)pDevice->pulse.pStreamCapture)) {
20016  #if defined(MA_DEBUG_OUTPUT)
20017  printf("[PulseAudio] ma_device_read__pulse: Corked.\n");
20018  #endif
20019  break;
20020  }
20021 
20022  MA_ASSERT(pDevice->pulse.pMappedBufferCapture == NULL); /* <-- We're about to map a buffer which means we shouldn't have an existing mapping. */
20023 
20024  error = ((ma_pa_stream_peek_proc)pDevice->pContext->pulse.pa_stream_peek)((ma_pa_stream*)pDevice->pulse.pStreamCapture, &pDevice->pulse.pMappedBufferCapture, &bytesMapped);
20025  if (error < 0) {
20026  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to peek capture buffer.", ma_result_from_pulse(error));
20027  }
20028 
20029  if (bytesMapped > 0) {
20030  pDevice->pulse.mappedBufferFramesCapacityCapture = bytesMapped / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
20031  pDevice->pulse.mappedBufferFramesRemainingCapture = pDevice->pulse.mappedBufferFramesCapacityCapture;
20032 
20033  #if defined(MA_DEBUG_OUTPUT)
20034  printf("[PulseAudio] ma_device_read__pulse: Mapped. mappedBufferFramesCapacityCapture=%d, mappedBufferFramesRemainingCapture=%d\n", pDevice->pulse.mappedBufferFramesCapacityCapture, pDevice->pulse.mappedBufferFramesRemainingCapture);
20035  #endif
20036 
20037  if (pDevice->pulse.pMappedBufferCapture == NULL) {
20038  /* It's a hole. */
20039  #if defined(MA_DEBUG_OUTPUT)
20040  printf("[PulseAudio] ma_device_read__pulse: Call pa_stream_peek(). Hole.\n");
20041  #endif
20042  }
20043 
20044  break;
20045  } else {
20046  if (pDevice->pulse.pMappedBufferCapture == NULL) {
20047  /* Nothing available yet. Need to wait for more. */
20048 
20049  /*
20050  I have had reports of a deadlock in this part of the code. I have reproduced this when using the "Built-in Audio Analogue Stereo" device without
20051  an actual microphone connected. I'm experimenting here by not blocking in pa_mainloop_iterate() and instead sleep for a bit when there are no
20052  dispatches.
20053  */
20054  error = ((ma_pa_mainloop_iterate_proc)pDevice->pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 0, NULL);
20055  if (error < 0) {
20056  return ma_result_from_pulse(error);
20057  }
20058 
20059  /* Sleep for a bit if nothing was dispatched. */
20060  if (error == 0) {
20061  ma_sleep(1);
20062  }
20063 
20064  #if defined(MA_DEBUG_OUTPUT)
20065  printf("[PulseAudio] ma_device_read__pulse: No data available. Waiting. mappedBufferFramesCapacityCapture=%d, mappedBufferFramesRemainingCapture=%d\n", pDevice->pulse.mappedBufferFramesCapacityCapture, pDevice->pulse.mappedBufferFramesRemainingCapture);
20066  #endif
20067  } else {
20068  /* Getting here means we mapped 0 bytes, but have a non-NULL buffer. I don't think this should ever happen. */
20070  }
20071  }
20072  }
20073  }
20074 
20075  if (pFramesRead != NULL) {
20076  *pFramesRead = totalFramesRead;
20077  }
20078 
20079  return MA_SUCCESS;
20080 }
20081 
20082 static ma_result ma_device_main_loop__pulse(ma_device* pDevice)
20083 {
20084  ma_result result = MA_SUCCESS;
20085  ma_bool32 exitLoop = MA_FALSE;
20086 
20087  MA_ASSERT(pDevice != NULL);
20088 
20089  /* The stream needs to be uncorked first. We do this at the top for both capture and playback for PulseAudio. */
20090  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
20091  result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 0);
20092  if (result != MA_SUCCESS) {
20093  return result;
20094  }
20095  }
20096  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
20097  result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 0);
20098  if (result != MA_SUCCESS) {
20099  return result;
20100  }
20101  }
20102 
20103 
20104  while (ma_device__get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
20105  switch (pDevice->type)
20106  {
20107  case ma_device_type_duplex:
20108  {
20109  /* The process is: device_read -> convert -> callback -> convert -> device_write */
20110  ma_uint32 totalCapturedDeviceFramesProcessed = 0;
20111  ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
20112 
20113  while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
20114  ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
20115  ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
20116  ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
20117  ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
20118  ma_uint32 capturedDeviceFramesRemaining;
20119  ma_uint32 capturedDeviceFramesProcessed;
20120  ma_uint32 capturedDeviceFramesToProcess;
20121  ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed;
20122  if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) {
20123  capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames;
20124  }
20125 
20126  result = ma_device_read__pulse(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess);
20127  if (result != MA_SUCCESS) {
20128  exitLoop = MA_TRUE;
20129  break;
20130  }
20131 
20132  capturedDeviceFramesRemaining = capturedDeviceFramesToProcess;
20133  capturedDeviceFramesProcessed = 0;
20134 
20135  for (;;) {
20136  ma_uint8 capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
20137  ma_uint8 playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
20138  ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
20139  ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
20140  ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames);
20141  ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining;
20142  ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
20143 
20144  /* Convert capture data from device format to client format. */
20145  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration);
20146  if (result != MA_SUCCESS) {
20147  break;
20148  }
20149 
20150  /*
20151  If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small
20152  which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
20153  */
20154  if (capturedClientFramesToProcessThisIteration == 0) {
20155  break;
20156  }
20157 
20158  ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/
20159 
20160  capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
20161  capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
20162 
20163  /* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */
20164  for (;;) {
20165  ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration;
20166  ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames;
20167  result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount);
20168  if (result != MA_SUCCESS) {
20169  break;
20170  }
20171 
20172  result = ma_device_write__pulse(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL); /* Safe cast. */
20173  if (result != MA_SUCCESS) {
20174  exitLoop = MA_TRUE;
20175  break;
20176  }
20177 
20178  capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount; /* Safe cast. */
20179  if (capturedClientFramesToProcessThisIteration == 0) {
20180  break;
20181  }
20182  }
20183 
20184  /* In case an error happened from ma_device_write__pulse()... */
20185  if (result != MA_SUCCESS) {
20186  exitLoop = MA_TRUE;
20187  break;
20188  }
20189  }
20190 
20191  totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed;
20192  }
20193  } break;
20194 
20196  {
20197  ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
20198  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
20199  ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
20200  ma_uint32 framesReadThisPeriod = 0;
20201  while (framesReadThisPeriod < periodSizeInFrames) {
20202  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
20203  ma_uint32 framesProcessed;
20204  ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
20205  if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
20206  framesToReadThisIteration = intermediaryBufferSizeInFrames;
20207  }
20208 
20209  result = ma_device_read__pulse(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
20210  if (result != MA_SUCCESS) {
20211  exitLoop = MA_TRUE;
20212  break;
20213  }
20214 
20215  ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
20216 
20217  framesReadThisPeriod += framesProcessed;
20218  }
20219  } break;
20220 
20222  {
20223  ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
20224  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
20225  ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
20226  ma_uint32 framesWrittenThisPeriod = 0;
20227  while (framesWrittenThisPeriod < periodSizeInFrames) {
20228  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
20229  ma_uint32 framesProcessed;
20230  ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
20231  if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
20232  framesToWriteThisIteration = intermediaryBufferSizeInFrames;
20233  }
20234 
20235  ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
20236 
20237  result = ma_device_write__pulse(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
20238  if (result != MA_SUCCESS) {
20239  exitLoop = MA_TRUE;
20240  break;
20241  }
20242 
20243  framesWrittenThisPeriod += framesProcessed;
20244  }
20245  } break;
20246 
20247  /* To silence a warning. Will never hit this. */
20249  default: break;
20250  }
20251  }
20252 
20253  /* Here is where the device needs to be stopped. */
20254  ma_device_stop__pulse(pDevice);
20255 
20256  return result;
20257 }
20258 
20259 
20260 static ma_result ma_context_uninit__pulse(ma_context* pContext)
20261 {
20262  MA_ASSERT(pContext != NULL);
20263  MA_ASSERT(pContext->backend == ma_backend_pulseaudio);
20264 
20265  ma_free(pContext->pulse.pServerName, &pContext->allocationCallbacks);
20266  pContext->pulse.pServerName = NULL;
20267 
20268  ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks);
20269  pContext->pulse.pApplicationName = NULL;
20270 
20271 #ifndef MA_NO_RUNTIME_LINKING
20272  ma_dlclose(pContext, pContext->pulse.pulseSO);
20273 #endif
20274 
20275  return MA_SUCCESS;
20276 }
20277 
20278 static ma_result ma_context_init__pulse(const ma_context_config* pConfig, ma_context* pContext)
20279 {
20280 #ifndef MA_NO_RUNTIME_LINKING
20281  const char* libpulseNames[] = {
20282  "libpulse.so",
20283  "libpulse.so.0"
20284  };
20285  size_t i;
20286 
20287  for (i = 0; i < ma_countof(libpulseNames); ++i) {
20288  pContext->pulse.pulseSO = ma_dlopen(pContext, libpulseNames[i]);
20289  if (pContext->pulse.pulseSO != NULL) {
20290  break;
20291  }
20292  }
20293 
20294  if (pContext->pulse.pulseSO == NULL) {
20295  return MA_NO_BACKEND;
20296  }
20297 
20298  pContext->pulse.pa_mainloop_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_new");
20299  pContext->pulse.pa_mainloop_free = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_free");
20300  pContext->pulse.pa_mainloop_get_api = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_get_api");
20301  pContext->pulse.pa_mainloop_iterate = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_iterate");
20302  pContext->pulse.pa_mainloop_wakeup = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_wakeup");
20303  pContext->pulse.pa_context_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_new");
20304  pContext->pulse.pa_context_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_unref");
20305  pContext->pulse.pa_context_connect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_connect");
20306  pContext->pulse.pa_context_disconnect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_disconnect");
20307  pContext->pulse.pa_context_set_state_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_set_state_callback");
20308  pContext->pulse.pa_context_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_state");
20309  pContext->pulse.pa_context_get_sink_info_list = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_list");
20310  pContext->pulse.pa_context_get_source_info_list = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_list");
20311  pContext->pulse.pa_context_get_sink_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_by_name");
20312  pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_by_name");
20313  pContext->pulse.pa_operation_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_unref");
20314  pContext->pulse.pa_operation_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_get_state");
20315  pContext->pulse.pa_channel_map_init_extend = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_init_extend");
20316  pContext->pulse.pa_channel_map_valid = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_valid");
20317  pContext->pulse.pa_channel_map_compatible = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_compatible");
20318  pContext->pulse.pa_stream_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_new");
20319  pContext->pulse.pa_stream_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_unref");
20320  pContext->pulse.pa_stream_connect_playback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_playback");
20321  pContext->pulse.pa_stream_connect_record = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_record");
20322  pContext->pulse.pa_stream_disconnect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_disconnect");
20323  pContext->pulse.pa_stream_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_state");
20324  pContext->pulse.pa_stream_get_sample_spec = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_sample_spec");
20325  pContext->pulse.pa_stream_get_channel_map = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_channel_map");
20326  pContext->pulse.pa_stream_get_buffer_attr = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_buffer_attr");
20327  pContext->pulse.pa_stream_set_buffer_attr = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_buffer_attr");
20328  pContext->pulse.pa_stream_get_device_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_device_name");
20329  pContext->pulse.pa_stream_set_write_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_write_callback");
20330  pContext->pulse.pa_stream_set_read_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_read_callback");
20331  pContext->pulse.pa_stream_flush = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_flush");
20332  pContext->pulse.pa_stream_drain = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drain");
20333  pContext->pulse.pa_stream_is_corked = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_corked");
20334  pContext->pulse.pa_stream_cork = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_cork");
20335  pContext->pulse.pa_stream_trigger = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_trigger");
20336  pContext->pulse.pa_stream_begin_write = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_begin_write");
20337  pContext->pulse.pa_stream_write = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_write");
20338  pContext->pulse.pa_stream_peek = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_peek");
20339  pContext->pulse.pa_stream_drop = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drop");
20340  pContext->pulse.pa_stream_writable_size = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_writable_size");
20341  pContext->pulse.pa_stream_readable_size = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_readable_size");
20342 #else
20343  /* This strange assignment system is just for type safety. */
20344  ma_pa_mainloop_new_proc _pa_mainloop_new = pa_mainloop_new;
20345  ma_pa_mainloop_free_proc _pa_mainloop_free = pa_mainloop_free;
20346  ma_pa_mainloop_get_api_proc _pa_mainloop_get_api = pa_mainloop_get_api;
20347  ma_pa_mainloop_iterate_proc _pa_mainloop_iterate = pa_mainloop_iterate;
20348  ma_pa_mainloop_wakeup_proc _pa_mainloop_wakeup = pa_mainloop_wakeup;
20349  ma_pa_context_new_proc _pa_context_new = pa_context_new;
20350  ma_pa_context_unref_proc _pa_context_unref = pa_context_unref;
20351  ma_pa_context_connect_proc _pa_context_connect = pa_context_connect;
20352  ma_pa_context_disconnect_proc _pa_context_disconnect = pa_context_disconnect;
20353  ma_pa_context_set_state_callback_proc _pa_context_set_state_callback = pa_context_set_state_callback;
20354  ma_pa_context_get_state_proc _pa_context_get_state = pa_context_get_state;
20355  ma_pa_context_get_sink_info_list_proc _pa_context_get_sink_info_list = pa_context_get_sink_info_list;
20356  ma_pa_context_get_source_info_list_proc _pa_context_get_source_info_list = pa_context_get_source_info_list;
20357  ma_pa_context_get_sink_info_by_name_proc _pa_context_get_sink_info_by_name = pa_context_get_sink_info_by_name;
20358  ma_pa_context_get_source_info_by_name_proc _pa_context_get_source_info_by_name= pa_context_get_source_info_by_name;
20359  ma_pa_operation_unref_proc _pa_operation_unref = pa_operation_unref;
20360  ma_pa_operation_get_state_proc _pa_operation_get_state = pa_operation_get_state;
20361  ma_pa_channel_map_init_extend_proc _pa_channel_map_init_extend = pa_channel_map_init_extend;
20362  ma_pa_channel_map_valid_proc _pa_channel_map_valid = pa_channel_map_valid;
20363  ma_pa_channel_map_compatible_proc _pa_channel_map_compatible = pa_channel_map_compatible;
20364  ma_pa_stream_new_proc _pa_stream_new = pa_stream_new;
20365  ma_pa_stream_unref_proc _pa_stream_unref = pa_stream_unref;
20366  ma_pa_stream_connect_playback_proc _pa_stream_connect_playback = pa_stream_connect_playback;
20367  ma_pa_stream_connect_record_proc _pa_stream_connect_record = pa_stream_connect_record;
20368  ma_pa_stream_disconnect_proc _pa_stream_disconnect = pa_stream_disconnect;
20369  ma_pa_stream_get_state_proc _pa_stream_get_state = pa_stream_get_state;
20370  ma_pa_stream_get_sample_spec_proc _pa_stream_get_sample_spec = pa_stream_get_sample_spec;
20371  ma_pa_stream_get_channel_map_proc _pa_stream_get_channel_map = pa_stream_get_channel_map;
20372  ma_pa_stream_get_buffer_attr_proc _pa_stream_get_buffer_attr = pa_stream_get_buffer_attr;
20373  ma_pa_stream_set_buffer_attr_proc _pa_stream_set_buffer_attr = pa_stream_set_buffer_attr;
20374  ma_pa_stream_get_device_name_proc _pa_stream_get_device_name = pa_stream_get_device_name;
20375  ma_pa_stream_set_write_callback_proc _pa_stream_set_write_callback = pa_stream_set_write_callback;
20376  ma_pa_stream_set_read_callback_proc _pa_stream_set_read_callback = pa_stream_set_read_callback;
20377  ma_pa_stream_flush_proc _pa_stream_flush = pa_stream_flush;
20378  ma_pa_stream_drain_proc _pa_stream_drain = pa_stream_drain;
20379  ma_pa_stream_is_corked_proc _pa_stream_is_corked = pa_stream_is_corked;
20380  ma_pa_stream_cork_proc _pa_stream_cork = pa_stream_cork;
20381  ma_pa_stream_trigger_proc _pa_stream_trigger = pa_stream_trigger;
20382  ma_pa_stream_begin_write_proc _pa_stream_begin_write = pa_stream_begin_write;
20383  ma_pa_stream_write_proc _pa_stream_write = pa_stream_write;
20384  ma_pa_stream_peek_proc _pa_stream_peek = pa_stream_peek;
20385  ma_pa_stream_drop_proc _pa_stream_drop = pa_stream_drop;
20386  ma_pa_stream_writable_size_proc _pa_stream_writable_size = pa_stream_writable_size;
20387  ma_pa_stream_readable_size_proc _pa_stream_readable_size = pa_stream_readable_size;
20388 
20389  pContext->pulse.pa_mainloop_new = (ma_proc)_pa_mainloop_new;
20390  pContext->pulse.pa_mainloop_free = (ma_proc)_pa_mainloop_free;
20391  pContext->pulse.pa_mainloop_get_api = (ma_proc)_pa_mainloop_get_api;
20392  pContext->pulse.pa_mainloop_iterate = (ma_proc)_pa_mainloop_iterate;
20393  pContext->pulse.pa_mainloop_wakeup = (ma_proc)_pa_mainloop_wakeup;
20394  pContext->pulse.pa_context_new = (ma_proc)_pa_context_new;
20395  pContext->pulse.pa_context_unref = (ma_proc)_pa_context_unref;
20396  pContext->pulse.pa_context_connect = (ma_proc)_pa_context_connect;
20397  pContext->pulse.pa_context_disconnect = (ma_proc)_pa_context_disconnect;
20398  pContext->pulse.pa_context_set_state_callback = (ma_proc)_pa_context_set_state_callback;
20399  pContext->pulse.pa_context_get_state = (ma_proc)_pa_context_get_state;
20400  pContext->pulse.pa_context_get_sink_info_list = (ma_proc)_pa_context_get_sink_info_list;
20401  pContext->pulse.pa_context_get_source_info_list = (ma_proc)_pa_context_get_source_info_list;
20402  pContext->pulse.pa_context_get_sink_info_by_name = (ma_proc)_pa_context_get_sink_info_by_name;
20403  pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)_pa_context_get_source_info_by_name;
20404  pContext->pulse.pa_operation_unref = (ma_proc)_pa_operation_unref;
20405  pContext->pulse.pa_operation_get_state = (ma_proc)_pa_operation_get_state;
20406  pContext->pulse.pa_channel_map_init_extend = (ma_proc)_pa_channel_map_init_extend;
20407  pContext->pulse.pa_channel_map_valid = (ma_proc)_pa_channel_map_valid;
20408  pContext->pulse.pa_channel_map_compatible = (ma_proc)_pa_channel_map_compatible;
20409  pContext->pulse.pa_stream_new = (ma_proc)_pa_stream_new;
20410  pContext->pulse.pa_stream_unref = (ma_proc)_pa_stream_unref;
20411  pContext->pulse.pa_stream_connect_playback = (ma_proc)_pa_stream_connect_playback;
20412  pContext->pulse.pa_stream_connect_record = (ma_proc)_pa_stream_connect_record;
20413  pContext->pulse.pa_stream_disconnect = (ma_proc)_pa_stream_disconnect;
20414  pContext->pulse.pa_stream_get_state = (ma_proc)_pa_stream_get_state;
20415  pContext->pulse.pa_stream_get_sample_spec = (ma_proc)_pa_stream_get_sample_spec;
20416  pContext->pulse.pa_stream_get_channel_map = (ma_proc)_pa_stream_get_channel_map;
20417  pContext->pulse.pa_stream_get_buffer_attr = (ma_proc)_pa_stream_get_buffer_attr;
20418  pContext->pulse.pa_stream_set_buffer_attr = (ma_proc)_pa_stream_set_buffer_attr;
20419  pContext->pulse.pa_stream_get_device_name = (ma_proc)_pa_stream_get_device_name;
20420  pContext->pulse.pa_stream_set_write_callback = (ma_proc)_pa_stream_set_write_callback;
20421  pContext->pulse.pa_stream_set_read_callback = (ma_proc)_pa_stream_set_read_callback;
20422  pContext->pulse.pa_stream_flush = (ma_proc)_pa_stream_flush;
20423  pContext->pulse.pa_stream_drain = (ma_proc)_pa_stream_drain;
20424  pContext->pulse.pa_stream_is_corked = (ma_proc)_pa_stream_is_corked;
20425  pContext->pulse.pa_stream_cork = (ma_proc)_pa_stream_cork;
20426  pContext->pulse.pa_stream_trigger = (ma_proc)_pa_stream_trigger;
20427  pContext->pulse.pa_stream_begin_write = (ma_proc)_pa_stream_begin_write;
20428  pContext->pulse.pa_stream_write = (ma_proc)_pa_stream_write;
20429  pContext->pulse.pa_stream_peek = (ma_proc)_pa_stream_peek;
20430  pContext->pulse.pa_stream_drop = (ma_proc)_pa_stream_drop;
20431  pContext->pulse.pa_stream_writable_size = (ma_proc)_pa_stream_writable_size;
20432  pContext->pulse.pa_stream_readable_size = (ma_proc)_pa_stream_readable_size;
20433 #endif
20434 
20435  pContext->onUninit = ma_context_uninit__pulse;
20436  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__pulse;
20437  pContext->onEnumDevices = ma_context_enumerate_devices__pulse;
20438  pContext->onGetDeviceInfo = ma_context_get_device_info__pulse;
20439  pContext->onDeviceInit = ma_device_init__pulse;
20440  pContext->onDeviceUninit = ma_device_uninit__pulse;
20441  pContext->onDeviceStart = NULL;
20442  pContext->onDeviceStop = NULL;
20443  pContext->onDeviceMainLoop = ma_device_main_loop__pulse;
20444 
20445  if (pConfig->pulse.pApplicationName) {
20446  pContext->pulse.pApplicationName = ma_copy_string(pConfig->pulse.pApplicationName, &pContext->allocationCallbacks);
20447  }
20448  if (pConfig->pulse.pServerName) {
20449  pContext->pulse.pServerName = ma_copy_string(pConfig->pulse.pServerName, &pContext->allocationCallbacks);
20450  }
20451  pContext->pulse.tryAutoSpawn = pConfig->pulse.tryAutoSpawn;
20452 
20453  /*
20454  Although we have found the libpulse library, it doesn't necessarily mean PulseAudio is useable. We need to initialize
20455  and connect a dummy PulseAudio context to test PulseAudio's usability.
20456  */
20457  {
20458  ma_pa_mainloop* pMainLoop;
20459  ma_pa_mainloop_api* pAPI;
20460  ma_pa_context* pPulseContext;
20461  int error;
20462 
20463  pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)();
20464  if (pMainLoop == NULL) {
20465  ma_free(pContext->pulse.pServerName, &pContext->allocationCallbacks);
20466  ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks);
20467  #ifndef MA_NO_RUNTIME_LINKING
20468  ma_dlclose(pContext, pContext->pulse.pulseSO);
20469  #endif
20470  return MA_NO_BACKEND;
20471  }
20472 
20473  pAPI = ((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)(pMainLoop);
20474  if (pAPI == NULL) {
20475  ma_free(pContext->pulse.pServerName, &pContext->allocationCallbacks);
20476  ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks);
20477  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
20478  #ifndef MA_NO_RUNTIME_LINKING
20479  ma_dlclose(pContext, pContext->pulse.pulseSO);
20480  #endif
20481  return MA_NO_BACKEND;
20482  }
20483 
20484  pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(pAPI, pContext->pulse.pApplicationName);
20485  if (pPulseContext == NULL) {
20486  ma_free(pContext->pulse.pServerName, &pContext->allocationCallbacks);
20487  ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks);
20488  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
20489  #ifndef MA_NO_RUNTIME_LINKING
20490  ma_dlclose(pContext, pContext->pulse.pulseSO);
20491  #endif
20492  return MA_NO_BACKEND;
20493  }
20494 
20495  error = ((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)(pPulseContext, pContext->pulse.pServerName, 0, NULL);
20496  if (error != MA_PA_OK) {
20497  ma_free(pContext->pulse.pServerName, &pContext->allocationCallbacks);
20498  ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks);
20499  ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext);
20500  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
20501  #ifndef MA_NO_RUNTIME_LINKING
20502  ma_dlclose(pContext, pContext->pulse.pulseSO);
20503  #endif
20504  return MA_NO_BACKEND;
20505  }
20506 
20507  ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)(pPulseContext);
20508  ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext);
20509  ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop);
20510  }
20511 
20512  return MA_SUCCESS;
20513 }
20514 #endif
20515 
20516 
20517 /******************************************************************************
20518 
20519 JACK Backend
20520 
20521 ******************************************************************************/
20522 #ifdef MA_HAS_JACK
20523 
20524 /* It is assumed jack.h is available when compile-time linking is being used. */
20525 #ifdef MA_NO_RUNTIME_LINKING
20526 #include <jack/jack.h>
20527 
20528 typedef jack_nframes_t ma_jack_nframes_t;
20529 typedef jack_options_t ma_jack_options_t;
20530 typedef jack_status_t ma_jack_status_t;
20531 typedef jack_client_t ma_jack_client_t;
20532 typedef jack_port_t ma_jack_port_t;
20533 typedef JackProcessCallback ma_JackProcessCallback;
20534 typedef JackBufferSizeCallback ma_JackBufferSizeCallback;
20535 typedef JackShutdownCallback ma_JackShutdownCallback;
20536 #define MA_JACK_DEFAULT_AUDIO_TYPE JACK_DEFAULT_AUDIO_TYPE
20537 #define ma_JackNoStartServer JackNoStartServer
20538 #define ma_JackPortIsInput JackPortIsInput
20539 #define ma_JackPortIsOutput JackPortIsOutput
20540 #define ma_JackPortIsPhysical JackPortIsPhysical
20541 #else
20542 typedef ma_uint32 ma_jack_nframes_t;
20543 typedef int ma_jack_options_t;
20544 typedef int ma_jack_status_t;
20545 typedef struct ma_jack_client_t ma_jack_client_t;
20546 typedef struct ma_jack_port_t ma_jack_port_t;
20547 typedef int (* ma_JackProcessCallback) (ma_jack_nframes_t nframes, void* arg);
20548 typedef int (* ma_JackBufferSizeCallback)(ma_jack_nframes_t nframes, void* arg);
20549 typedef void (* ma_JackShutdownCallback) (void* arg);
20550 #define MA_JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio"
20551 #define ma_JackNoStartServer 1
20552 #define ma_JackPortIsInput 1
20553 #define ma_JackPortIsOutput 2
20554 #define ma_JackPortIsPhysical 4
20555 #endif
20556 
20557 typedef ma_jack_client_t* (* ma_jack_client_open_proc) (const char* client_name, ma_jack_options_t options, ma_jack_status_t* status, ...);
20558 typedef int (* ma_jack_client_close_proc) (ma_jack_client_t* client);
20559 typedef int (* ma_jack_client_name_size_proc) ();
20560 typedef int (* ma_jack_set_process_callback_proc) (ma_jack_client_t* client, ma_JackProcessCallback process_callback, void* arg);
20561 typedef int (* ma_jack_set_buffer_size_callback_proc)(ma_jack_client_t* client, ma_JackBufferSizeCallback bufsize_callback, void* arg);
20562 typedef void (* ma_jack_on_shutdown_proc) (ma_jack_client_t* client, ma_JackShutdownCallback function, void* arg);
20563 typedef ma_jack_nframes_t (* ma_jack_get_sample_rate_proc) (ma_jack_client_t* client);
20564 typedef ma_jack_nframes_t (* ma_jack_get_buffer_size_proc) (ma_jack_client_t* client);
20565 typedef const char** (* ma_jack_get_ports_proc) (ma_jack_client_t* client, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags);
20566 typedef int (* ma_jack_activate_proc) (ma_jack_client_t* client);
20567 typedef int (* ma_jack_deactivate_proc) (ma_jack_client_t* client);
20568 typedef int (* ma_jack_connect_proc) (ma_jack_client_t* client, const char* source_port, const char* destination_port);
20569 typedef ma_jack_port_t* (* ma_jack_port_register_proc) (ma_jack_client_t* client, const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size);
20570 typedef const char* (* ma_jack_port_name_proc) (const ma_jack_port_t* port);
20571 typedef void* (* ma_jack_port_get_buffer_proc) (ma_jack_port_t* port, ma_jack_nframes_t nframes);
20572 typedef void (* ma_jack_free_proc) (void* ptr);
20573 
20574 static ma_result ma_context_open_client__jack(ma_context* pContext, ma_jack_client_t** ppClient)
20575 {
20576  size_t maxClientNameSize;
20577  char clientName[256];
20578  ma_jack_status_t status;
20579  ma_jack_client_t* pClient;
20580 
20581  MA_ASSERT(pContext != NULL);
20582  MA_ASSERT(ppClient != NULL);
20583 
20584  if (ppClient) {
20585  *ppClient = NULL;
20586  }
20587 
20588  maxClientNameSize = ((ma_jack_client_name_size_proc)pContext->jack.jack_client_name_size)(); /* Includes null terminator. */
20589  ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (pContext->jack.pClientName != NULL) ? pContext->jack.pClientName : "miniaudio", (size_t)-1);
20590 
20591  pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? 0 : ma_JackNoStartServer, &status, NULL);
20592  if (pClient == NULL) {
20594  }
20595 
20596  if (ppClient) {
20597  *ppClient = pClient;
20598  }
20599 
20600  return MA_SUCCESS;
20601 }
20602 
20603 static ma_bool32 ma_context_is_device_id_equal__jack(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
20604 {
20605  MA_ASSERT(pContext != NULL);
20606  MA_ASSERT(pID0 != NULL);
20607  MA_ASSERT(pID1 != NULL);
20608  (void)pContext;
20609 
20610  return pID0->jack == pID1->jack;
20611 }
20612 
20613 static ma_result ma_context_enumerate_devices__jack(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
20614 {
20615  ma_bool32 cbResult = MA_TRUE;
20616 
20617  MA_ASSERT(pContext != NULL);
20618  MA_ASSERT(callback != NULL);
20619 
20620  /* Playback. */
20621  if (cbResult) {
20622  ma_device_info deviceInfo;
20623  MA_ZERO_OBJECT(&deviceInfo);
20624  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
20625  cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
20626  }
20627 
20628  /* Capture. */
20629  if (cbResult) {
20630  ma_device_info deviceInfo;
20631  MA_ZERO_OBJECT(&deviceInfo);
20632  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
20633  cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
20634  }
20635 
20636  return MA_SUCCESS;
20637 }
20638 
20639 static ma_result ma_context_get_device_info__jack(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
20640 {
20641  ma_jack_client_t* pClient;
20642  ma_result result;
20643  const char** ppPorts;
20644 
20645  MA_ASSERT(pContext != NULL);
20646 
20647  /* No exclusive mode with the JACK backend. */
20648  if (shareMode == ma_share_mode_exclusive) {
20650  }
20651 
20652  if (pDeviceID != NULL && pDeviceID->jack != 0) {
20653  return MA_NO_DEVICE; /* Don't know the device. */
20654  }
20655 
20656  /* Name / Description */
20657  if (deviceType == ma_device_type_playback) {
20658  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
20659  } else {
20660  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
20661  }
20662 
20663  /* Jack only supports f32 and has a specific channel count and sample rate. */
20664  pDeviceInfo->formatCount = 1;
20665  pDeviceInfo->formats[0] = ma_format_f32;
20666 
20667  /* The channel count and sample rate can only be determined by opening the device. */
20668  result = ma_context_open_client__jack(pContext, &pClient);
20669  if (result != MA_SUCCESS) {
20670  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", result);
20671  }
20672 
20673  pDeviceInfo->minSampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pClient);
20674  pDeviceInfo->maxSampleRate = pDeviceInfo->minSampleRate;
20675 
20676  pDeviceInfo->minChannels = 0;
20677  pDeviceInfo->maxChannels = 0;
20678 
20679  ppPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ((deviceType == ma_device_type_playback) ? ma_JackPortIsInput : ma_JackPortIsOutput));
20680  if (ppPorts == NULL) {
20681  ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient);
20682  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
20683  }
20684 
20685  while (ppPorts[pDeviceInfo->minChannels] != NULL) {
20686  pDeviceInfo->minChannels += 1;
20687  pDeviceInfo->maxChannels += 1;
20688  }
20689 
20690  ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
20691  ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient);
20692 
20693  (void)pContext;
20694  return MA_SUCCESS;
20695 }
20696 
20697 
20698 static void ma_device_uninit__jack(ma_device* pDevice)
20699 {
20700  ma_context* pContext;
20701 
20702  MA_ASSERT(pDevice != NULL);
20703 
20704  pContext = pDevice->pContext;
20705  MA_ASSERT(pContext != NULL);
20706 
20707  if (pDevice->jack.pClient != NULL) {
20708  ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDevice->jack.pClient);
20709  }
20710 
20711  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
20712  ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks);
20713  }
20714 
20715  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
20716  ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks);
20717  }
20718 
20719  if (pDevice->type == ma_device_type_duplex) {
20720  ma_pcm_rb_uninit(&pDevice->jack.duplexRB);
20721  }
20722 }
20723 
20724 static void ma_device__jack_shutdown_callback(void* pUserData)
20725 {
20726  /* JACK died. Stop the device. */
20727  ma_device* pDevice = (ma_device*)pUserData;
20728  MA_ASSERT(pDevice != NULL);
20729 
20730  ma_device_stop(pDevice);
20731 }
20732 
20733 static int ma_device__jack_buffer_size_callback(ma_jack_nframes_t frameCount, void* pUserData)
20734 {
20735  ma_device* pDevice = (ma_device*)pUserData;
20736  MA_ASSERT(pDevice != NULL);
20737 
20738  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
20739  size_t newBufferSize = frameCount * (pDevice->capture.internalChannels * ma_get_bytes_per_sample(pDevice->capture.internalFormat));
20740  float* pNewBuffer = (float*)ma__calloc_from_callbacks(newBufferSize, &pDevice->pContext->allocationCallbacks);
20741  if (pNewBuffer == NULL) {
20742  return MA_OUT_OF_MEMORY;
20743  }
20744 
20745  ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks);
20746 
20747  pDevice->jack.pIntermediaryBufferCapture = pNewBuffer;
20748  pDevice->playback.internalPeriodSizeInFrames = frameCount;
20749  }
20750 
20751  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
20752  size_t newBufferSize = frameCount * (pDevice->playback.internalChannels * ma_get_bytes_per_sample(pDevice->playback.internalFormat));
20753  float* pNewBuffer = (float*)ma__calloc_from_callbacks(newBufferSize, &pDevice->pContext->allocationCallbacks);
20754  if (pNewBuffer == NULL) {
20755  return MA_OUT_OF_MEMORY;
20756  }
20757 
20758  ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks);
20759 
20760  pDevice->jack.pIntermediaryBufferPlayback = pNewBuffer;
20761  pDevice->playback.internalPeriodSizeInFrames = frameCount;
20762  }
20763 
20764  return 0;
20765 }
20766 
20767 static int ma_device__jack_process_callback(ma_jack_nframes_t frameCount, void* pUserData)
20768 {
20769  ma_device* pDevice;
20770  ma_context* pContext;
20771  ma_uint32 iChannel;
20772 
20773  pDevice = (ma_device*)pUserData;
20774  MA_ASSERT(pDevice != NULL);
20775 
20776  pContext = pDevice->pContext;
20777  MA_ASSERT(pContext != NULL);
20778 
20779  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
20780  /* Channels need to be interleaved. */
20781  for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) {
20782  const float* pSrc = (const float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsCapture[iChannel], frameCount);
20783  if (pSrc != NULL) {
20784  float* pDst = pDevice->jack.pIntermediaryBufferCapture + iChannel;
20785  ma_jack_nframes_t iFrame;
20786  for (iFrame = 0; iFrame < frameCount; ++iFrame) {
20787  *pDst = *pSrc;
20788 
20789  pDst += pDevice->capture.internalChannels;
20790  pSrc += 1;
20791  }
20792  }
20793  }
20794 
20795  if (pDevice->type == ma_device_type_duplex) {
20796  ma_device__handle_duplex_callback_capture(pDevice, frameCount, pDevice->jack.pIntermediaryBufferCapture, &pDevice->jack.duplexRB);
20797  } else {
20798  ma_device__send_frames_to_client(pDevice, frameCount, pDevice->jack.pIntermediaryBufferCapture);
20799  }
20800  }
20801 
20802  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
20803  if (pDevice->type == ma_device_type_duplex) {
20804  ma_device__handle_duplex_callback_playback(pDevice, frameCount, pDevice->jack.pIntermediaryBufferPlayback, &pDevice->jack.duplexRB);
20805  } else {
20806  ma_device__read_frames_from_client(pDevice, frameCount, pDevice->jack.pIntermediaryBufferPlayback);
20807  }
20808 
20809  /* Channels need to be deinterleaved. */
20810  for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) {
20811  float* pDst = (float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsPlayback[iChannel], frameCount);
20812  if (pDst != NULL) {
20813  const float* pSrc = pDevice->jack.pIntermediaryBufferPlayback + iChannel;
20814  ma_jack_nframes_t iFrame;
20815  for (iFrame = 0; iFrame < frameCount; ++iFrame) {
20816  *pDst = *pSrc;
20817 
20818  pDst += 1;
20819  pSrc += pDevice->playback.internalChannels;
20820  }
20821  }
20822  }
20823  }
20824 
20825  return 0;
20826 }
20827 
20828 static ma_result ma_device_init__jack(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
20829 {
20830  ma_result result;
20831  ma_uint32 periods;
20832  ma_uint32 periodSizeInFrames;
20833 
20834  MA_ASSERT(pContext != NULL);
20835  MA_ASSERT(pConfig != NULL);
20836  MA_ASSERT(pDevice != NULL);
20837 
20838  if (pConfig->deviceType == ma_device_type_loopback) {
20840  }
20841 
20842  /* Only supporting default devices with JACK. */
20843  if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID != NULL && pConfig->playback.pDeviceID->jack != 0) ||
20844  ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID != NULL && pConfig->capture.pDeviceID->jack != 0)) {
20845  return MA_NO_DEVICE;
20846  }
20847 
20848  /* No exclusive mode with the JACK backend. */
20852  }
20853 
20854  /* Open the client. */
20855  result = ma_context_open_client__jack(pContext, (ma_jack_client_t**)&pDevice->jack.pClient);
20856  if (result != MA_SUCCESS) {
20857  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", result);
20858  }
20859 
20860  /* Callbacks. */
20861  if (((ma_jack_set_process_callback_proc)pContext->jack.jack_set_process_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_process_callback, pDevice) != 0) {
20862  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set process callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
20863  }
20864  if (((ma_jack_set_buffer_size_callback_proc)pContext->jack.jack_set_buffer_size_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_buffer_size_callback, pDevice) != 0) {
20865  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set buffer size callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
20866  }
20867 
20868  ((ma_jack_on_shutdown_proc)pContext->jack.jack_on_shutdown)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_shutdown_callback, pDevice);
20869 
20870 
20871  /* The buffer size in frames can change. */
20872  periods = pConfig->periods;
20873  periodSizeInFrames = ((ma_jack_get_buffer_size_proc)pContext->jack.jack_get_buffer_size)((ma_jack_client_t*)pDevice->jack.pClient);
20874 
20875  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
20876  const char** ppPorts;
20877 
20879  pDevice->capture.internalChannels = 0;
20880  pDevice->capture.internalSampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient);
20882 
20883  ppPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput);
20884  if (ppPorts == NULL) {
20885  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
20886  }
20887 
20888  while (ppPorts[pDevice->capture.internalChannels] != NULL) {
20889  char name[64];
20890  ma_strcpy_s(name, sizeof(name), "capture");
20891  ma_itoa_s((int)pDevice->capture.internalChannels, name+7, sizeof(name)-7, 10); /* 7 = length of "capture" */
20892 
20893  pDevice->jack.pPortsCapture[pDevice->capture.internalChannels] = ((ma_jack_port_register_proc)pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsInput, 0);
20894  if (pDevice->jack.pPortsCapture[pDevice->capture.internalChannels] == NULL) {
20895  ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
20896  ma_device_uninit__jack(pDevice);
20897  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
20898  }
20899 
20900  pDevice->capture.internalChannels += 1;
20901  }
20902 
20903  ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
20904 
20905  pDevice->capture.internalPeriodSizeInFrames = periodSizeInFrames;
20906  pDevice->capture.internalPeriods = periods;
20907 
20908  pDevice->jack.pIntermediaryBufferCapture = (float*)ma__calloc_from_callbacks(pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels), &pContext->allocationCallbacks);
20909  if (pDevice->jack.pIntermediaryBufferCapture == NULL) {
20910  ma_device_uninit__jack(pDevice);
20911  return MA_OUT_OF_MEMORY;
20912  }
20913  }
20914 
20915  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
20916  const char** ppPorts;
20917 
20919  pDevice->playback.internalChannels = 0;
20920  pDevice->playback.internalSampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient);
20922 
20923  ppPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsInput);
20924  if (ppPorts == NULL) {
20925  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
20926  }
20927 
20928  while (ppPorts[pDevice->playback.internalChannels] != NULL) {
20929  char name[64];
20930  ma_strcpy_s(name, sizeof(name), "playback");
20931  ma_itoa_s((int)pDevice->playback.internalChannels, name+8, sizeof(name)-8, 10); /* 8 = length of "playback" */
20932 
20933  pDevice->jack.pPortsPlayback[pDevice->playback.internalChannels] = ((ma_jack_port_register_proc)pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsOutput, 0);
20934  if (pDevice->jack.pPortsPlayback[pDevice->playback.internalChannels] == NULL) {
20935  ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
20936  ma_device_uninit__jack(pDevice);
20937  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
20938  }
20939 
20940  pDevice->playback.internalChannels += 1;
20941  }
20942 
20943  ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
20944 
20945  pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames;
20946  pDevice->playback.internalPeriods = periods;
20947 
20948  pDevice->jack.pIntermediaryBufferPlayback = (float*)ma__calloc_from_callbacks(pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels), &pContext->allocationCallbacks);
20949  if (pDevice->jack.pIntermediaryBufferPlayback == NULL) {
20950  ma_device_uninit__jack(pDevice);
20951  return MA_OUT_OF_MEMORY;
20952  }
20953  }
20954 
20955  if (pDevice->type == ma_device_type_duplex) {
20957  result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->jack.duplexRB);
20958  if (result != MA_SUCCESS) {
20959  ma_device_uninit__jack(pDevice);
20960  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to initialize ring buffer.", result);
20961  }
20962 
20963  /* We need a period to act as a buffer for cases where the playback and capture device's end up desyncing. */
20964  {
20965  ma_uint32 marginSizeInFrames = rbSizeInFrames / pDevice->capture.internalPeriods;
20966  void* pMarginData;
20967  ma_pcm_rb_acquire_write(&pDevice->jack.duplexRB, &marginSizeInFrames, &pMarginData);
20968  {
20969  MA_ZERO_MEMORY(pMarginData, marginSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
20970  }
20971  ma_pcm_rb_commit_write(&pDevice->jack.duplexRB, marginSizeInFrames, pMarginData);
20972  }
20973  }
20974 
20975  return MA_SUCCESS;
20976 }
20977 
20978 
20979 static ma_result ma_device_start__jack(ma_device* pDevice)
20980 {
20981  ma_context* pContext = pDevice->pContext;
20982  int resultJACK;
20983  size_t i;
20984 
20985  resultJACK = ((ma_jack_activate_proc)pContext->jack.jack_activate)((ma_jack_client_t*)pDevice->jack.pClient);
20986  if (resultJACK != 0) {
20987  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to activate the JACK client.", MA_FAILED_TO_START_BACKEND_DEVICE);
20988  }
20989 
20990  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
20991  const char** ppServerPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput);
20992  if (ppServerPorts == NULL) {
20993  ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
20994  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.", MA_ERROR);
20995  }
20996 
20997  for (i = 0; ppServerPorts[i] != NULL; ++i) {
20998  const char* pServerPort = ppServerPorts[i];
20999  const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.pPortsCapture[i]);
21000 
21001  resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pServerPort, pClientPort);
21002  if (resultJACK != 0) {
21003  ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
21004  ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
21005  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.", MA_ERROR);
21006  }
21007  }
21008 
21009  ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
21010  }
21011 
21012  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
21013  const char** ppServerPorts = ((ma_jack_get_ports_proc)pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsInput);
21014  if (ppServerPorts == NULL) {
21015  ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
21016  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.", MA_ERROR);
21017  }
21018 
21019  for (i = 0; ppServerPorts[i] != NULL; ++i) {
21020  const char* pServerPort = ppServerPorts[i];
21021  const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.pPortsPlayback[i]);
21022 
21023  resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pClientPort, pServerPort);
21024  if (resultJACK != 0) {
21025  ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
21026  ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
21027  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.", MA_ERROR);
21028  }
21029  }
21030 
21031  ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
21032  }
21033 
21034  return MA_SUCCESS;
21035 }
21036 
21037 static ma_result ma_device_stop__jack(ma_device* pDevice)
21038 {
21039  ma_context* pContext = pDevice->pContext;
21040  ma_stop_proc onStop;
21041 
21042  if (((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient) != 0) {
21043  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] An error occurred when deactivating the JACK client.", MA_ERROR);
21044  }
21045 
21046  onStop = pDevice->onStop;
21047  if (onStop) {
21048  onStop(pDevice);
21049  }
21050 
21051  return MA_SUCCESS;
21052 }
21053 
21054 
21055 static ma_result ma_context_uninit__jack(ma_context* pContext)
21056 {
21057  MA_ASSERT(pContext != NULL);
21058  MA_ASSERT(pContext->backend == ma_backend_jack);
21059 
21060  ma_free(pContext->jack.pClientName, &pContext->allocationCallbacks);
21061  pContext->jack.pClientName = NULL;
21062 
21063 #ifndef MA_NO_RUNTIME_LINKING
21064  ma_dlclose(pContext, pContext->jack.jackSO);
21065 #endif
21066 
21067  return MA_SUCCESS;
21068 }
21069 
21070 static ma_result ma_context_init__jack(const ma_context_config* pConfig, ma_context* pContext)
21071 {
21072 #ifndef MA_NO_RUNTIME_LINKING
21073  const char* libjackNames[] = {
21074 #ifdef MA_WIN32
21075  "libjack.dll"
21076 #else
21077  "libjack.so",
21078  "libjack.so.0"
21079 #endif
21080  };
21081  size_t i;
21082 
21083  for (i = 0; i < ma_countof(libjackNames); ++i) {
21084  pContext->jack.jackSO = ma_dlopen(pContext, libjackNames[i]);
21085  if (pContext->jack.jackSO != NULL) {
21086  break;
21087  }
21088  }
21089 
21090  if (pContext->jack.jackSO == NULL) {
21091  return MA_NO_BACKEND;
21092  }
21093 
21094  pContext->jack.jack_client_open = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_open");
21095  pContext->jack.jack_client_close = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_close");
21096  pContext->jack.jack_client_name_size = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_name_size");
21097  pContext->jack.jack_set_process_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_process_callback");
21098  pContext->jack.jack_set_buffer_size_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_buffer_size_callback");
21099  pContext->jack.jack_on_shutdown = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_on_shutdown");
21100  pContext->jack.jack_get_sample_rate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_sample_rate");
21101  pContext->jack.jack_get_buffer_size = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_buffer_size");
21102  pContext->jack.jack_get_ports = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_ports");
21103  pContext->jack.jack_activate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_activate");
21104  pContext->jack.jack_deactivate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_deactivate");
21105  pContext->jack.jack_connect = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_connect");
21106  pContext->jack.jack_port_register = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_register");
21107  pContext->jack.jack_port_name = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_name");
21108  pContext->jack.jack_port_get_buffer = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_get_buffer");
21109  pContext->jack.jack_free = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_free");
21110 #else
21111  /*
21112  This strange assignment system is here just to ensure type safety of miniaudio's function pointer
21113  types. If anything differs slightly the compiler should throw a warning.
21114  */
21115  ma_jack_client_open_proc _jack_client_open = jack_client_open;
21116  ma_jack_client_close_proc _jack_client_close = jack_client_close;
21117  ma_jack_client_name_size_proc _jack_client_name_size = jack_client_name_size;
21118  ma_jack_set_process_callback_proc _jack_set_process_callback = jack_set_process_callback;
21119  ma_jack_set_buffer_size_callback_proc _jack_set_buffer_size_callback = jack_set_buffer_size_callback;
21120  ma_jack_on_shutdown_proc _jack_on_shutdown = jack_on_shutdown;
21121  ma_jack_get_sample_rate_proc _jack_get_sample_rate = jack_get_sample_rate;
21122  ma_jack_get_buffer_size_proc _jack_get_buffer_size = jack_get_buffer_size;
21123  ma_jack_get_ports_proc _jack_get_ports = jack_get_ports;
21124  ma_jack_activate_proc _jack_activate = jack_activate;
21125  ma_jack_deactivate_proc _jack_deactivate = jack_deactivate;
21126  ma_jack_connect_proc _jack_connect = jack_connect;
21127  ma_jack_port_register_proc _jack_port_register = jack_port_register;
21128  ma_jack_port_name_proc _jack_port_name = jack_port_name;
21129  ma_jack_port_get_buffer_proc _jack_port_get_buffer = jack_port_get_buffer;
21130  ma_jack_free_proc _jack_free = jack_free;
21131 
21132  pContext->jack.jack_client_open = (ma_proc)_jack_client_open;
21133  pContext->jack.jack_client_close = (ma_proc)_jack_client_close;
21134  pContext->jack.jack_client_name_size = (ma_proc)_jack_client_name_size;
21135  pContext->jack.jack_set_process_callback = (ma_proc)_jack_set_process_callback;
21136  pContext->jack.jack_set_buffer_size_callback = (ma_proc)_jack_set_buffer_size_callback;
21137  pContext->jack.jack_on_shutdown = (ma_proc)_jack_on_shutdown;
21138  pContext->jack.jack_get_sample_rate = (ma_proc)_jack_get_sample_rate;
21139  pContext->jack.jack_get_buffer_size = (ma_proc)_jack_get_buffer_size;
21140  pContext->jack.jack_get_ports = (ma_proc)_jack_get_ports;
21141  pContext->jack.jack_activate = (ma_proc)_jack_activate;
21142  pContext->jack.jack_deactivate = (ma_proc)_jack_deactivate;
21143  pContext->jack.jack_connect = (ma_proc)_jack_connect;
21144  pContext->jack.jack_port_register = (ma_proc)_jack_port_register;
21145  pContext->jack.jack_port_name = (ma_proc)_jack_port_name;
21146  pContext->jack.jack_port_get_buffer = (ma_proc)_jack_port_get_buffer;
21147  pContext->jack.jack_free = (ma_proc)_jack_free;
21148 #endif
21149 
21150  pContext->isBackendAsynchronous = MA_TRUE;
21151 
21152  pContext->onUninit = ma_context_uninit__jack;
21153  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__jack;
21154  pContext->onEnumDevices = ma_context_enumerate_devices__jack;
21155  pContext->onGetDeviceInfo = ma_context_get_device_info__jack;
21156  pContext->onDeviceInit = ma_device_init__jack;
21157  pContext->onDeviceUninit = ma_device_uninit__jack;
21158  pContext->onDeviceStart = ma_device_start__jack;
21159  pContext->onDeviceStop = ma_device_stop__jack;
21160 
21161  if (pConfig->jack.pClientName != NULL) {
21162  pContext->jack.pClientName = ma_copy_string(pConfig->jack.pClientName, &pContext->allocationCallbacks);
21163  }
21164  pContext->jack.tryStartServer = pConfig->jack.tryStartServer;
21165 
21166  /*
21167  Getting here means the JACK library is installed, but it doesn't necessarily mean it's usable. We need to quickly test this by connecting
21168  a temporary client.
21169  */
21170  {
21171  ma_jack_client_t* pDummyClient;
21172  ma_result result = ma_context_open_client__jack(pContext, &pDummyClient);
21173  if (result != MA_SUCCESS) {
21174  ma_free(pContext->jack.pClientName, &pContext->allocationCallbacks);
21175  #ifndef MA_NO_RUNTIME_LINKING
21176  ma_dlclose(pContext, pContext->jack.jackSO);
21177  #endif
21178  return MA_NO_BACKEND;
21179  }
21180 
21181  ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDummyClient);
21182  }
21183 
21184  return MA_SUCCESS;
21185 }
21186 #endif /* JACK */
21187 
21188 
21189 
21190 /******************************************************************************
21191 
21192 Core Audio Backend
21193 
21194 ******************************************************************************/
21195 #ifdef MA_HAS_COREAUDIO
21196 #include <TargetConditionals.h>
21197 
21198 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1
21199  #define MA_APPLE_MOBILE
21200  #if defined(TARGET_OS_TV) && TARGET_OS_TV == 1
21201  #define MA_APPLE_TV
21202  #endif
21203  #if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
21204  #define MA_APPLE_WATCH
21205  #endif
21206 #else
21207  #define MA_APPLE_DESKTOP
21208 #endif
21209 
21210 #if defined(MA_APPLE_DESKTOP)
21211 #include <CoreAudio/CoreAudio.h>
21212 #else
21213 #include <AVFoundation/AVFoundation.h>
21214 #endif
21215 
21216 #include <AudioToolbox/AudioToolbox.h>
21217 
21218 /* CoreFoundation */
21219 typedef Boolean (* ma_CFStringGetCString_proc)(CFStringRef theString, char* buffer, CFIndex bufferSize, CFStringEncoding encoding);
21220 typedef void (* ma_CFRelease_proc)(CFTypeRef cf);
21221 
21222 /* CoreAudio */
21223 #if defined(MA_APPLE_DESKTOP)
21224 typedef OSStatus (* ma_AudioObjectGetPropertyData_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* ioDataSize, void* outData);
21225 typedef OSStatus (* ma_AudioObjectGetPropertyDataSize_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize);
21226 typedef OSStatus (* ma_AudioObjectSetPropertyData_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData);
21227 typedef OSStatus (* ma_AudioObjectAddPropertyListener_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, AudioObjectPropertyListenerProc inListener, void* inClientData);
21228 typedef OSStatus (* ma_AudioObjectRemovePropertyListener_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, AudioObjectPropertyListenerProc inListener, void* inClientData);
21229 #endif
21230 
21231 /* AudioToolbox */
21232 typedef AudioComponent (* ma_AudioComponentFindNext_proc)(AudioComponent inComponent, const AudioComponentDescription* inDesc);
21233 typedef OSStatus (* ma_AudioComponentInstanceDispose_proc)(AudioComponentInstance inInstance);
21234 typedef OSStatus (* ma_AudioComponentInstanceNew_proc)(AudioComponent inComponent, AudioComponentInstance* outInstance);
21235 typedef OSStatus (* ma_AudioOutputUnitStart_proc)(AudioUnit inUnit);
21236 typedef OSStatus (* ma_AudioOutputUnitStop_proc)(AudioUnit inUnit);
21237 typedef OSStatus (* ma_AudioUnitAddPropertyListener_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitPropertyListenerProc inProc, void* inProcUserData);
21238 typedef OSStatus (* ma_AudioUnitGetPropertyInfo_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32* outDataSize, Boolean* outWriteable);
21239 typedef OSStatus (* ma_AudioUnitGetProperty_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData, UInt32* ioDataSize);
21240 typedef OSStatus (* ma_AudioUnitSetProperty_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void* inData, UInt32 inDataSize);
21241 typedef OSStatus (* ma_AudioUnitInitialize_proc)(AudioUnit inUnit);
21242 typedef OSStatus (* ma_AudioUnitRender_proc)(AudioUnit inUnit, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData);
21243 
21244 
21245 #define MA_COREAUDIO_OUTPUT_BUS 0
21246 #define MA_COREAUDIO_INPUT_BUS 1
21247 
21248 #if defined(MA_APPLE_DESKTOP)
21249 static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_device_type deviceType, ma_bool32 disposePreviousAudioUnit);
21250 #endif
21251 
21252 /*
21253 Core Audio
21254 
21255 So far, Core Audio has been the worst backend to work with due to being both unintuitive and having almost no documentation
21256 apart from comments in the headers (which admittedly are quite good). For my own purposes, and for anybody out there whose
21257 needing to figure out how this darn thing works, I'm going to outline a few things here.
21258 
21259 Since miniaudio is a fairly low-level API, one of the things it needs is control over specific devices, and it needs to be
21260 able to identify whether or not it can be used as playback and/or capture. The AudioObject API is the only one I've seen
21261 that supports this level of detail. There was some public domain sample code I stumbled across that used the AudioComponent
21262 and AudioUnit APIs, but I couldn't see anything that gave low-level control over device selection and capabilities (the
21263 distinction between playback and capture in particular). Therefore, miniaudio is using the AudioObject API.
21264 
21265 Most (all?) functions in the AudioObject API take a AudioObjectID as it's input. This is the device identifier. When
21266 retrieving global information, such as the device list, you use kAudioObjectSystemObject. When retrieving device-specific
21267 data, you pass in the ID for that device. In order to retrieve device-specific IDs you need to enumerate over each of the
21268 devices. This is done using the AudioObjectGetPropertyDataSize() and AudioObjectGetPropertyData() APIs which seem to be
21269 the central APIs for retrieving information about the system and specific devices.
21270 
21271 To use the AudioObjectGetPropertyData() API you need to use the notion of a property address. A property address is a
21272 structure with three variables and is used to identify which property you are getting or setting. The first is the "selector"
21273 which is basically the specific property that you're wanting to retrieve or set. The second is the "scope", which is
21274 typically set to kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyScopeInput for input-specific properties and
21275 kAudioObjectPropertyScopeOutput for output-specific properties. The last is the "element" which is always set to
21276 kAudioObjectPropertyElementMaster in miniaudio's case. I don't know of any cases where this would be set to anything different.
21277 
21278 Back to the earlier issue of device retrieval, you first use the AudioObjectGetPropertyDataSize() API to retrieve the size
21279 of the raw data which is just a list of AudioDeviceID's. You use the kAudioObjectSystemObject AudioObjectID, and a property
21280 address with the kAudioHardwarePropertyDevices selector and the kAudioObjectPropertyScopeGlobal scope. Once you have the
21281 size, allocate a block of memory of that size and then call AudioObjectGetPropertyData(). The data is just a list of
21282 AudioDeviceID's so just do "dataSize/sizeof(AudioDeviceID)" to know the device count.
21283 */
21284 
21285 static ma_result ma_result_from_OSStatus(OSStatus status)
21286 {
21287  switch (status)
21288  {
21289  case noErr: return MA_SUCCESS;
21290  #if defined(MA_APPLE_DESKTOP)
21291  case kAudioHardwareNotRunningError: return MA_DEVICE_NOT_STARTED;
21292  case kAudioHardwareUnspecifiedError: return MA_ERROR;
21293  case kAudioHardwareUnknownPropertyError: return MA_INVALID_ARGS;
21294  case kAudioHardwareBadPropertySizeError: return MA_INVALID_OPERATION;
21295  case kAudioHardwareIllegalOperationError: return MA_INVALID_OPERATION;
21296  case kAudioHardwareBadObjectError: return MA_INVALID_ARGS;
21297  case kAudioHardwareBadDeviceError: return MA_INVALID_ARGS;
21298  case kAudioHardwareBadStreamError: return MA_INVALID_ARGS;
21299  case kAudioHardwareUnsupportedOperationError: return MA_INVALID_OPERATION;
21300  case kAudioDeviceUnsupportedFormatError: return MA_FORMAT_NOT_SUPPORTED;
21301  case kAudioDevicePermissionsError: return MA_ACCESS_DENIED;
21302  #endif
21303  default: return MA_ERROR;
21304  }
21305 }
21306 
21307 #if 0
21308 static ma_channel ma_channel_from_AudioChannelBitmap(AudioChannelBitmap bit)
21309 {
21310  switch (bit)
21311  {
21312  case kAudioChannelBit_Left: return MA_CHANNEL_LEFT;
21313  case kAudioChannelBit_Right: return MA_CHANNEL_RIGHT;
21314  case kAudioChannelBit_Center: return MA_CHANNEL_FRONT_CENTER;
21315  case kAudioChannelBit_LFEScreen: return MA_CHANNEL_LFE;
21316  case kAudioChannelBit_LeftSurround: return MA_CHANNEL_BACK_LEFT;
21317  case kAudioChannelBit_RightSurround: return MA_CHANNEL_BACK_RIGHT;
21318  case kAudioChannelBit_LeftCenter: return MA_CHANNEL_FRONT_LEFT_CENTER;
21319  case kAudioChannelBit_RightCenter: return MA_CHANNEL_FRONT_RIGHT_CENTER;
21320  case kAudioChannelBit_CenterSurround: return MA_CHANNEL_BACK_CENTER;
21321  case kAudioChannelBit_LeftSurroundDirect: return MA_CHANNEL_SIDE_LEFT;
21322  case kAudioChannelBit_RightSurroundDirect: return MA_CHANNEL_SIDE_RIGHT;
21323  case kAudioChannelBit_TopCenterSurround: return MA_CHANNEL_TOP_CENTER;
21324  case kAudioChannelBit_VerticalHeightLeft: return MA_CHANNEL_TOP_FRONT_LEFT;
21325  case kAudioChannelBit_VerticalHeightCenter: return MA_CHANNEL_TOP_FRONT_CENTER;
21326  case kAudioChannelBit_VerticalHeightRight: return MA_CHANNEL_TOP_FRONT_RIGHT;
21327  case kAudioChannelBit_TopBackLeft: return MA_CHANNEL_TOP_BACK_LEFT;
21328  case kAudioChannelBit_TopBackCenter: return MA_CHANNEL_TOP_BACK_CENTER;
21329  case kAudioChannelBit_TopBackRight: return MA_CHANNEL_TOP_BACK_RIGHT;
21330  default: return MA_CHANNEL_NONE;
21331  }
21332 }
21333 #endif
21334 
21335 static ma_result ma_format_from_AudioStreamBasicDescription(const AudioStreamBasicDescription* pDescription, ma_format* pFormatOut)
21336 {
21337  MA_ASSERT(pDescription != NULL);
21338  MA_ASSERT(pFormatOut != NULL);
21339 
21340  *pFormatOut = ma_format_unknown; /* Safety. */
21341 
21342  /* There's a few things miniaudio doesn't support. */
21343  if (pDescription->mFormatID != kAudioFormatLinearPCM) {
21344  return MA_FORMAT_NOT_SUPPORTED;
21345  }
21346 
21347  /* We don't support any non-packed formats that are aligned high. */
21348  if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) != 0) {
21349  return MA_FORMAT_NOT_SUPPORTED;
21350  }
21351 
21352  /* Only supporting native-endian. */
21353  if ((ma_is_little_endian() && (pDescription->mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) || (ma_is_big_endian() && (pDescription->mFormatFlags & kAudioFormatFlagIsBigEndian) == 0)) {
21354  return MA_FORMAT_NOT_SUPPORTED;
21355  }
21356 
21357  /* We are not currently supporting non-interleaved formats (this will be added in a future version of miniaudio). */
21358  /*if ((pDescription->mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0) {
21359  return MA_FORMAT_NOT_SUPPORTED;
21360  }*/
21361 
21362  if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0) {
21363  if (pDescription->mBitsPerChannel == 32) {
21364  *pFormatOut = ma_format_f32;
21365  return MA_SUCCESS;
21366  }
21367  } else {
21368  if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) != 0) {
21369  if (pDescription->mBitsPerChannel == 16) {
21370  *pFormatOut = ma_format_s16;
21371  return MA_SUCCESS;
21372  } else if (pDescription->mBitsPerChannel == 24) {
21373  if (pDescription->mBytesPerFrame == (pDescription->mBitsPerChannel/8 * pDescription->mChannelsPerFrame)) {
21374  *pFormatOut = ma_format_s24;
21375  return MA_SUCCESS;
21376  } else {
21377  if (pDescription->mBytesPerFrame/pDescription->mChannelsPerFrame == sizeof(ma_int32)) {
21378  /* TODO: Implement ma_format_s24_32. */
21380  /*return MA_SUCCESS;*/
21381  return MA_FORMAT_NOT_SUPPORTED;
21382  }
21383  }
21384  } else if (pDescription->mBitsPerChannel == 32) {
21385  *pFormatOut = ma_format_s32;
21386  return MA_SUCCESS;
21387  }
21388  } else {
21389  if (pDescription->mBitsPerChannel == 8) {
21390  *pFormatOut = ma_format_u8;
21391  return MA_SUCCESS;
21392  }
21393  }
21394  }
21395 
21396  /* Getting here means the format is not supported. */
21397  return MA_FORMAT_NOT_SUPPORTED;
21398 }
21399 
21400 #if defined(MA_APPLE_DESKTOP)
21401 static ma_channel ma_channel_from_AudioChannelLabel(AudioChannelLabel label)
21402 {
21403  switch (label)
21404  {
21405  case kAudioChannelLabel_Unknown: return MA_CHANNEL_NONE;
21406  case kAudioChannelLabel_Unused: return MA_CHANNEL_NONE;
21407  case kAudioChannelLabel_UseCoordinates: return MA_CHANNEL_NONE;
21408  case kAudioChannelLabel_Left: return MA_CHANNEL_LEFT;
21409  case kAudioChannelLabel_Right: return MA_CHANNEL_RIGHT;
21410  case kAudioChannelLabel_Center: return MA_CHANNEL_FRONT_CENTER;
21411  case kAudioChannelLabel_LFEScreen: return MA_CHANNEL_LFE;
21412  case kAudioChannelLabel_LeftSurround: return MA_CHANNEL_BACK_LEFT;
21413  case kAudioChannelLabel_RightSurround: return MA_CHANNEL_BACK_RIGHT;
21414  case kAudioChannelLabel_LeftCenter: return MA_CHANNEL_FRONT_LEFT_CENTER;
21415  case kAudioChannelLabel_RightCenter: return MA_CHANNEL_FRONT_RIGHT_CENTER;
21416  case kAudioChannelLabel_CenterSurround: return MA_CHANNEL_BACK_CENTER;
21417  case kAudioChannelLabel_LeftSurroundDirect: return MA_CHANNEL_SIDE_LEFT;
21418  case kAudioChannelLabel_RightSurroundDirect: return MA_CHANNEL_SIDE_RIGHT;
21419  case kAudioChannelLabel_TopCenterSurround: return MA_CHANNEL_TOP_CENTER;
21420  case kAudioChannelLabel_VerticalHeightLeft: return MA_CHANNEL_TOP_FRONT_LEFT;
21421  case kAudioChannelLabel_VerticalHeightCenter: return MA_CHANNEL_TOP_FRONT_CENTER;
21422  case kAudioChannelLabel_VerticalHeightRight: return MA_CHANNEL_TOP_FRONT_RIGHT;
21423  case kAudioChannelLabel_TopBackLeft: return MA_CHANNEL_TOP_BACK_LEFT;
21424  case kAudioChannelLabel_TopBackCenter: return MA_CHANNEL_TOP_BACK_CENTER;
21425  case kAudioChannelLabel_TopBackRight: return MA_CHANNEL_TOP_BACK_RIGHT;
21426  case kAudioChannelLabel_RearSurroundLeft: return MA_CHANNEL_BACK_LEFT;
21427  case kAudioChannelLabel_RearSurroundRight: return MA_CHANNEL_BACK_RIGHT;
21428  case kAudioChannelLabel_LeftWide: return MA_CHANNEL_SIDE_LEFT;
21429  case kAudioChannelLabel_RightWide: return MA_CHANNEL_SIDE_RIGHT;
21430  case kAudioChannelLabel_LFE2: return MA_CHANNEL_LFE;
21431  case kAudioChannelLabel_LeftTotal: return MA_CHANNEL_LEFT;
21432  case kAudioChannelLabel_RightTotal: return MA_CHANNEL_RIGHT;
21433  case kAudioChannelLabel_HearingImpaired: return MA_CHANNEL_NONE;
21434  case kAudioChannelLabel_Narration: return MA_CHANNEL_MONO;
21435  case kAudioChannelLabel_Mono: return MA_CHANNEL_MONO;
21436  case kAudioChannelLabel_DialogCentricMix: return MA_CHANNEL_MONO;
21437  case kAudioChannelLabel_CenterSurroundDirect: return MA_CHANNEL_BACK_CENTER;
21438  case kAudioChannelLabel_Haptic: return MA_CHANNEL_NONE;
21439  case kAudioChannelLabel_Ambisonic_W: return MA_CHANNEL_NONE;
21440  case kAudioChannelLabel_Ambisonic_X: return MA_CHANNEL_NONE;
21441  case kAudioChannelLabel_Ambisonic_Y: return MA_CHANNEL_NONE;
21442  case kAudioChannelLabel_Ambisonic_Z: return MA_CHANNEL_NONE;
21443  case kAudioChannelLabel_MS_Mid: return MA_CHANNEL_LEFT;
21444  case kAudioChannelLabel_MS_Side: return MA_CHANNEL_RIGHT;
21445  case kAudioChannelLabel_XY_X: return MA_CHANNEL_LEFT;
21446  case kAudioChannelLabel_XY_Y: return MA_CHANNEL_RIGHT;
21447  case kAudioChannelLabel_HeadphonesLeft: return MA_CHANNEL_LEFT;
21448  case kAudioChannelLabel_HeadphonesRight: return MA_CHANNEL_RIGHT;
21449  case kAudioChannelLabel_ClickTrack: return MA_CHANNEL_NONE;
21450  case kAudioChannelLabel_ForeignLanguage: return MA_CHANNEL_NONE;
21451  case kAudioChannelLabel_Discrete: return MA_CHANNEL_NONE;
21452  case kAudioChannelLabel_Discrete_0: return MA_CHANNEL_AUX_0;
21453  case kAudioChannelLabel_Discrete_1: return MA_CHANNEL_AUX_1;
21454  case kAudioChannelLabel_Discrete_2: return MA_CHANNEL_AUX_2;
21455  case kAudioChannelLabel_Discrete_3: return MA_CHANNEL_AUX_3;
21456  case kAudioChannelLabel_Discrete_4: return MA_CHANNEL_AUX_4;
21457  case kAudioChannelLabel_Discrete_5: return MA_CHANNEL_AUX_5;
21458  case kAudioChannelLabel_Discrete_6: return MA_CHANNEL_AUX_6;
21459  case kAudioChannelLabel_Discrete_7: return MA_CHANNEL_AUX_7;
21460  case kAudioChannelLabel_Discrete_8: return MA_CHANNEL_AUX_8;
21461  case kAudioChannelLabel_Discrete_9: return MA_CHANNEL_AUX_9;
21462  case kAudioChannelLabel_Discrete_10: return MA_CHANNEL_AUX_10;
21463  case kAudioChannelLabel_Discrete_11: return MA_CHANNEL_AUX_11;
21464  case kAudioChannelLabel_Discrete_12: return MA_CHANNEL_AUX_12;
21465  case kAudioChannelLabel_Discrete_13: return MA_CHANNEL_AUX_13;
21466  case kAudioChannelLabel_Discrete_14: return MA_CHANNEL_AUX_14;
21467  case kAudioChannelLabel_Discrete_15: return MA_CHANNEL_AUX_15;
21468  case kAudioChannelLabel_Discrete_65535: return MA_CHANNEL_NONE;
21469 
21470  #if 0 /* Introduced in a later version of macOS. */
21471  case kAudioChannelLabel_HOA_ACN: return MA_CHANNEL_NONE;
21472  case kAudioChannelLabel_HOA_ACN_0: return MA_CHANNEL_AUX_0;
21473  case kAudioChannelLabel_HOA_ACN_1: return MA_CHANNEL_AUX_1;
21474  case kAudioChannelLabel_HOA_ACN_2: return MA_CHANNEL_AUX_2;
21475  case kAudioChannelLabel_HOA_ACN_3: return MA_CHANNEL_AUX_3;
21476  case kAudioChannelLabel_HOA_ACN_4: return MA_CHANNEL_AUX_4;
21477  case kAudioChannelLabel_HOA_ACN_5: return MA_CHANNEL_AUX_5;
21478  case kAudioChannelLabel_HOA_ACN_6: return MA_CHANNEL_AUX_6;
21479  case kAudioChannelLabel_HOA_ACN_7: return MA_CHANNEL_AUX_7;
21480  case kAudioChannelLabel_HOA_ACN_8: return MA_CHANNEL_AUX_8;
21481  case kAudioChannelLabel_HOA_ACN_9: return MA_CHANNEL_AUX_9;
21482  case kAudioChannelLabel_HOA_ACN_10: return MA_CHANNEL_AUX_10;
21483  case kAudioChannelLabel_HOA_ACN_11: return MA_CHANNEL_AUX_11;
21484  case kAudioChannelLabel_HOA_ACN_12: return MA_CHANNEL_AUX_12;
21485  case kAudioChannelLabel_HOA_ACN_13: return MA_CHANNEL_AUX_13;
21486  case kAudioChannelLabel_HOA_ACN_14: return MA_CHANNEL_AUX_14;
21487  case kAudioChannelLabel_HOA_ACN_15: return MA_CHANNEL_AUX_15;
21488  case kAudioChannelLabel_HOA_ACN_65024: return MA_CHANNEL_NONE;
21489  #endif
21490 
21491  default: return MA_CHANNEL_NONE;
21492  }
21493 }
21494 
21495 static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* pChannelLayout, ma_channel channelMap[MA_MAX_CHANNELS])
21496 {
21497  MA_ASSERT(pChannelLayout != NULL);
21498 
21499  if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
21500  UInt32 iChannel;
21501  for (iChannel = 0; iChannel < pChannelLayout->mNumberChannelDescriptions; ++iChannel) {
21502  channelMap[iChannel] = ma_channel_from_AudioChannelLabel(pChannelLayout->mChannelDescriptions[iChannel].mChannelLabel);
21503  }
21504  } else
21505 #if 0
21506  if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {
21507  /* This is the same kind of system that's used by Windows audio APIs. */
21508  UInt32 iChannel = 0;
21509  UInt32 iBit;
21510  AudioChannelBitmap bitmap = pChannelLayout->mChannelBitmap;
21511  for (iBit = 0; iBit < 32; ++iBit) {
21512  AudioChannelBitmap bit = bitmap & (1 << iBit);
21513  if (bit != 0) {
21514  channelMap[iChannel++] = ma_channel_from_AudioChannelBit(bit);
21515  }
21516  }
21517  } else
21518 #endif
21519  {
21520  /*
21521  Need to use the tag to determine the channel map. For now I'm just assuming a default channel map, but later on this should
21522  be updated to determine the mapping based on the tag.
21523  */
21524  UInt32 channelCount = AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag);
21525  switch (pChannelLayout->mChannelLayoutTag)
21526  {
21527  case kAudioChannelLayoutTag_Mono:
21528  case kAudioChannelLayoutTag_Stereo:
21529  case kAudioChannelLayoutTag_StereoHeadphones:
21530  case kAudioChannelLayoutTag_MatrixStereo:
21531  case kAudioChannelLayoutTag_MidSide:
21532  case kAudioChannelLayoutTag_XY:
21533  case kAudioChannelLayoutTag_Binaural:
21534  case kAudioChannelLayoutTag_Ambisonic_B_Format:
21535  {
21537  } break;
21538 
21539  case kAudioChannelLayoutTag_Octagonal:
21540  {
21541  channelMap[7] = MA_CHANNEL_SIDE_RIGHT;
21542  channelMap[6] = MA_CHANNEL_SIDE_LEFT;
21543  } /* Intentional fallthrough. */
21544  case kAudioChannelLayoutTag_Hexagonal:
21545  {
21546  channelMap[5] = MA_CHANNEL_BACK_CENTER;
21547  } /* Intentional fallthrough. */
21548  case kAudioChannelLayoutTag_Pentagonal:
21549  {
21550  channelMap[4] = MA_CHANNEL_FRONT_CENTER;
21551  } /* Intentional fallghrough. */
21552  case kAudioChannelLayoutTag_Quadraphonic:
21553  {
21554  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
21555  channelMap[2] = MA_CHANNEL_BACK_LEFT;
21556  channelMap[1] = MA_CHANNEL_RIGHT;
21557  channelMap[0] = MA_CHANNEL_LEFT;
21558  } break;
21559 
21560  /* TODO: Add support for more tags here. */
21561 
21562  default:
21563  {
21565  } break;
21566  }
21567  }
21568 
21569  return MA_SUCCESS;
21570 }
21571 
21572 static ma_result ma_get_device_object_ids__coreaudio(ma_context* pContext, UInt32* pDeviceCount, AudioObjectID** ppDeviceObjectIDs) /* NOTE: Free the returned buffer with ma_free(). */
21573 {
21574  AudioObjectPropertyAddress propAddressDevices;
21575  UInt32 deviceObjectsDataSize;
21576  OSStatus status;
21577  AudioObjectID* pDeviceObjectIDs;
21578 
21579  MA_ASSERT(pContext != NULL);
21580  MA_ASSERT(pDeviceCount != NULL);
21581  MA_ASSERT(ppDeviceObjectIDs != NULL);
21582 
21583  /* Safety. */
21584  *pDeviceCount = 0;
21585  *ppDeviceObjectIDs = NULL;
21586 
21587  propAddressDevices.mSelector = kAudioHardwarePropertyDevices;
21588  propAddressDevices.mScope = kAudioObjectPropertyScopeGlobal;
21589  propAddressDevices.mElement = kAudioObjectPropertyElementMaster;
21590 
21591  status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(kAudioObjectSystemObject, &propAddressDevices, 0, NULL, &deviceObjectsDataSize);
21592  if (status != noErr) {
21593  return ma_result_from_OSStatus(status);
21594  }
21595 
21596  pDeviceObjectIDs = (AudioObjectID*)ma_malloc(deviceObjectsDataSize, &pContext->allocationCallbacks);
21597  if (pDeviceObjectIDs == NULL) {
21598  return MA_OUT_OF_MEMORY;
21599  }
21600 
21601  status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject, &propAddressDevices, 0, NULL, &deviceObjectsDataSize, pDeviceObjectIDs);
21602  if (status != noErr) {
21603  ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
21604  return ma_result_from_OSStatus(status);
21605  }
21606 
21607  *pDeviceCount = deviceObjectsDataSize / sizeof(AudioObjectID);
21608  *ppDeviceObjectIDs = pDeviceObjectIDs;
21609 
21610  return MA_SUCCESS;
21611 }
21612 
21613 static ma_result ma_get_AudioObject_uid_as_CFStringRef(ma_context* pContext, AudioObjectID objectID, CFStringRef* pUID)
21614 {
21615  AudioObjectPropertyAddress propAddress;
21616  UInt32 dataSize;
21617  OSStatus status;
21618 
21619  MA_ASSERT(pContext != NULL);
21620 
21621  propAddress.mSelector = kAudioDevicePropertyDeviceUID;
21622  propAddress.mScope = kAudioObjectPropertyScopeGlobal;
21623  propAddress.mElement = kAudioObjectPropertyElementMaster;
21624 
21625  dataSize = sizeof(*pUID);
21626  status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, pUID);
21627  if (status != noErr) {
21628  return ma_result_from_OSStatus(status);
21629  }
21630 
21631  return MA_SUCCESS;
21632 }
21633 
21634 static ma_result ma_get_AudioObject_uid(ma_context* pContext, AudioObjectID objectID, size_t bufferSize, char* bufferOut)
21635 {
21636  CFStringRef uid;
21637  ma_result result;
21638 
21639  MA_ASSERT(pContext != NULL);
21640 
21641  result = ma_get_AudioObject_uid_as_CFStringRef(pContext, objectID, &uid);
21642  if (result != MA_SUCCESS) {
21643  return result;
21644  }
21645 
21646  if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(uid, bufferOut, bufferSize, kCFStringEncodingUTF8)) {
21647  return MA_ERROR;
21648  }
21649 
21650  ((ma_CFRelease_proc)pContext->coreaudio.CFRelease)(uid);
21651  return MA_SUCCESS;
21652 }
21653 
21654 static ma_result ma_get_AudioObject_name(ma_context* pContext, AudioObjectID objectID, size_t bufferSize, char* bufferOut)
21655 {
21656  AudioObjectPropertyAddress propAddress;
21657  CFStringRef deviceName = NULL;
21658  UInt32 dataSize;
21659  OSStatus status;
21660 
21661  MA_ASSERT(pContext != NULL);
21662 
21663  propAddress.mSelector = kAudioDevicePropertyDeviceNameCFString;
21664  propAddress.mScope = kAudioObjectPropertyScopeGlobal;
21665  propAddress.mElement = kAudioObjectPropertyElementMaster;
21666 
21667  dataSize = sizeof(deviceName);
21668  status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, &deviceName);
21669  if (status != noErr) {
21670  return ma_result_from_OSStatus(status);
21671  }
21672 
21673  if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(deviceName, bufferOut, bufferSize, kCFStringEncodingUTF8)) {
21674  return MA_ERROR;
21675  }
21676 
21677  ((ma_CFRelease_proc)pContext->coreaudio.CFRelease)(deviceName);
21678  return MA_SUCCESS;
21679 }
21680 
21681 static ma_bool32 ma_does_AudioObject_support_scope(ma_context* pContext, AudioObjectID deviceObjectID, AudioObjectPropertyScope scope)
21682 {
21683  AudioObjectPropertyAddress propAddress;
21684  UInt32 dataSize;
21685  OSStatus status;
21686  AudioBufferList* pBufferList;
21687  ma_bool32 isSupported;
21688 
21689  MA_ASSERT(pContext != NULL);
21690 
21691  /* To know whether or not a device is an input device we need ot look at the stream configuration. If it has an output channel it's a playback device. */
21692  propAddress.mSelector = kAudioDevicePropertyStreamConfiguration;
21693  propAddress.mScope = scope;
21694  propAddress.mElement = kAudioObjectPropertyElementMaster;
21695 
21696  status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
21697  if (status != noErr) {
21698  return MA_FALSE;
21699  }
21700 
21701  pBufferList = (AudioBufferList*)ma__malloc_from_callbacks(dataSize, &pContext->allocationCallbacks);
21702  if (pBufferList == NULL) {
21703  return MA_FALSE; /* Out of memory. */
21704  }
21705 
21706  status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pBufferList);
21707  if (status != noErr) {
21708  ma__free_from_callbacks(pBufferList, &pContext->allocationCallbacks);
21709  return MA_FALSE;
21710  }
21711 
21712  isSupported = MA_FALSE;
21713  if (pBufferList->mNumberBuffers > 0) {
21714  isSupported = MA_TRUE;
21715  }
21716 
21717  ma__free_from_callbacks(pBufferList, &pContext->allocationCallbacks);
21718  return isSupported;
21719 }
21720 
21721 static ma_bool32 ma_does_AudioObject_support_playback(ma_context* pContext, AudioObjectID deviceObjectID)
21722 {
21723  return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeOutput);
21724 }
21725 
21726 static ma_bool32 ma_does_AudioObject_support_capture(ma_context* pContext, AudioObjectID deviceObjectID)
21727 {
21728  return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeInput);
21729 }
21730 
21731 
21732 static ma_result ma_get_AudioObject_stream_descriptions(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, UInt32* pDescriptionCount, AudioStreamRangedDescription** ppDescriptions) /* NOTE: Free the returned pointer with ma_free(). */
21733 {
21734  AudioObjectPropertyAddress propAddress;
21735  UInt32 dataSize;
21736  OSStatus status;
21737  AudioStreamRangedDescription* pDescriptions;
21738 
21739  MA_ASSERT(pContext != NULL);
21740  MA_ASSERT(pDescriptionCount != NULL);
21741  MA_ASSERT(ppDescriptions != NULL);
21742 
21743  /*
21744  TODO: Experiment with kAudioStreamPropertyAvailablePhysicalFormats instead of (or in addition to) kAudioStreamPropertyAvailableVirtualFormats. My
21745  MacBook Pro uses s24/32 format, however, which miniaudio does not currently support.
21746  */
21747  propAddress.mSelector = kAudioStreamPropertyAvailableVirtualFormats; /*kAudioStreamPropertyAvailablePhysicalFormats;*/
21748  propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
21749  propAddress.mElement = kAudioObjectPropertyElementMaster;
21750 
21751  status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
21752  if (status != noErr) {
21753  return ma_result_from_OSStatus(status);
21754  }
21755 
21756  pDescriptions = (AudioStreamRangedDescription*)ma_malloc(dataSize, &pContext->allocationCallbacks);
21757  if (pDescriptions == NULL) {
21758  return MA_OUT_OF_MEMORY;
21759  }
21760 
21761  status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pDescriptions);
21762  if (status != noErr) {
21763  ma_free(pDescriptions, &pContext->allocationCallbacks);
21764  return ma_result_from_OSStatus(status);
21765  }
21766 
21767  *pDescriptionCount = dataSize / sizeof(*pDescriptions);
21768  *ppDescriptions = pDescriptions;
21769  return MA_SUCCESS;
21770 }
21771 
21772 
21773 static ma_result ma_get_AudioObject_channel_layout(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, AudioChannelLayout** ppChannelLayout) /* NOTE: Free the returned pointer with ma_free(). */
21774 {
21775  AudioObjectPropertyAddress propAddress;
21776  UInt32 dataSize;
21777  OSStatus status;
21778  AudioChannelLayout* pChannelLayout;
21779 
21780  MA_ASSERT(pContext != NULL);
21781  MA_ASSERT(ppChannelLayout != NULL);
21782 
21783  *ppChannelLayout = NULL; /* Safety. */
21784 
21785  propAddress.mSelector = kAudioDevicePropertyPreferredChannelLayout;
21786  propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
21787  propAddress.mElement = kAudioObjectPropertyElementMaster;
21788 
21789  status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
21790  if (status != noErr) {
21791  return ma_result_from_OSStatus(status);
21792  }
21793 
21794  pChannelLayout = (AudioChannelLayout*)ma_malloc(dataSize, &pContext->allocationCallbacks);
21795  if (pChannelLayout == NULL) {
21796  return MA_OUT_OF_MEMORY;
21797  }
21798 
21799  status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pChannelLayout);
21800  if (status != noErr) {
21801  ma_free(pChannelLayout, &pContext->allocationCallbacks);
21802  return ma_result_from_OSStatus(status);
21803  }
21804 
21805  *ppChannelLayout = pChannelLayout;
21806  return MA_SUCCESS;
21807 }
21808 
21809 static ma_result ma_get_AudioObject_channel_count(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32* pChannelCount)
21810 {
21811  AudioChannelLayout* pChannelLayout;
21812  ma_result result;
21813 
21814  MA_ASSERT(pContext != NULL);
21815  MA_ASSERT(pChannelCount != NULL);
21816 
21817  *pChannelCount = 0; /* Safety. */
21818 
21819  result = ma_get_AudioObject_channel_layout(pContext, deviceObjectID, deviceType, &pChannelLayout);
21820  if (result != MA_SUCCESS) {
21821  return result;
21822  }
21823 
21824  if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
21825  *pChannelCount = pChannelLayout->mNumberChannelDescriptions;
21826  } else if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {
21827  *pChannelCount = ma_count_set_bits(pChannelLayout->mChannelBitmap);
21828  } else {
21829  *pChannelCount = AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag);
21830  }
21831 
21832  ma_free(pChannelLayout, &pContext->allocationCallbacks);
21833  return MA_SUCCESS;
21834 }
21835 
21836 #if 0
21837 static ma_result ma_get_AudioObject_channel_map(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_channel channelMap[MA_MAX_CHANNELS])
21838 {
21839  AudioChannelLayout* pChannelLayout;
21840  ma_result result;
21841 
21842  MA_ASSERT(pContext != NULL);
21843 
21844  result = ma_get_AudioObject_channel_layout(pContext, deviceObjectID, deviceType, &pChannelLayout);
21845  if (result != MA_SUCCESS) {
21846  return result; /* Rather than always failing here, would it be more robust to simply assume a default? */
21847  }
21848 
21849  result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, channelMap);
21850  if (result != MA_SUCCESS) {
21851  ma_free(pChannelLayout, &pContext->allocationCallbacks);
21852  return result;
21853  }
21854 
21855  ma_free(pChannelLayout, &pContext->allocationCallbacks);
21856  return result;
21857 }
21858 #endif
21859 
21860 static ma_result ma_get_AudioObject_sample_rates(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, UInt32* pSampleRateRangesCount, AudioValueRange** ppSampleRateRanges) /* NOTE: Free the returned pointer with ma_free(). */
21861 {
21862  AudioObjectPropertyAddress propAddress;
21863  UInt32 dataSize;
21864  OSStatus status;
21865  AudioValueRange* pSampleRateRanges;
21866 
21867  MA_ASSERT(pContext != NULL);
21868  MA_ASSERT(pSampleRateRangesCount != NULL);
21869  MA_ASSERT(ppSampleRateRanges != NULL);
21870 
21871  /* Safety. */
21872  *pSampleRateRangesCount = 0;
21873  *ppSampleRateRanges = NULL;
21874 
21875  propAddress.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
21876  propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
21877  propAddress.mElement = kAudioObjectPropertyElementMaster;
21878 
21879  status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
21880  if (status != noErr) {
21881  return ma_result_from_OSStatus(status);
21882  }
21883 
21884  pSampleRateRanges = (AudioValueRange*)ma_malloc(dataSize, &pContext->allocationCallbacks);
21885  if (pSampleRateRanges == NULL) {
21886  return MA_OUT_OF_MEMORY;
21887  }
21888 
21889  status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pSampleRateRanges);
21890  if (status != noErr) {
21891  ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
21892  return ma_result_from_OSStatus(status);
21893  }
21894 
21895  *pSampleRateRangesCount = dataSize / sizeof(*pSampleRateRanges);
21896  *ppSampleRateRanges = pSampleRateRanges;
21897  return MA_SUCCESS;
21898 }
21899 
21900 #if 0
21901 static ma_result ma_get_AudioObject_get_closest_sample_rate(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32 sampleRateIn, ma_uint32* pSampleRateOut)
21902 {
21903  UInt32 sampleRateRangeCount;
21904  AudioValueRange* pSampleRateRanges;
21905  ma_result result;
21906 
21907  MA_ASSERT(pContext != NULL);
21908  MA_ASSERT(pSampleRateOut != NULL);
21909 
21910  *pSampleRateOut = 0; /* Safety. */
21911 
21912  result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges);
21913  if (result != MA_SUCCESS) {
21914  return result;
21915  }
21916 
21917  if (sampleRateRangeCount == 0) {
21918  ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
21919  return MA_ERROR; /* Should never hit this case should we? */
21920  }
21921 
21922  if (sampleRateIn == 0) {
21923  /* Search in order of miniaudio's preferred priority. */
21924  UInt32 iMALSampleRate;
21925  for (iMALSampleRate = 0; iMALSampleRate < ma_countof(g_maStandardSampleRatePriorities); ++iMALSampleRate) {
21926  ma_uint32 malSampleRate = g_maStandardSampleRatePriorities[iMALSampleRate];
21927  UInt32 iCASampleRate;
21928  for (iCASampleRate = 0; iCASampleRate < sampleRateRangeCount; ++iCASampleRate) {
21929  AudioValueRange caSampleRate = pSampleRateRanges[iCASampleRate];
21930  if (caSampleRate.mMinimum <= malSampleRate && caSampleRate.mMaximum >= malSampleRate) {
21931  *pSampleRateOut = malSampleRate;
21932  ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
21933  return MA_SUCCESS;
21934  }
21935  }
21936  }
21937 
21938  /*
21939  If we get here it means none of miniaudio's standard sample rates matched any of the supported sample rates from the device. In this
21940  case we just fall back to the first one reported by Core Audio.
21941  */
21942  MA_ASSERT(sampleRateRangeCount > 0);
21943 
21944  *pSampleRateOut = pSampleRateRanges[0].mMinimum;
21945  ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
21946  return MA_SUCCESS;
21947  } else {
21948  /* Find the closest match to this sample rate. */
21949  UInt32 currentAbsoluteDifference = INT32_MAX;
21950  UInt32 iCurrentClosestRange = (UInt32)-1;
21951  UInt32 iRange;
21952  for (iRange = 0; iRange < sampleRateRangeCount; ++iRange) {
21953  if (pSampleRateRanges[iRange].mMinimum <= sampleRateIn && pSampleRateRanges[iRange].mMaximum >= sampleRateIn) {
21954  *pSampleRateOut = sampleRateIn;
21955  ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
21956  return MA_SUCCESS;
21957  } else {
21958  UInt32 absoluteDifference;
21959  if (pSampleRateRanges[iRange].mMinimum > sampleRateIn) {
21960  absoluteDifference = pSampleRateRanges[iRange].mMinimum - sampleRateIn;
21961  } else {
21962  absoluteDifference = sampleRateIn - pSampleRateRanges[iRange].mMaximum;
21963  }
21964 
21965  if (currentAbsoluteDifference > absoluteDifference) {
21966  currentAbsoluteDifference = absoluteDifference;
21967  iCurrentClosestRange = iRange;
21968  }
21969  }
21970  }
21971 
21972  MA_ASSERT(iCurrentClosestRange != (UInt32)-1);
21973 
21974  *pSampleRateOut = pSampleRateRanges[iCurrentClosestRange].mMinimum;
21975  ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
21976  return MA_SUCCESS;
21977  }
21978 
21979  /* Should never get here, but it would mean we weren't able to find any suitable sample rates. */
21980  /*ma_free(pSampleRateRanges, &pContext->allocationCallbacks);*/
21981  /*return MA_ERROR;*/
21982 }
21983 #endif
21984 
21985 static ma_result ma_get_AudioObject_closest_buffer_size_in_frames(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32 bufferSizeInFramesIn, ma_uint32* pBufferSizeInFramesOut)
21986 {
21987  AudioObjectPropertyAddress propAddress;
21988  AudioValueRange bufferSizeRange;
21989  UInt32 dataSize;
21990  OSStatus status;
21991 
21992  MA_ASSERT(pContext != NULL);
21993  MA_ASSERT(pBufferSizeInFramesOut != NULL);
21994 
21995  *pBufferSizeInFramesOut = 0; /* Safety. */
21996 
21997  propAddress.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
21998  propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
21999  propAddress.mElement = kAudioObjectPropertyElementMaster;
22000 
22001  dataSize = sizeof(bufferSizeRange);
22002  status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, &bufferSizeRange);
22003  if (status != noErr) {
22004  return ma_result_from_OSStatus(status);
22005  }
22006 
22007  /* This is just a clamp. */
22008  if (bufferSizeInFramesIn < bufferSizeRange.mMinimum) {
22009  *pBufferSizeInFramesOut = (ma_uint32)bufferSizeRange.mMinimum;
22010  } else if (bufferSizeInFramesIn > bufferSizeRange.mMaximum) {
22011  *pBufferSizeInFramesOut = (ma_uint32)bufferSizeRange.mMaximum;
22012  } else {
22013  *pBufferSizeInFramesOut = bufferSizeInFramesIn;
22014  }
22015 
22016  return MA_SUCCESS;
22017 }
22018 
22019 static ma_result ma_set_AudioObject_buffer_size_in_frames(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32* pPeriodSizeInOut)
22020 {
22021  ma_result result;
22022  ma_uint32 chosenBufferSizeInFrames;
22023  AudioObjectPropertyAddress propAddress;
22024  UInt32 dataSize;
22025  OSStatus status;
22026 
22027  MA_ASSERT(pContext != NULL);
22028 
22029  result = ma_get_AudioObject_closest_buffer_size_in_frames(pContext, deviceObjectID, deviceType, *pPeriodSizeInOut, &chosenBufferSizeInFrames);
22030  if (result != MA_SUCCESS) {
22031  return result;
22032  }
22033 
22034  /* Try setting the size of the buffer... If this fails we just use whatever is currently set. */
22035  propAddress.mSelector = kAudioDevicePropertyBufferFrameSize;
22036  propAddress.mScope = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
22037  propAddress.mElement = kAudioObjectPropertyElementMaster;
22038 
22039  ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(chosenBufferSizeInFrames), &chosenBufferSizeInFrames);
22040 
22041  /* Get the actual size of the buffer. */
22042  dataSize = sizeof(*pPeriodSizeInOut);
22043  status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, &chosenBufferSizeInFrames);
22044  if (status != noErr) {
22045  return ma_result_from_OSStatus(status);
22046  }
22047 
22048  *pPeriodSizeInOut = chosenBufferSizeInFrames;
22049  return MA_SUCCESS;
22050 }
22051 
22052 
22053 static ma_result ma_find_AudioObjectID(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, AudioObjectID* pDeviceObjectID)
22054 {
22055  MA_ASSERT(pContext != NULL);
22056  MA_ASSERT(pDeviceObjectID != NULL);
22057 
22058  /* Safety. */
22059  *pDeviceObjectID = 0;
22060 
22061  if (pDeviceID == NULL) {
22062  /* Default device. */
22063  AudioObjectPropertyAddress propAddressDefaultDevice;
22064  UInt32 defaultDeviceObjectIDSize = sizeof(AudioObjectID);
22065  AudioObjectID defaultDeviceObjectID;
22066  OSStatus status;
22067 
22068  propAddressDefaultDevice.mScope = kAudioObjectPropertyScopeGlobal;
22069  propAddressDefaultDevice.mElement = kAudioObjectPropertyElementMaster;
22070  if (deviceType == ma_device_type_playback) {
22071  propAddressDefaultDevice.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
22072  } else {
22073  propAddressDefaultDevice.mSelector = kAudioHardwarePropertyDefaultInputDevice;
22074  }
22075 
22076  defaultDeviceObjectIDSize = sizeof(AudioObjectID);
22077  status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject, &propAddressDefaultDevice, 0, NULL, &defaultDeviceObjectIDSize, &defaultDeviceObjectID);
22078  if (status == noErr) {
22079  *pDeviceObjectID = defaultDeviceObjectID;
22080  return MA_SUCCESS;
22081  }
22082  } else {
22083  /* Explicit device. */
22084  UInt32 deviceCount;
22085  AudioObjectID* pDeviceObjectIDs;
22086  ma_result result;
22087  UInt32 iDevice;
22088 
22089  result = ma_get_device_object_ids__coreaudio(pContext, &deviceCount, &pDeviceObjectIDs);
22090  if (result != MA_SUCCESS) {
22091  return result;
22092  }
22093 
22094  for (iDevice = 0; iDevice < deviceCount; ++iDevice) {
22095  AudioObjectID deviceObjectID = pDeviceObjectIDs[iDevice];
22096 
22097  char uid[256];
22098  if (ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(uid), uid) != MA_SUCCESS) {
22099  continue;
22100  }
22101 
22102  if (deviceType == ma_device_type_playback) {
22103  if (ma_does_AudioObject_support_playback(pContext, deviceObjectID)) {
22104  if (strcmp(uid, pDeviceID->coreaudio) == 0) {
22105  *pDeviceObjectID = deviceObjectID;
22106  ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
22107  return MA_SUCCESS;
22108  }
22109  }
22110  } else {
22111  if (ma_does_AudioObject_support_capture(pContext, deviceObjectID)) {
22112  if (strcmp(uid, pDeviceID->coreaudio) == 0) {
22113  *pDeviceObjectID = deviceObjectID;
22114  ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
22115  return MA_SUCCESS;
22116  }
22117  }
22118  }
22119  }
22120 
22121  ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
22122  }
22123 
22124  /* If we get here it means we couldn't find the device. */
22125  return MA_NO_DEVICE;
22126 }
22127 
22128 
22129 static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_bool32 usingDefaultFormat, ma_bool32 usingDefaultChannels, ma_bool32 usingDefaultSampleRate, AudioStreamBasicDescription* pFormat)
22130 {
22131  UInt32 deviceFormatDescriptionCount;
22132  AudioStreamRangedDescription* pDeviceFormatDescriptions;
22133  ma_result result;
22134  ma_uint32 desiredSampleRate;
22135  ma_uint32 desiredChannelCount;
22136  ma_format desiredFormat;
22137  AudioStreamBasicDescription bestDeviceFormatSoFar;
22138  ma_bool32 hasSupportedFormat;
22139  UInt32 iFormat;
22140 
22141  result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &deviceFormatDescriptionCount, &pDeviceFormatDescriptions);
22142  if (result != MA_SUCCESS) {
22143  return result;
22144  }
22145 
22146  desiredSampleRate = sampleRate;
22147  if (usingDefaultSampleRate) {
22148  /*
22149  When using the device's default sample rate, we get the highest priority standard rate supported by the device. Otherwise
22150  we just use the pre-set rate.
22151  */
22152  ma_uint32 iStandardRate;
22153  for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) {
22154  ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate];
22155  ma_bool32 foundRate = MA_FALSE;
22156  UInt32 iDeviceRate;
22157 
22158  for (iDeviceRate = 0; iDeviceRate < deviceFormatDescriptionCount; ++iDeviceRate) {
22159  ma_uint32 deviceRate = (ma_uint32)pDeviceFormatDescriptions[iDeviceRate].mFormat.mSampleRate;
22160 
22161  if (deviceRate == standardRate) {
22162  desiredSampleRate = standardRate;
22163  foundRate = MA_TRUE;
22164  break;
22165  }
22166  }
22167 
22168  if (foundRate) {
22169  break;
22170  }
22171  }
22172  }
22173 
22174  desiredChannelCount = channels;
22175  if (usingDefaultChannels) {
22176  ma_get_AudioObject_channel_count(pContext, deviceObjectID, deviceType, &desiredChannelCount); /* <-- Not critical if this fails. */
22177  }
22178 
22179  desiredFormat = format;
22180  if (usingDefaultFormat) {
22181  desiredFormat = g_maFormatPriorities[0];
22182  }
22183 
22184  /*
22185  If we get here it means we don't have an exact match to what the client is asking for. We'll need to find the closest one. The next
22186  loop will check for formats that have the same sample rate to what we're asking for. If there is, we prefer that one in all cases.
22187  */
22188  MA_ZERO_OBJECT(&bestDeviceFormatSoFar);
22189 
22190  hasSupportedFormat = MA_FALSE;
22191  for (iFormat = 0; iFormat < deviceFormatDescriptionCount; ++iFormat) {
22192  ma_format format;
22193  ma_result formatResult = ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat, &format);
22194  if (formatResult == MA_SUCCESS && format != ma_format_unknown) {
22195  hasSupportedFormat = MA_TRUE;
22196  bestDeviceFormatSoFar = pDeviceFormatDescriptions[iFormat].mFormat;
22197  break;
22198  }
22199  }
22200 
22201  if (!hasSupportedFormat) {
22202  ma_free(pDeviceFormatDescriptions, &pContext->allocationCallbacks);
22203  return MA_FORMAT_NOT_SUPPORTED;
22204  }
22205 
22206 
22207  for (iFormat = 0; iFormat < deviceFormatDescriptionCount; ++iFormat) {
22208  AudioStreamBasicDescription thisDeviceFormat = pDeviceFormatDescriptions[iFormat].mFormat;
22209  ma_format thisSampleFormat;
22210  ma_result formatResult;
22211  ma_format bestSampleFormatSoFar;
22212 
22213  /* If the format is not supported by miniaudio we need to skip this one entirely. */
22214  formatResult = ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat, &thisSampleFormat);
22215  if (formatResult != MA_SUCCESS || thisSampleFormat == ma_format_unknown) {
22216  continue; /* The format is not supported by miniaudio. Skip. */
22217  }
22218 
22219  ma_format_from_AudioStreamBasicDescription(&bestDeviceFormatSoFar, &bestSampleFormatSoFar);
22220 
22221  /* Getting here means the format is supported by miniaudio which makes this format a candidate. */
22222  if (thisDeviceFormat.mSampleRate != desiredSampleRate) {
22223  /*
22224  The sample rate does not match, but this format could still be usable, although it's a very low priority. If the best format
22225  so far has an equal sample rate we can just ignore this one.
22226  */
22227  if (bestDeviceFormatSoFar.mSampleRate == desiredSampleRate) {
22228  continue; /* The best sample rate so far has the same sample rate as what we requested which means it's still the best so far. Skip this format. */
22229  } else {
22230  /* In this case, neither the best format so far nor this one have the same sample rate. Check the channel count next. */
22231  if (thisDeviceFormat.mChannelsPerFrame != desiredChannelCount) {
22232  /* This format has a different sample rate _and_ a different channel count. */
22233  if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) {
22234  continue; /* No change to the best format. */
22235  } else {
22236  /*
22237  Both this format and the best so far have different sample rates and different channel counts. Whichever has the
22238  best format is the new best.
22239  */
22240  if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
22241  bestDeviceFormatSoFar = thisDeviceFormat;
22242  continue;
22243  } else {
22244  continue; /* No change to the best format. */
22245  }
22246  }
22247  } else {
22248  /* This format has a different sample rate but the desired channel count. */
22249  if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) {
22250  /* Both this format and the best so far have the desired channel count. Whichever has the best format is the new best. */
22251  if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
22252  bestDeviceFormatSoFar = thisDeviceFormat;
22253  continue;
22254  } else {
22255  continue; /* No change to the best format for now. */
22256  }
22257  } else {
22258  /* This format has the desired channel count, but the best so far does not. We have a new best. */
22259  bestDeviceFormatSoFar = thisDeviceFormat;
22260  continue;
22261  }
22262  }
22263  }
22264  } else {
22265  /*
22266  The sample rates match which makes this format a very high priority contender. If the best format so far has a different
22267  sample rate it needs to be replaced with this one.
22268  */
22269  if (bestDeviceFormatSoFar.mSampleRate != desiredSampleRate) {
22270  bestDeviceFormatSoFar = thisDeviceFormat;
22271  continue;
22272  } else {
22273  /* In this case both this format and the best format so far have the same sample rate. Check the channel count next. */
22274  if (thisDeviceFormat.mChannelsPerFrame == desiredChannelCount) {
22275  /*
22276  In this case this format has the same channel count as what the client is requesting. If the best format so far has
22277  a different count, this one becomes the new best.
22278  */
22279  if (bestDeviceFormatSoFar.mChannelsPerFrame != desiredChannelCount) {
22280  bestDeviceFormatSoFar = thisDeviceFormat;
22281  continue;
22282  } else {
22283  /* In this case both this format and the best so far have the ideal sample rate and channel count. Check the format. */
22284  if (thisSampleFormat == desiredFormat) {
22285  bestDeviceFormatSoFar = thisDeviceFormat;
22286  break; /* Found the exact match. */
22287  } else {
22288  /* The formats are different. The new best format is the one with the highest priority format according to miniaudio. */
22289  if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
22290  bestDeviceFormatSoFar = thisDeviceFormat;
22291  continue;
22292  } else {
22293  continue; /* No change to the best format for now. */
22294  }
22295  }
22296  }
22297  } else {
22298  /*
22299  In this case the channel count is different to what the client has requested. If the best so far has the same channel
22300  count as the requested count then it remains the best.
22301  */
22302  if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) {
22303  continue;
22304  } else {
22305  /*
22306  This is the case where both have the same sample rate (good) but different channel counts. Right now both have about
22307  the same priority, but we need to compare the format now.
22308  */
22309  if (thisSampleFormat == bestSampleFormatSoFar) {
22310  if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
22311  bestDeviceFormatSoFar = thisDeviceFormat;
22312  continue;
22313  } else {
22314  continue; /* No change to the best format for now. */
22315  }
22316  }
22317  }
22318  }
22319  }
22320  }
22321  }
22322 
22323  *pFormat = bestDeviceFormatSoFar;
22324 
22325  ma_free(pDeviceFormatDescriptions, &pContext->allocationCallbacks);
22326  return MA_SUCCESS;
22327 }
22328 
22329 static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit audioUnit, ma_device_type deviceType, ma_channel channelMap[MA_MAX_CHANNELS])
22330 {
22331  AudioUnitScope deviceScope;
22332  AudioUnitElement deviceBus;
22333  UInt32 channelLayoutSize;
22334  OSStatus status;
22335  AudioChannelLayout* pChannelLayout;
22336  ma_result result;
22337 
22338  MA_ASSERT(pContext != NULL);
22339 
22340  if (deviceType == ma_device_type_playback) {
22341  deviceScope = kAudioUnitScope_Output;
22342  deviceBus = MA_COREAUDIO_OUTPUT_BUS;
22343  } else {
22344  deviceScope = kAudioUnitScope_Input;
22345  deviceBus = MA_COREAUDIO_INPUT_BUS;
22346  }
22347 
22348  status = ((ma_AudioUnitGetPropertyInfo_proc)pContext->coreaudio.AudioUnitGetPropertyInfo)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, &channelLayoutSize, NULL);
22349  if (status != noErr) {
22350  return ma_result_from_OSStatus(status);
22351  }
22352 
22353  pChannelLayout = (AudioChannelLayout*)ma__malloc_from_callbacks(channelLayoutSize, &pContext->allocationCallbacks);
22354  if (pChannelLayout == NULL) {
22355  return MA_OUT_OF_MEMORY;
22356  }
22357 
22358  status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, pChannelLayout, &channelLayoutSize);
22359  if (status != noErr) {
22360  ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks);
22361  return ma_result_from_OSStatus(status);
22362  }
22363 
22364  result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, channelMap);
22365  if (result != MA_SUCCESS) {
22366  ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks);
22367  return result;
22368  }
22369 
22370  ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks);
22371  return MA_SUCCESS;
22372 }
22373 #endif /* MA_APPLE_DESKTOP */
22374 
22375 static ma_bool32 ma_context_is_device_id_equal__coreaudio(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
22376 {
22377  MA_ASSERT(pContext != NULL);
22378  MA_ASSERT(pID0 != NULL);
22379  MA_ASSERT(pID1 != NULL);
22380  (void)pContext;
22381 
22382  return strcmp(pID0->coreaudio, pID1->coreaudio) == 0;
22383 }
22384 
22385 static ma_result ma_context_enumerate_devices__coreaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
22386 {
22387 #if defined(MA_APPLE_DESKTOP)
22388  UInt32 deviceCount;
22389  AudioObjectID* pDeviceObjectIDs;
22390  ma_result result;
22391  UInt32 iDevice;
22392 
22393  result = ma_get_device_object_ids__coreaudio(pContext, &deviceCount, &pDeviceObjectIDs);
22394  if (result != MA_SUCCESS) {
22395  return result;
22396  }
22397 
22398  for (iDevice = 0; iDevice < deviceCount; ++iDevice) {
22399  AudioObjectID deviceObjectID = pDeviceObjectIDs[iDevice];
22400  ma_device_info info;
22401 
22402  MA_ZERO_OBJECT(&info);
22403  if (ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(info.id.coreaudio), info.id.coreaudio) != MA_SUCCESS) {
22404  continue;
22405  }
22406  if (ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(info.name), info.name) != MA_SUCCESS) {
22407  continue;
22408  }
22409 
22410  if (ma_does_AudioObject_support_playback(pContext, deviceObjectID)) {
22411  if (!callback(pContext, ma_device_type_playback, &info, pUserData)) {
22412  break;
22413  }
22414  }
22415  if (ma_does_AudioObject_support_capture(pContext, deviceObjectID)) {
22416  if (!callback(pContext, ma_device_type_capture, &info, pUserData)) {
22417  break;
22418  }
22419  }
22420  }
22421 
22422  ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
22423 #else
22424  /* Only supporting default devices on non-Desktop platforms. */
22425  ma_device_info info;
22426 
22427  MA_ZERO_OBJECT(&info);
22428  ma_strncpy_s(info.name, sizeof(info.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
22429  if (!callback(pContext, ma_device_type_playback, &info, pUserData)) {
22430  return MA_SUCCESS;
22431  }
22432 
22433  MA_ZERO_OBJECT(&info);
22434  ma_strncpy_s(info.name, sizeof(info.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
22435  if (!callback(pContext, ma_device_type_capture, &info, pUserData)) {
22436  return MA_SUCCESS;
22437  }
22438 #endif
22439 
22440  return MA_SUCCESS;
22441 }
22442 
22443 static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
22444 {
22445  ma_result result;
22446 
22447  MA_ASSERT(pContext != NULL);
22448 
22449  /* No exclusive mode with the Core Audio backend for now. */
22450  if (shareMode == ma_share_mode_exclusive) {
22452  }
22453 
22454 #if defined(MA_APPLE_DESKTOP)
22455  /* Desktop */
22456  {
22457  AudioObjectID deviceObjectID;
22458  UInt32 streamDescriptionCount;
22459  AudioStreamRangedDescription* pStreamDescriptions;
22460  UInt32 iStreamDescription;
22461  UInt32 sampleRateRangeCount;
22462  AudioValueRange* pSampleRateRanges;
22463 
22464  result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID);
22465  if (result != MA_SUCCESS) {
22466  return result;
22467  }
22468 
22469  result = ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(pDeviceInfo->id.coreaudio), pDeviceInfo->id.coreaudio);
22470  if (result != MA_SUCCESS) {
22471  return result;
22472  }
22473 
22474  result = ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(pDeviceInfo->name), pDeviceInfo->name);
22475  if (result != MA_SUCCESS) {
22476  return result;
22477  }
22478 
22479  /* Formats. */
22480  result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &streamDescriptionCount, &pStreamDescriptions);
22481  if (result != MA_SUCCESS) {
22482  return result;
22483  }
22484 
22485  for (iStreamDescription = 0; iStreamDescription < streamDescriptionCount; ++iStreamDescription) {
22486  ma_format format;
22487  ma_bool32 formatExists = MA_FALSE;
22488  ma_uint32 iOutputFormat;
22489 
22490  result = ma_format_from_AudioStreamBasicDescription(&pStreamDescriptions[iStreamDescription].mFormat, &format);
22491  if (result != MA_SUCCESS) {
22492  continue;
22493  }
22494 
22495  MA_ASSERT(format != ma_format_unknown);
22496 
22497  /* Make sure the format isn't already in the output list. */
22498  for (iOutputFormat = 0; iOutputFormat < pDeviceInfo->formatCount; ++iOutputFormat) {
22499  if (pDeviceInfo->formats[iOutputFormat] == format) {
22500  formatExists = MA_TRUE;
22501  break;
22502  }
22503  }
22504 
22505  if (!formatExists) {
22506  pDeviceInfo->formats[pDeviceInfo->formatCount++] = format;
22507  }
22508  }
22509 
22510  ma_free(pStreamDescriptions, &pContext->allocationCallbacks);
22511 
22512 
22513  /* Channels. */
22514  result = ma_get_AudioObject_channel_count(pContext, deviceObjectID, deviceType, &pDeviceInfo->minChannels);
22515  if (result != MA_SUCCESS) {
22516  return result;
22517  }
22518  pDeviceInfo->maxChannels = pDeviceInfo->minChannels;
22519 
22520 
22521  /* Sample rates. */
22522  result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges);
22523  if (result != MA_SUCCESS) {
22524  return result;
22525  }
22526 
22527  if (sampleRateRangeCount > 0) {
22528  UInt32 iSampleRate;
22529  pDeviceInfo->minSampleRate = UINT32_MAX;
22530  pDeviceInfo->maxSampleRate = 0;
22531  for (iSampleRate = 0; iSampleRate < sampleRateRangeCount; ++iSampleRate) {
22532  if (pDeviceInfo->minSampleRate > pSampleRateRanges[iSampleRate].mMinimum) {
22533  pDeviceInfo->minSampleRate = pSampleRateRanges[iSampleRate].mMinimum;
22534  }
22535  if (pDeviceInfo->maxSampleRate < pSampleRateRanges[iSampleRate].mMaximum) {
22536  pDeviceInfo->maxSampleRate = pSampleRateRanges[iSampleRate].mMaximum;
22537  }
22538  }
22539  }
22540  }
22541 #else
22542  /* Mobile */
22543  {
22544  AudioComponentDescription desc;
22545  AudioComponent component;
22546  AudioUnit audioUnit;
22547  OSStatus status;
22548  AudioUnitScope formatScope;
22549  AudioUnitElement formatElement;
22550  AudioStreamBasicDescription bestFormat;
22551  UInt32 propSize;
22552 
22553  if (deviceType == ma_device_type_playback) {
22554  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
22555  } else {
22556  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
22557  }
22558 
22559  /*
22560  Retrieving device information is more annoying on mobile than desktop. For simplicity I'm locking this down to whatever format is
22561  reported on a temporary I/O unit. The problem, however, is that this doesn't return a value for the sample rate which we need to
22562  retrieve from the AVAudioSession shared instance.
22563  */
22564  desc.componentType = kAudioUnitType_Output;
22565  desc.componentSubType = kAudioUnitSubType_RemoteIO;
22566  desc.componentManufacturer = kAudioUnitManufacturer_Apple;
22567  desc.componentFlags = 0;
22568  desc.componentFlagsMask = 0;
22569 
22570  component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc);
22571  if (component == NULL) {
22573  }
22574 
22575  status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)(component, &audioUnit);
22576  if (status != noErr) {
22577  return ma_result_from_OSStatus(status);
22578  }
22579 
22580  formatScope = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
22581  formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;
22582 
22583  propSize = sizeof(bestFormat);
22584  status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, &propSize);
22585  if (status != noErr) {
22586  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
22587  return ma_result_from_OSStatus(status);
22588  }
22589 
22590  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
22591  audioUnit = NULL;
22592 
22593 
22594  pDeviceInfo->minChannels = bestFormat.mChannelsPerFrame;
22595  pDeviceInfo->maxChannels = bestFormat.mChannelsPerFrame;
22596 
22597  pDeviceInfo->formatCount = 1;
22598  result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pDeviceInfo->formats[0]);
22599  if (result != MA_SUCCESS) {
22600  return result;
22601  }
22602 
22603  /*
22604  It looks like Apple are wanting to push the whole AVAudioSession thing. Thus, we need to use that to determine device settings. To do
22605  this we just get the shared instance and inspect.
22606  */
22607  @autoreleasepool {
22608  AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
22609  MA_ASSERT(pAudioSession != NULL);
22610 
22611  pDeviceInfo->minSampleRate = (ma_uint32)pAudioSession.sampleRate;
22612  pDeviceInfo->maxSampleRate = pDeviceInfo->minSampleRate;
22613  }
22614  }
22615 #endif
22616 
22617  (void)pDeviceInfo; /* Unused. */
22618  return MA_SUCCESS;
22619 }
22620 
22621 
22622 static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFlags* pActionFlags, const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pBufferList)
22623 {
22624  ma_device* pDevice = (ma_device*)pUserData;
22625  ma_stream_layout layout;
22626 
22627  MA_ASSERT(pDevice != NULL);
22628 
22629 #if defined(MA_DEBUG_OUTPUT)
22630  printf("INFO: Output Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", busNumber, frameCount, pBufferList->mNumberBuffers);
22631 #endif
22632 
22633  /* We need to check whether or not we are outputting interleaved or non-interleaved samples. The way we do this is slightly different for each type. */
22635  if (pBufferList->mBuffers[0].mNumberChannels != pDevice->playback.internalChannels) {
22637  }
22638 
22639  if (layout == ma_stream_layout_interleaved) {
22640  /* For now we can assume everything is interleaved. */
22641  UInt32 iBuffer;
22642  for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) {
22643  if (pBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->playback.internalChannels) {
22644  ma_uint32 frameCountForThisBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
22645  if (frameCountForThisBuffer > 0) {
22646  if (pDevice->type == ma_device_type_duplex) {
22647  ma_device__handle_duplex_callback_playback(pDevice, frameCountForThisBuffer, pBufferList->mBuffers[iBuffer].mData, &pDevice->coreaudio.duplexRB);
22648  } else {
22649  ma_device__read_frames_from_client(pDevice, frameCountForThisBuffer, pBufferList->mBuffers[iBuffer].mData);
22650  }
22651  }
22652 
22653  #if defined(MA_DEBUG_OUTPUT)
22654  printf(" frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pBufferList->mBuffers[iBuffer].mNumberChannels, pBufferList->mBuffers[iBuffer].mDataByteSize);
22655  #endif
22656  } else {
22657  /*
22658  This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's
22659  not interleaved, in which case we can't handle right now since miniaudio does not yet support non-interleaved streams. We just
22660  output silence here.
22661  */
22662  MA_ZERO_MEMORY(pBufferList->mBuffers[iBuffer].mData, pBufferList->mBuffers[iBuffer].mDataByteSize);
22663 
22664  #if defined(MA_DEBUG_OUTPUT)
22665  printf(" WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pBufferList->mBuffers[iBuffer].mNumberChannels, pBufferList->mBuffers[iBuffer].mDataByteSize);
22666  #endif
22667  }
22668  }
22669  } else {
22670  /* This is the deinterleaved case. We need to update each buffer in groups of internalChannels. This assumes each buffer is the same size. */
22671 
22672  /*
22673  For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something
22674  very strange has happened and we're not going to support it.
22675  */
22676  if ((pBufferList->mNumberBuffers % pDevice->playback.internalChannels) == 0) {
22677  ma_uint8 tempBuffer[4096];
22678  UInt32 iBuffer;
22679 
22680  for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; iBuffer += pDevice->playback.internalChannels) {
22681  ma_uint32 frameCountPerBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_sample(pDevice->playback.internalFormat);
22682  ma_uint32 framesRemaining = frameCountPerBuffer;
22683 
22684  while (framesRemaining > 0) {
22685  void* ppDeinterleavedBuffers[MA_MAX_CHANNELS];
22686  ma_uint32 iChannel;
22687  ma_uint32 framesToRead = sizeof(tempBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
22688  if (framesToRead > framesRemaining) {
22689  framesToRead = framesRemaining;
22690  }
22691 
22692  if (pDevice->type == ma_device_type_duplex) {
22693  ma_device__handle_duplex_callback_playback(pDevice, framesToRead, tempBuffer, &pDevice->coreaudio.duplexRB);
22694  } else {
22695  ma_device__read_frames_from_client(pDevice, framesToRead, tempBuffer);
22696  }
22697 
22698  for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) {
22699  ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pBufferList->mBuffers[iBuffer+iChannel].mData, (frameCountPerBuffer - framesRemaining) * ma_get_bytes_per_sample(pDevice->playback.internalFormat));
22700  }
22701 
22702  ma_deinterleave_pcm_frames(pDevice->playback.internalFormat, pDevice->playback.internalChannels, framesToRead, tempBuffer, ppDeinterleavedBuffers);
22703 
22704  framesRemaining -= framesToRead;
22705  }
22706  }
22707  }
22708  }
22709 
22710  (void)pActionFlags;
22711  (void)pTimeStamp;
22712  (void)busNumber;
22713 
22714  return noErr;
22715 }
22716 
22717 static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFlags* pActionFlags, const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pUnusedBufferList)
22718 {
22719  ma_device* pDevice = (ma_device*)pUserData;
22720  AudioBufferList* pRenderedBufferList;
22721  ma_stream_layout layout;
22722  OSStatus status;
22723 
22724  MA_ASSERT(pDevice != NULL);
22725 
22726  pRenderedBufferList = (AudioBufferList*)pDevice->coreaudio.pAudioBufferList;
22727  MA_ASSERT(pRenderedBufferList);
22728 
22729  /* We need to check whether or not we are outputting interleaved or non-interleaved samples. The way we do this is slightly different for each type. */
22731  if (pRenderedBufferList->mBuffers[0].mNumberChannels != pDevice->capture.internalChannels) {
22733  }
22734 
22735 #if defined(MA_DEBUG_OUTPUT)
22736  printf("INFO: Input Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", busNumber, frameCount, pRenderedBufferList->mNumberBuffers);
22737 #endif
22738 
22739  status = ((ma_AudioUnitRender_proc)pDevice->pContext->coreaudio.AudioUnitRender)((AudioUnit)pDevice->coreaudio.audioUnitCapture, pActionFlags, pTimeStamp, busNumber, frameCount, pRenderedBufferList);
22740  if (status != noErr) {
22741  #if defined(MA_DEBUG_OUTPUT)
22742  printf(" ERROR: AudioUnitRender() failed with %d\n", status);
22743  #endif
22744  return status;
22745  }
22746 
22747  if (layout == ma_stream_layout_interleaved) {
22748  UInt32 iBuffer;
22749  for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) {
22750  if (pRenderedBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->capture.internalChannels) {
22751  if (pDevice->type == ma_device_type_duplex) {
22752  ma_device__handle_duplex_callback_capture(pDevice, frameCount, pRenderedBufferList->mBuffers[iBuffer].mData, &pDevice->coreaudio.duplexRB);
22753  } else {
22754  ma_device__send_frames_to_client(pDevice, frameCount, pRenderedBufferList->mBuffers[iBuffer].mData);
22755  }
22756  #if defined(MA_DEBUG_OUTPUT)
22757  printf(" mDataByteSize=%d\n", pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);
22758  #endif
22759  } else {
22760  /*
22761  This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's
22762  not interleaved, in which case we can't handle right now since miniaudio does not yet support non-interleaved streams.
22763  */
22764  ma_uint8 silentBuffer[4096];
22765  ma_uint32 framesRemaining;
22766 
22767  MA_ZERO_MEMORY(silentBuffer, sizeof(silentBuffer));
22768 
22769  framesRemaining = frameCount;
22770  while (framesRemaining > 0) {
22771  ma_uint32 framesToSend = sizeof(silentBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
22772  if (framesToSend > framesRemaining) {
22773  framesToSend = framesRemaining;
22774  }
22775 
22776  if (pDevice->type == ma_device_type_duplex) {
22777  ma_device__handle_duplex_callback_capture(pDevice, framesToSend, silentBuffer, &pDevice->coreaudio.duplexRB);
22778  } else {
22779  ma_device__send_frames_to_client(pDevice, framesToSend, silentBuffer);
22780  }
22781 
22782  framesRemaining -= framesToSend;
22783  }
22784 
22785  #if defined(MA_DEBUG_OUTPUT)
22786  printf(" WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pRenderedBufferList->mBuffers[iBuffer].mNumberChannels, pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);
22787  #endif
22788  }
22789  }
22790  } else {
22791  /* This is the deinterleaved case. We need to interleave the audio data before sending it to the client. This assumes each buffer is the same size. */
22792 
22793  /*
22794  For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something
22795  very strange has happened and we're not going to support it.
22796  */
22797  if ((pRenderedBufferList->mNumberBuffers % pDevice->capture.internalChannels) == 0) {
22798  ma_uint8 tempBuffer[4096];
22799  UInt32 iBuffer;
22800  for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; iBuffer += pDevice->capture.internalChannels) {
22801  ma_uint32 framesRemaining = frameCount;
22802  while (framesRemaining > 0) {
22803  void* ppDeinterleavedBuffers[MA_MAX_CHANNELS];
22804  ma_uint32 iChannel;
22805  ma_uint32 framesToSend = sizeof(tempBuffer) / ma_get_bytes_per_sample(pDevice->capture.internalFormat);
22806  if (framesToSend > framesRemaining) {
22807  framesToSend = framesRemaining;
22808  }
22809 
22810  for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) {
22811  ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pRenderedBufferList->mBuffers[iBuffer+iChannel].mData, (frameCount - framesRemaining) * ma_get_bytes_per_sample(pDevice->capture.internalFormat));
22812  }
22813 
22814  ma_interleave_pcm_frames(pDevice->capture.internalFormat, pDevice->capture.internalChannels, framesToSend, (const void**)ppDeinterleavedBuffers, tempBuffer);
22815 
22816  if (pDevice->type == ma_device_type_duplex) {
22817  ma_device__handle_duplex_callback_capture(pDevice, framesToSend, tempBuffer, &pDevice->coreaudio.duplexRB);
22818  } else {
22819  ma_device__send_frames_to_client(pDevice, framesToSend, tempBuffer);
22820  }
22821 
22822  framesRemaining -= framesToSend;
22823  }
22824  }
22825  }
22826  }
22827 
22828  (void)pActionFlags;
22829  (void)pTimeStamp;
22830  (void)busNumber;
22831  (void)frameCount;
22832  (void)pUnusedBufferList;
22833 
22834  return noErr;
22835 }
22836 
22837 static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, AudioUnitPropertyID propertyID, AudioUnitScope scope, AudioUnitElement element)
22838 {
22839  ma_device* pDevice = (ma_device*)pUserData;
22840  MA_ASSERT(pDevice != NULL);
22841 
22842  /*
22843  There's been a report of a deadlock here when triggered by ma_device_uninit(). It looks like
22844  AudioUnitGetProprty (called below) and AudioComponentInstanceDispose (called in ma_device_uninit)
22845  can try waiting on the same lock. I'm going to try working around this by not calling any Core
22846  Audio APIs in the callback when the device has been stopped or uninitialized.
22847  */
22848  if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED || ma_device__get_state(pDevice) == MA_STATE_STOPPING || ma_device__get_state(pDevice) == MA_STATE_STOPPED) {
22849  ma_stop_proc onStop = pDevice->onStop;
22850  if (onStop) {
22851  onStop(pDevice);
22852  }
22853 
22854  ma_event_signal(&pDevice->coreaudio.stopEvent);
22855  } else {
22856  UInt32 isRunning;
22857  UInt32 isRunningSize = sizeof(isRunning);
22858  OSStatus status = ((ma_AudioUnitGetProperty_proc)pDevice->pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioOutputUnitProperty_IsRunning, scope, element, &isRunning, &isRunningSize);
22859  if (status != noErr) {
22860  return; /* Don't really know what to do in this case... just ignore it, I suppose... */
22861  }
22862 
22863  if (!isRunning) {
22864  ma_stop_proc onStop;
22865 
22866  /*
22867  The stop event is a bit annoying in Core Audio because it will be called when we automatically switch the default device. Some scenarios to consider:
22868 
22869  1) When the device is unplugged, this will be called _before_ the default device change notification.
22870  2) When the device is changed via the default device change notification, this will be called _after_ the switch.
22871 
22872  For case #1, we just check if there's a new default device available. If so, we just ignore the stop event. For case #2 we check a flag.
22873  */
22874  if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isDefaultPlaybackDevice) ||
22875  ((audioUnit == pDevice->coreaudio.audioUnitCapture) && pDevice->coreaudio.isDefaultCaptureDevice)) {
22876  /*
22877  It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device
22878  via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the
22879  device to be seamless to the client (we don't want them receiving the onStop event and thinking that the device has stopped when it
22880  hasn't!).
22881  */
22882  if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) ||
22883  ((audioUnit == pDevice->coreaudio.audioUnitCapture) && pDevice->coreaudio.isSwitchingCaptureDevice)) {
22884  return;
22885  }
22886 
22887  /*
22888  Getting here means the device is not reinitializing which means it may have been unplugged. From what I can see, it looks like Core Audio
22889  will try switching to the new default device seamlessly. We need to somehow find a way to determine whether or not Core Audio will most
22890  likely be successful in switching to the new device.
22891 
22892  TODO: Try to predict if Core Audio will switch devices. If not, the onStop callback needs to be posted.
22893  */
22894  return;
22895  }
22896 
22897  /* Getting here means we need to stop the device. */
22898  onStop = pDevice->onStop;
22899  if (onStop) {
22900  onStop(pDevice);
22901  }
22902  }
22903  }
22904 
22905  (void)propertyID; /* Unused. */
22906 }
22907 
22908 #if defined(MA_APPLE_DESKTOP)
22909 static ma_uint32 g_DeviceTrackingInitCounter_CoreAudio = 0;
22910 static ma_mutex g_DeviceTrackingMutex_CoreAudio;
22911 static ma_device** g_ppTrackedDevices_CoreAudio = NULL;
22912 static ma_uint32 g_TrackedDeviceCap_CoreAudio = 0;
22913 static ma_uint32 g_TrackedDeviceCount_CoreAudio = 0;
22914 
22915 static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UInt32 addressCount, const AudioObjectPropertyAddress* pAddresses, void* pUserData)
22916 {
22917  ma_device_type deviceType;
22918 
22919  /* Not sure if I really need to check this, but it makes me feel better. */
22920  if (addressCount == 0) {
22921  return noErr;
22922  }
22923 
22924  if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultOutputDevice) {
22925  deviceType = ma_device_type_playback;
22926  } else if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultInputDevice) {
22927  deviceType = ma_device_type_capture;
22928  } else {
22929  return noErr; /* Should never hit this. */
22930  }
22931 
22932  ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
22933  {
22934  ma_uint32 iDevice;
22935  for (iDevice = 0; iDevice < g_TrackedDeviceCount_CoreAudio; iDevice += 1) {
22936  ma_result reinitResult;
22937  ma_device* pDevice;
22938 
22939  pDevice = g_ppTrackedDevices_CoreAudio[iDevice];
22940  if (pDevice->type == deviceType || pDevice->type == ma_device_type_duplex) {
22941  if (deviceType == ma_device_type_playback) {
22942  pDevice->coreaudio.isSwitchingPlaybackDevice = MA_TRUE;
22943  reinitResult = ma_device_reinit_internal__coreaudio(pDevice, deviceType, MA_TRUE);
22944  pDevice->coreaudio.isSwitchingPlaybackDevice = MA_FALSE;
22945  } else {
22946  pDevice->coreaudio.isSwitchingCaptureDevice = MA_TRUE;
22947  reinitResult = ma_device_reinit_internal__coreaudio(pDevice, deviceType, MA_TRUE);
22948  pDevice->coreaudio.isSwitchingCaptureDevice = MA_FALSE;
22949  }
22950 
22951  if (reinitResult == MA_SUCCESS) {
22952  ma_device__post_init_setup(pDevice, deviceType);
22953 
22954  /* Restart the device if required. If this fails we need to stop the device entirely. */
22955  if (ma_device__get_state(pDevice) == MA_STATE_STARTED) {
22956  OSStatus status;
22957  if (deviceType == ma_device_type_playback) {
22958  status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
22959  if (status != noErr) {
22960  if (pDevice->type == ma_device_type_duplex) {
22961  ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
22962  }
22964  }
22965  } else if (deviceType == ma_device_type_capture) {
22966  status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
22967  if (status != noErr) {
22968  if (pDevice->type == ma_device_type_duplex) {
22969  ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
22970  }
22972  }
22973  }
22974  }
22975  }
22976  }
22977  }
22978  }
22979  ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
22980 
22981  (void)objectID; /* Unused. */
22982  return noErr;
22983 }
22984 
22985 static ma_result ma_context__init_device_tracking__coreaudio(ma_context* pContext)
22986 {
22987  MA_ASSERT(pContext != NULL);
22988 
22989  if (ma_atomic_increment_32(&g_DeviceTrackingInitCounter_CoreAudio) == 1) {
22990  AudioObjectPropertyAddress propAddress;
22991  propAddress.mScope = kAudioObjectPropertyScopeGlobal;
22992  propAddress.mElement = kAudioObjectPropertyElementMaster;
22993 
22994  ma_mutex_init(pContext, &g_DeviceTrackingMutex_CoreAudio);
22995 
22996  propAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
22997  ((ma_AudioObjectAddPropertyListener_proc)pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
22998 
22999  propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
23000  ((ma_AudioObjectAddPropertyListener_proc)pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
23001  }
23002 
23003  return MA_SUCCESS;
23004 }
23005 
23006 static ma_result ma_context__uninit_device_tracking__coreaudio(ma_context* pContext)
23007 {
23008  MA_ASSERT(pContext != NULL);
23009 
23010  if (ma_atomic_decrement_32(&g_DeviceTrackingInitCounter_CoreAudio) == 0) {
23011  AudioObjectPropertyAddress propAddress;
23012  propAddress.mScope = kAudioObjectPropertyScopeGlobal;
23013  propAddress.mElement = kAudioObjectPropertyElementMaster;
23014 
23015  propAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
23016  ((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
23017 
23018  propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
23019  ((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
23020 
23021  /* At this point there should be no tracked devices. If so there's an error somewhere. */
23022  MA_ASSERT(g_ppTrackedDevices_CoreAudio == NULL);
23023  MA_ASSERT(g_TrackedDeviceCount_CoreAudio == 0);
23024 
23025  ma_mutex_uninit(&g_DeviceTrackingMutex_CoreAudio);
23026  }
23027 
23028  return MA_SUCCESS;
23029 }
23030 
23031 static ma_result ma_device__track__coreaudio(ma_device* pDevice)
23032 {
23033  ma_result result;
23034 
23035  MA_ASSERT(pDevice != NULL);
23036 
23037  result = ma_context__init_device_tracking__coreaudio(pDevice->pContext);
23038  if (result != MA_SUCCESS) {
23039  return result;
23040  }
23041 
23042  ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
23043  {
23044  /* Allocate memory if required. */
23045  if (g_TrackedDeviceCap_CoreAudio <= g_TrackedDeviceCount_CoreAudio) {
23046  ma_uint32 oldCap;
23047  ma_uint32 newCap;
23048  ma_device** ppNewDevices;
23049 
23050  oldCap = g_TrackedDeviceCap_CoreAudio;
23051  newCap = g_TrackedDeviceCap_CoreAudio * 2;
23052  if (newCap == 0) {
23053  newCap = 1;
23054  }
23055 
23056  ppNewDevices = (ma_device**)ma__realloc_from_callbacks(g_ppTrackedDevices_CoreAudio, sizeof(*g_ppTrackedDevices_CoreAudio)*newCap, sizeof(*g_ppTrackedDevices_CoreAudio)*oldCap, &pDevice->pContext->allocationCallbacks);
23057  if (ppNewDevices == NULL) {
23058  ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
23059  return MA_OUT_OF_MEMORY;
23060  }
23061 
23062  g_ppTrackedDevices_CoreAudio = ppNewDevices;
23063  g_TrackedDeviceCap_CoreAudio = newCap;
23064  }
23065 
23066  g_ppTrackedDevices_CoreAudio[g_TrackedDeviceCount_CoreAudio] = pDevice;
23067  g_TrackedDeviceCount_CoreAudio += 1;
23068  }
23069  ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
23070 
23071  return MA_SUCCESS;
23072 }
23073 
23074 static ma_result ma_device__untrack__coreaudio(ma_device* pDevice)
23075 {
23076  ma_result result;
23077 
23078  MA_ASSERT(pDevice != NULL);
23079 
23080  ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
23081  {
23082  ma_uint32 iDevice;
23083  for (iDevice = 0; iDevice < g_TrackedDeviceCount_CoreAudio; iDevice += 1) {
23084  if (g_ppTrackedDevices_CoreAudio[iDevice] == pDevice) {
23085  /* We've found the device. We now need to remove it from the list. */
23086  ma_uint32 jDevice;
23087  for (jDevice = iDevice; jDevice < g_TrackedDeviceCount_CoreAudio-1; jDevice += 1) {
23088  g_ppTrackedDevices_CoreAudio[jDevice] = g_ppTrackedDevices_CoreAudio[jDevice+1];
23089  }
23090 
23091  g_TrackedDeviceCount_CoreAudio -= 1;
23092 
23093  /* If there's nothing else in the list we need to free memory. */
23094  if (g_TrackedDeviceCount_CoreAudio == 0) {
23095  ma__free_from_callbacks(g_ppTrackedDevices_CoreAudio, &pDevice->pContext->allocationCallbacks);
23096  g_ppTrackedDevices_CoreAudio = NULL;
23097  g_TrackedDeviceCap_CoreAudio = 0;
23098  }
23099 
23100  break;
23101  }
23102  }
23103  }
23104  ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
23105 
23106  result = ma_context__uninit_device_tracking__coreaudio(pDevice->pContext);
23107  if (result != MA_SUCCESS) {
23108  return result;
23109  }
23110 
23111  return MA_SUCCESS;
23112 }
23113 #endif
23114 
23115 #if defined(MA_APPLE_MOBILE)
23116 @interface ma_router_change_handler:NSObject {
23117  ma_device* m_pDevice;
23118 }
23119 @end
23120 
23121 @implementation ma_router_change_handler
23122 -(id)init:(ma_device*)pDevice
23123 {
23124  self = [super init];
23125  m_pDevice = pDevice;
23126 
23127  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_route_change:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];
23128 
23129  return self;
23130 }
23131 
23132 -(void)dealloc
23133 {
23134  [self remove_handler];
23135 }
23136 
23137 -(void)remove_handler
23138 {
23139  [[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVAudioSessionRouteChangeNotification" object:nil];
23140 }
23141 
23142 -(void)handle_route_change:(NSNotification*)pNotification
23143 {
23144  AVAudioSession* pSession = [AVAudioSession sharedInstance];
23145 
23146  NSInteger reason = [[[pNotification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
23147  switch (reason)
23148  {
23149  case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
23150  {
23151  #if defined(MA_DEBUG_OUTPUT)
23152  printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n");
23153  #endif
23154  } break;
23155 
23156  case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
23157  {
23158  #if defined(MA_DEBUG_OUTPUT)
23159  printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n");
23160  #endif
23161  } break;
23162 
23163  case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
23164  {
23165  #if defined(MA_DEBUG_OUTPUT)
23166  printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory\n");
23167  #endif
23168  } break;
23169 
23170  case AVAudioSessionRouteChangeReasonWakeFromSleep:
23171  {
23172  #if defined(MA_DEBUG_OUTPUT)
23173  printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonWakeFromSleep\n");
23174  #endif
23175  } break;
23176 
23177  case AVAudioSessionRouteChangeReasonOverride:
23178  {
23179  #if defined(MA_DEBUG_OUTPUT)
23180  printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOverride\n");
23181  #endif
23182  } break;
23183 
23184  case AVAudioSessionRouteChangeReasonCategoryChange:
23185  {
23186  #if defined(MA_DEBUG_OUTPUT)
23187  printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n");
23188  #endif
23189  } break;
23190 
23191  case AVAudioSessionRouteChangeReasonUnknown:
23192  default:
23193  {
23194  #if defined(MA_DEBUG_OUTPUT)
23195  printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n");
23196  #endif
23197  } break;
23198  }
23199 
23200  m_pDevice->sampleRate = (ma_uint32)pSession.sampleRate;
23201 
23202  if (m_pDevice->type == ma_device_type_capture || m_pDevice->type == ma_device_type_duplex) {
23203  m_pDevice->capture.channels = (ma_uint32)pSession.inputNumberOfChannels;
23205  }
23206  if (m_pDevice->type == ma_device_type_playback || m_pDevice->type == ma_device_type_duplex) {
23207  m_pDevice->playback.channels = (ma_uint32)pSession.outputNumberOfChannels;
23209  }
23210 }
23211 @end
23212 #endif
23213 
23214 static void ma_device_uninit__coreaudio(ma_device* pDevice)
23215 {
23216  MA_ASSERT(pDevice != NULL);
23217  MA_ASSERT(ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED);
23218 
23219 #if defined(MA_APPLE_DESKTOP)
23220  /*
23221  Make sure we're no longer tracking the device. It doesn't matter if we call this for a non-default device because it'll
23222  just gracefully ignore it.
23223  */
23224  ma_device__untrack__coreaudio(pDevice);
23225 #endif
23226 #if defined(MA_APPLE_MOBILE)
23227  if (pDevice->coreaudio.pRouteChangeHandler != NULL) {
23228  ma_router_change_handler* pRouteChangeHandler = (__bridge_transfer ma_router_change_handler*)pDevice->coreaudio.pRouteChangeHandler;
23229  [pRouteChangeHandler remove_handler];
23230  }
23231 #endif
23232 
23233  if (pDevice->coreaudio.audioUnitCapture != NULL) {
23234  ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
23235  }
23236  if (pDevice->coreaudio.audioUnitPlayback != NULL) {
23237  ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
23238  }
23239 
23240  if (pDevice->coreaudio.pAudioBufferList) {
23241  ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
23242  }
23243 
23244  if (pDevice->type == ma_device_type_duplex) {
23245  ma_pcm_rb_uninit(&pDevice->coreaudio.duplexRB);
23246  }
23247 }
23248 
23249 typedef struct
23250 {
23251  /* Input. */
23252  ma_format formatIn;
23253  ma_uint32 channelsIn;
23254  ma_uint32 sampleRateIn;
23255  ma_channel channelMapIn[MA_MAX_CHANNELS];
23256  ma_uint32 periodSizeInFramesIn;
23257  ma_uint32 periodSizeInMillisecondsIn;
23258  ma_uint32 periodsIn;
23259  ma_bool32 usingDefaultFormat;
23260  ma_bool32 usingDefaultChannels;
23261  ma_bool32 usingDefaultSampleRate;
23262  ma_bool32 usingDefaultChannelMap;
23263  ma_share_mode shareMode;
23264  ma_bool32 registerStopEvent;
23265 
23266  /* Output. */
23267 #if defined(MA_APPLE_DESKTOP)
23268  AudioObjectID deviceObjectID;
23269 #endif
23270  AudioComponent component;
23271  AudioUnit audioUnit;
23272  AudioBufferList* pAudioBufferList; /* Only used for input devices. */
23273  ma_format formatOut;
23274  ma_uint32 channelsOut;
23275  ma_uint32 sampleRateOut;
23276  ma_channel channelMapOut[MA_MAX_CHANNELS];
23277  ma_uint32 periodSizeInFramesOut;
23278  ma_uint32 periodsOut;
23279  char deviceName[256];
23280 } ma_device_init_internal_data__coreaudio;
23281 
23282 static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_init_internal_data__coreaudio* pData, void* pDevice_DoNotReference) /* <-- pDevice is typed as void* intentionally so as to avoid accidentally referencing it. */
23283 {
23284  ma_result result;
23285  OSStatus status;
23286  UInt32 enableIOFlag;
23287  AudioStreamBasicDescription bestFormat;
23288  ma_uint32 actualPeriodSizeInFrames;
23289  AURenderCallbackStruct callbackInfo;
23290 #if defined(MA_APPLE_DESKTOP)
23291  AudioObjectID deviceObjectID;
23292 #endif
23293 
23294  /* This API should only be used for a single device type: playback or capture. No full-duplex mode. */
23295  if (deviceType == ma_device_type_duplex) {
23296  return MA_INVALID_ARGS;
23297  }
23298 
23299  MA_ASSERT(pContext != NULL);
23300  MA_ASSERT(deviceType == ma_device_type_playback || deviceType == ma_device_type_capture);
23301 
23302 #if defined(MA_APPLE_DESKTOP)
23303  pData->deviceObjectID = 0;
23304 #endif
23305  pData->component = NULL;
23306  pData->audioUnit = NULL;
23307  pData->pAudioBufferList = NULL;
23308 
23309 #if defined(MA_APPLE_DESKTOP)
23310  result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID);
23311  if (result != MA_SUCCESS) {
23312  return result;
23313  }
23314 
23315  pData->deviceObjectID = deviceObjectID;
23316 #endif
23317 
23318  /* Core audio doesn't really use the notion of a period so we can leave this unmodified, but not too over the top. */
23319  pData->periodsOut = pData->periodsIn;
23320  if (pData->periodsOut == 0) {
23321  pData->periodsOut = MA_DEFAULT_PERIODS;
23322  }
23323  if (pData->periodsOut > 16) {
23324  pData->periodsOut = 16;
23325  }
23326 
23327 
23328  /* Audio unit. */
23329  status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)((AudioComponent)pContext->coreaudio.component, (AudioUnit*)&pData->audioUnit);
23330  if (status != noErr) {
23331  return ma_result_from_OSStatus(status);
23332  }
23333 
23334 
23335  /* The input/output buses need to be explicitly enabled and disabled. We set the flag based on the output unit first, then we just swap it for input. */
23336  enableIOFlag = 1;
23337  if (deviceType == ma_device_type_capture) {
23338  enableIOFlag = 0;
23339  }
23340 
23341  status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));
23342  if (status != noErr) {
23343  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23344  return ma_result_from_OSStatus(status);
23345  }
23346 
23347  enableIOFlag = (enableIOFlag == 0) ? 1 : 0;
23348  status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));
23349  if (status != noErr) {
23350  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23351  return ma_result_from_OSStatus(status);
23352  }
23353 
23354 
23355  /* Set the device to use with this audio unit. This is only used on desktop since we are using defaults on mobile. */
23356 #if defined(MA_APPLE_DESKTOP)
23357  status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS, &deviceObjectID, sizeof(AudioDeviceID));
23358  if (status != noErr) {
23359  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23360  return ma_result_from_OSStatus(result);
23361  }
23362 #endif
23363 
23364  /*
23365  Format. This is the hardest part of initialization because there's a few variables to take into account.
23366  1) The format must be supported by the device.
23367  2) The format must be supported miniaudio.
23368  3) There's a priority that miniaudio prefers.
23369 
23370  Ideally we would like to use a format that's as close to the hardware as possible so we can get as close to a passthrough as possible. The
23371  most important property is the sample rate. miniaudio can do format conversion for any sample rate and channel count, but cannot do the same
23372  for the sample data format. If the sample data format is not supported by miniaudio it must be ignored completely.
23373 
23374  On mobile platforms this is a bit different. We just force the use of whatever the audio unit's current format is set to.
23375  */
23376  {
23377  AudioUnitScope formatScope = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
23378  AudioUnitElement formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;
23379 
23380  #if defined(MA_APPLE_DESKTOP)
23381  AudioStreamBasicDescription origFormat;
23382  UInt32 origFormatSize;
23383 
23384  result = ma_find_best_format__coreaudio(pContext, deviceObjectID, deviceType, pData->formatIn, pData->channelsIn, pData->sampleRateIn, pData->usingDefaultFormat, pData->usingDefaultChannels, pData->usingDefaultSampleRate, &bestFormat);
23385  if (result != MA_SUCCESS) {
23386  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23387  return result;
23388  }
23389 
23390  /* From what I can see, Apple's documentation implies that we should keep the sample rate consistent. */
23391  origFormatSize = sizeof(origFormat);
23392  if (deviceType == ma_device_type_playback) {
23393  status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &origFormat, &origFormatSize);
23394  } else {
23395  status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &origFormat, &origFormatSize);
23396  }
23397 
23398  if (status != noErr) {
23399  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23400  return result;
23401  }
23402 
23403  bestFormat.mSampleRate = origFormat.mSampleRate;
23404 
23405  status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
23406  if (status != noErr) {
23407  /* We failed to set the format, so fall back to the current format of the audio unit. */
23408  bestFormat = origFormat;
23409  }
23410  #else
23411  UInt32 propSize = sizeof(bestFormat);
23412  status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, &propSize);
23413  if (status != noErr) {
23414  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23415  return ma_result_from_OSStatus(status);
23416  }
23417 
23418  /*
23419  Sample rate is a little different here because for some reason kAudioUnitProperty_StreamFormat returns 0... Oh well. We need to instead try
23420  setting the sample rate to what the user has requested and then just see the results of it. Need to use some Objective-C here for this since
23421  it depends on Apple's AVAudioSession API. To do this we just get the shared AVAudioSession instance and then set it. Note that from what I
23422  can tell, it looks like the sample rate is shared between playback and capture for everything.
23423  */
23424  @autoreleasepool {
23425  AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
23426  MA_ASSERT(pAudioSession != NULL);
23427 
23428  [pAudioSession setPreferredSampleRate:(double)pData->sampleRateIn error:nil];
23429  bestFormat.mSampleRate = pAudioSession.sampleRate;
23430 
23431  /*
23432  I've had a report that the channel count returned by AudioUnitGetProperty above is inconsistent with
23433  AVAudioSession outputNumberOfChannels. I'm going to try using the AVAudioSession values instead.
23434  */
23435  if (deviceType == ma_device_type_playback) {
23436  bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.outputNumberOfChannels;
23437  }
23438  if (deviceType == ma_device_type_capture) {
23439  bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.inputNumberOfChannels;
23440  }
23441  }
23442 
23443  status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
23444  if (status != noErr) {
23445  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23446  return ma_result_from_OSStatus(status);
23447  }
23448  #endif
23449 
23450  result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pData->formatOut);
23451  if (result != MA_SUCCESS) {
23452  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23453  return result;
23454  }
23455 
23456  if (pData->formatOut == ma_format_unknown) {
23457  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23458  return MA_FORMAT_NOT_SUPPORTED;
23459  }
23460 
23461  pData->channelsOut = bestFormat.mChannelsPerFrame;
23462  pData->sampleRateOut = bestFormat.mSampleRate;
23463  }
23464 
23465  /*
23466  Internal channel map. This is weird in my testing. If I use the AudioObject to get the
23467  channel map, the channel descriptions are set to "Unknown" for some reason. To work around
23468  this it looks like retrieving it from the AudioUnit will work. However, and this is where
23469  it gets weird, it doesn't seem to work with capture devices, nor at all on iOS... Therefore
23470  I'm going to fall back to a default assumption in these cases.
23471  */
23472 #if defined(MA_APPLE_DESKTOP)
23473  result = ma_get_AudioUnit_channel_map(pContext, pData->audioUnit, deviceType, pData->channelMapOut);
23474  if (result != MA_SUCCESS) {
23475  #if 0
23476  /* Try falling back to the channel map from the AudioObject. */
23477  result = ma_get_AudioObject_channel_map(pContext, deviceObjectID, deviceType, pData->channelMapOut);
23478  if (result != MA_SUCCESS) {
23479  return result;
23480  }
23481  #else
23482  /* Fall back to default assumptions. */
23483  ma_get_standard_channel_map(ma_standard_channel_map_default, pData->channelsOut, pData->channelMapOut);
23484  #endif
23485  }
23486 #else
23487  /* TODO: Figure out how to get the channel map using AVAudioSession. */
23488  ma_get_standard_channel_map(ma_standard_channel_map_default, pData->channelsOut, pData->channelMapOut);
23489 #endif
23490 
23491 
23492  /* Buffer size. Not allowing this to be configurable on iOS. */
23493  actualPeriodSizeInFrames = pData->periodSizeInFramesIn;
23494 
23495 #if defined(MA_APPLE_DESKTOP)
23496  if (actualPeriodSizeInFrames == 0) {
23497  actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, pData->sampleRateOut);
23498  }
23499 
23500  result = ma_set_AudioObject_buffer_size_in_frames(pContext, deviceObjectID, deviceType, &actualPeriodSizeInFrames);
23501  if (result != MA_SUCCESS) {
23502  return result;
23503  }
23504 
23505  pData->periodSizeInFramesOut = actualPeriodSizeInFrames;
23506 #else
23507  actualPeriodSizeInFrames = 2048;
23508  pData->periodSizeInFramesOut = actualPeriodSizeInFrames;
23509 #endif
23510 
23511 
23512  /*
23513  During testing I discovered that the buffer size can be too big. You'll get an error like this:
23514 
23515  kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=4096, mMaxFramesPerSlice=512
23516 
23517  Note how inFramesToProcess is smaller than mMaxFramesPerSlice. To fix, we need to set kAudioUnitProperty_MaximumFramesPerSlice to that
23518  of the size of our buffer, or do it the other way around and set our buffer size to the kAudioUnitProperty_MaximumFramesPerSlice.
23519  */
23520  {
23521  /*AudioUnitScope propScope = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
23522  AudioUnitElement propBus = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;
23523 
23524  status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, propScope, propBus, &actualBufferSizeInFrames, sizeof(actualBufferSizeInFrames));
23525  if (status != noErr) {
23526  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23527  return ma_result_from_OSStatus(status);
23528  }*/
23529 
23530  status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &actualPeriodSizeInFrames, sizeof(actualPeriodSizeInFrames));
23531  if (status != noErr) {
23532  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23533  return ma_result_from_OSStatus(status);
23534  }
23535  }
23536 
23537  /* We need a buffer list if this is an input device. We render into this in the input callback. */
23538  if (deviceType == ma_device_type_capture) {
23539  ma_bool32 isInterleaved = (bestFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
23540  size_t allocationSize;
23541  AudioBufferList* pBufferList;
23542 
23543  allocationSize = sizeof(AudioBufferList) - sizeof(AudioBuffer); /* Subtract sizeof(AudioBuffer) because that part is dynamically sized. */
23544  if (isInterleaved) {
23545  /* Interleaved case. This is the simple case because we just have one buffer. */
23546  allocationSize += sizeof(AudioBuffer) * 1;
23547  allocationSize += actualPeriodSizeInFrames * ma_get_bytes_per_frame(pData->formatOut, pData->channelsOut);
23548  } else {
23549  /* Non-interleaved case. This is the more complex case because there's more than one buffer. */
23550  allocationSize += sizeof(AudioBuffer) * pData->channelsOut;
23551  allocationSize += actualPeriodSizeInFrames * ma_get_bytes_per_sample(pData->formatOut) * pData->channelsOut;
23552  }
23553 
23554  pBufferList = (AudioBufferList*)ma__malloc_from_callbacks(allocationSize, &pContext->allocationCallbacks);
23555  if (pBufferList == NULL) {
23556  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23557  return MA_OUT_OF_MEMORY;
23558  }
23559 
23560  if (isInterleaved) {
23561  pBufferList->mNumberBuffers = 1;
23562  pBufferList->mBuffers[0].mNumberChannels = pData->channelsOut;
23563  pBufferList->mBuffers[0].mDataByteSize = actualPeriodSizeInFrames * ma_get_bytes_per_frame(pData->formatOut, pData->channelsOut);
23564  pBufferList->mBuffers[0].mData = (ma_uint8*)pBufferList + sizeof(AudioBufferList);
23565  } else {
23566  ma_uint32 iBuffer;
23567  pBufferList->mNumberBuffers = pData->channelsOut;
23568  for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) {
23569  pBufferList->mBuffers[iBuffer].mNumberChannels = 1;
23570  pBufferList->mBuffers[iBuffer].mDataByteSize = actualPeriodSizeInFrames * ma_get_bytes_per_sample(pData->formatOut);
23571  pBufferList->mBuffers[iBuffer].mData = (ma_uint8*)pBufferList + ((sizeof(AudioBufferList) - sizeof(AudioBuffer)) + (sizeof(AudioBuffer) * pData->channelsOut)) + (actualPeriodSizeInFrames * ma_get_bytes_per_sample(pData->formatOut) * iBuffer);
23572  }
23573  }
23574 
23575  pData->pAudioBufferList = pBufferList;
23576  }
23577 
23578  /* Callbacks. */
23579  callbackInfo.inputProcRefCon = pDevice_DoNotReference;
23580  if (deviceType == ma_device_type_playback) {
23581  callbackInfo.inputProc = ma_on_output__coreaudio;
23582  status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, MA_COREAUDIO_OUTPUT_BUS, &callbackInfo, sizeof(callbackInfo));
23583  if (status != noErr) {
23584  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23585  return ma_result_from_OSStatus(status);
23586  }
23587  } else {
23588  callbackInfo.inputProc = ma_on_input__coreaudio;
23589  status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, MA_COREAUDIO_INPUT_BUS, &callbackInfo, sizeof(callbackInfo));
23590  if (status != noErr) {
23591  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23592  return ma_result_from_OSStatus(status);
23593  }
23594  }
23595 
23596  /* We need to listen for stop events. */
23597  if (pData->registerStopEvent) {
23598  status = ((ma_AudioUnitAddPropertyListener_proc)pContext->coreaudio.AudioUnitAddPropertyListener)(pData->audioUnit, kAudioOutputUnitProperty_IsRunning, on_start_stop__coreaudio, pDevice_DoNotReference);
23599  if (status != noErr) {
23600  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23601  return ma_result_from_OSStatus(status);
23602  }
23603  }
23604 
23605  /* Initialize the audio unit. */
23606  status = ((ma_AudioUnitInitialize_proc)pContext->coreaudio.AudioUnitInitialize)(pData->audioUnit);
23607  if (status != noErr) {
23608  ma__free_from_callbacks(pData->pAudioBufferList, &pContext->allocationCallbacks);
23609  pData->pAudioBufferList = NULL;
23610  ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
23611  return ma_result_from_OSStatus(status);
23612  }
23613 
23614  /* Grab the name. */
23615 #if defined(MA_APPLE_DESKTOP)
23616  ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(pData->deviceName), pData->deviceName);
23617 #else
23618  if (deviceType == ma_device_type_playback) {
23619  ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_PLAYBACK_DEVICE_NAME);
23620  } else {
23621  ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_CAPTURE_DEVICE_NAME);
23622  }
23623 #endif
23624 
23625  return result;
23626 }
23627 
23628 #if defined(MA_APPLE_DESKTOP)
23629 static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_device_type deviceType, ma_bool32 disposePreviousAudioUnit)
23630 {
23631  ma_device_init_internal_data__coreaudio data;
23632  ma_result result;
23633 
23634  /* This should only be called for playback or capture, not duplex. */
23635  if (deviceType == ma_device_type_duplex) {
23636  return MA_INVALID_ARGS;
23637  }
23638 
23639  if (deviceType == ma_device_type_capture) {
23640  data.formatIn = pDevice->capture.format;
23641  data.channelsIn = pDevice->capture.channels;
23642  data.sampleRateIn = pDevice->sampleRate;
23643  MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
23644  data.usingDefaultFormat = pDevice->capture.usingDefaultFormat;
23645  data.usingDefaultChannels = pDevice->capture.usingDefaultChannels;
23646  data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
23647  data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap;
23648  data.shareMode = pDevice->capture.shareMode;
23649  data.registerStopEvent = MA_TRUE;
23650 
23651  if (disposePreviousAudioUnit) {
23652  ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
23653  ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
23654  }
23655  if (pDevice->coreaudio.pAudioBufferList) {
23656  ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
23657  }
23658  } else if (deviceType == ma_device_type_playback) {
23659  data.formatIn = pDevice->playback.format;
23660  data.channelsIn = pDevice->playback.channels;
23661  data.sampleRateIn = pDevice->sampleRate;
23662  MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
23663  data.usingDefaultFormat = pDevice->playback.usingDefaultFormat;
23664  data.usingDefaultChannels = pDevice->playback.usingDefaultChannels;
23665  data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
23666  data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap;
23667  data.shareMode = pDevice->playback.shareMode;
23668  data.registerStopEvent = (pDevice->type != ma_device_type_duplex);
23669 
23670  if (disposePreviousAudioUnit) {
23671  ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
23672  ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
23673  }
23674  }
23675  data.periodSizeInFramesIn = pDevice->coreaudio.originalPeriodSizeInFrames;
23676  data.periodSizeInMillisecondsIn = pDevice->coreaudio.originalPeriodSizeInMilliseconds;
23677  data.periodsIn = pDevice->coreaudio.originalPeriods;
23678 
23679  /* Need at least 3 periods for duplex. */
23680  if (data.periodsIn < 3 && pDevice->type == ma_device_type_duplex) {
23681  data.periodsIn = 3;
23682  }
23683 
23684  result = ma_device_init_internal__coreaudio(pDevice->pContext, deviceType, NULL, &data, (void*)pDevice);
23685  if (result != MA_SUCCESS) {
23686  return result;
23687  }
23688 
23689  if (deviceType == ma_device_type_capture) {
23690  #if defined(MA_APPLE_DESKTOP)
23691  pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID;
23692  #endif
23693  pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit;
23694  pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList;
23695 
23696  pDevice->capture.internalFormat = data.formatOut;
23697  pDevice->capture.internalChannels = data.channelsOut;
23698  pDevice->capture.internalSampleRate = data.sampleRateOut;
23699  MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
23700  pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
23701  pDevice->capture.internalPeriods = data.periodsOut;
23702  } else if (deviceType == ma_device_type_playback) {
23703  #if defined(MA_APPLE_DESKTOP)
23704  pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID;
23705  #endif
23706  pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit;
23707 
23708  pDevice->playback.internalFormat = data.formatOut;
23709  pDevice->playback.internalChannels = data.channelsOut;
23710  pDevice->playback.internalSampleRate = data.sampleRateOut;
23711  MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
23712  pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
23713  pDevice->playback.internalPeriods = data.periodsOut;
23714  }
23715 
23716  return MA_SUCCESS;
23717 }
23718 #endif /* MA_APPLE_DESKTOP */
23719 
23720 static ma_result ma_device_init__coreaudio(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
23721 {
23722  ma_result result;
23723 
23724  MA_ASSERT(pContext != NULL);
23725  MA_ASSERT(pConfig != NULL);
23726  MA_ASSERT(pDevice != NULL);
23727 
23728  if (pConfig->deviceType == ma_device_type_loopback) {
23730  }
23731 
23732  /* No exclusive mode with the Core Audio backend for now. */
23736  }
23737 
23738  /* Capture needs to be initialized first. */
23739  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
23740  ma_device_init_internal_data__coreaudio data;
23741  data.formatIn = pConfig->capture.format;
23742  data.channelsIn = pConfig->capture.channels;
23743  data.sampleRateIn = pConfig->sampleRate;
23744  MA_COPY_MEMORY(data.channelMapIn, pConfig->capture.channelMap, sizeof(pConfig->capture.channelMap));
23745  data.usingDefaultFormat = pDevice->capture.usingDefaultFormat;
23746  data.usingDefaultChannels = pDevice->capture.usingDefaultChannels;
23747  data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
23748  data.usingDefaultChannelMap = pDevice->capture.usingDefaultChannelMap;
23749  data.shareMode = pConfig->capture.shareMode;
23750  data.periodSizeInFramesIn = pConfig->periodSizeInFrames;
23751  data.periodSizeInMillisecondsIn = pConfig->periodSizeInMilliseconds;
23752  data.periodsIn = pConfig->periods;
23753  data.registerStopEvent = MA_TRUE;
23754 
23755  /* Need at least 3 periods for duplex. */
23756  if (data.periodsIn < 3 && pConfig->deviceType == ma_device_type_duplex) {
23757  data.periodsIn = 3;
23758  }
23759 
23760  result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_capture, pConfig->capture.pDeviceID, &data, (void*)pDevice);
23761  if (result != MA_SUCCESS) {
23762  return result;
23763  }
23764 
23765  pDevice->coreaudio.isDefaultCaptureDevice = (pConfig->capture.pDeviceID == NULL);
23766  #if defined(MA_APPLE_DESKTOP)
23767  pDevice->coreaudio.deviceObjectIDCapture = (ma_uint32)data.deviceObjectID;
23768  #endif
23769  pDevice->coreaudio.audioUnitCapture = (ma_ptr)data.audioUnit;
23770  pDevice->coreaudio.pAudioBufferList = (ma_ptr)data.pAudioBufferList;
23771 
23772  pDevice->capture.internalFormat = data.formatOut;
23773  pDevice->capture.internalChannels = data.channelsOut;
23774  pDevice->capture.internalSampleRate = data.sampleRateOut;
23775  MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
23776  pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
23777  pDevice->capture.internalPeriods = data.periodsOut;
23778 
23779  #if defined(MA_APPLE_DESKTOP)
23780  /*
23781  If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
23782  switch the device in the background.
23783  */
23784  if (pConfig->capture.pDeviceID == NULL) {
23785  ma_device__track__coreaudio(pDevice);
23786  }
23787  #endif
23788  }
23789 
23790  /* Playback. */
23791  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
23792  ma_device_init_internal_data__coreaudio data;
23793  data.formatIn = pConfig->playback.format;
23794  data.channelsIn = pConfig->playback.channels;
23795  data.sampleRateIn = pConfig->sampleRate;
23796  MA_COPY_MEMORY(data.channelMapIn, pConfig->playback.channelMap, sizeof(pConfig->playback.channelMap));
23797  data.usingDefaultFormat = pDevice->playback.usingDefaultFormat;
23798  data.usingDefaultChannels = pDevice->playback.usingDefaultChannels;
23799  data.usingDefaultSampleRate = pDevice->usingDefaultSampleRate;
23800  data.usingDefaultChannelMap = pDevice->playback.usingDefaultChannelMap;
23801  data.shareMode = pConfig->playback.shareMode;
23802 
23803  /* In full-duplex mode we want the playback buffer to be the same size as the capture buffer. */
23804  if (pConfig->deviceType == ma_device_type_duplex) {
23805  data.periodSizeInFramesIn = pDevice->capture.internalPeriodSizeInFrames;
23806  data.periodsIn = pDevice->capture.internalPeriods;
23807  data.registerStopEvent = MA_FALSE;
23808  } else {
23809  data.periodSizeInFramesIn = pConfig->periodSizeInFrames;
23810  data.periodSizeInMillisecondsIn = pConfig->periodSizeInMilliseconds;
23811  data.periodsIn = pConfig->periods;
23812  data.registerStopEvent = MA_TRUE;
23813  }
23814 
23815  result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_playback, pConfig->playback.pDeviceID, &data, (void*)pDevice);
23816  if (result != MA_SUCCESS) {
23817  if (pConfig->deviceType == ma_device_type_duplex) {
23818  ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
23819  if (pDevice->coreaudio.pAudioBufferList) {
23820  ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
23821  }
23822  }
23823  return result;
23824  }
23825 
23826  pDevice->coreaudio.isDefaultPlaybackDevice = (pConfig->playback.pDeviceID == NULL);
23827  #if defined(MA_APPLE_DESKTOP)
23828  pDevice->coreaudio.deviceObjectIDPlayback = (ma_uint32)data.deviceObjectID;
23829  #endif
23830  pDevice->coreaudio.audioUnitPlayback = (ma_ptr)data.audioUnit;
23831 
23832  pDevice->playback.internalFormat = data.formatOut;
23833  pDevice->playback.internalChannels = data.channelsOut;
23834  pDevice->playback.internalSampleRate = data.sampleRateOut;
23835  MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
23836  pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
23837  pDevice->playback.internalPeriods = data.periodsOut;
23838 
23839  #if defined(MA_APPLE_DESKTOP)
23840  /*
23841  If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
23842  switch the device in the background.
23843  */
23844  if (pConfig->playback.pDeviceID == NULL && (pConfig->deviceType != ma_device_type_duplex || pConfig->capture.pDeviceID != NULL)) {
23845  ma_device__track__coreaudio(pDevice);
23846  }
23847  #endif
23848  }
23849 
23850  pDevice->coreaudio.originalPeriodSizeInFrames = pConfig->periodSizeInFrames;
23851  pDevice->coreaudio.originalPeriodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
23852  pDevice->coreaudio.originalPeriods = pConfig->periods;
23853 
23854  /*
23855  When stopping the device, a callback is called on another thread. We need to wait for this callback
23856  before returning from ma_device_stop(). This event is used for this.
23857  */
23858  ma_event_init(pContext, &pDevice->coreaudio.stopEvent);
23859 
23860  /* Need a ring buffer for duplex mode. */
23861  if (pConfig->deviceType == ma_device_type_duplex) {
23863  ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->coreaudio.duplexRB);
23864  if (result != MA_SUCCESS) {
23865  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[Core Audio] Failed to initialize ring buffer.", result);
23866  }
23867 
23868  /* We need a period to act as a buffer for cases where the playback and capture device's end up desyncing. */
23869  {
23870  ma_uint32 bufferSizeInFrames = rbSizeInFrames / pDevice->capture.internalPeriods;
23871  void* pBufferData;
23872  ma_pcm_rb_acquire_write(&pDevice->coreaudio.duplexRB, &bufferSizeInFrames, &pBufferData);
23873  {
23874  MA_ZERO_MEMORY(pBufferData, bufferSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
23875  }
23876  ma_pcm_rb_commit_write(&pDevice->coreaudio.duplexRB, bufferSizeInFrames, pBufferData);
23877  }
23878  }
23879 
23880  /*
23881  We need to detect when a route has changed so we can update the data conversion pipeline accordingly. This is done
23882  differently on non-Desktop Apple platforms.
23883  */
23884 #if defined(MA_APPLE_MOBILE)
23885  pDevice->coreaudio.pRouteChangeHandler = (__bridge_retained void*)[[ma_router_change_handler alloc] init:pDevice];
23886 #endif
23887 
23888  return MA_SUCCESS;
23889 }
23890 
23891 
23892 static ma_result ma_device_start__coreaudio(ma_device* pDevice)
23893 {
23894  MA_ASSERT(pDevice != NULL);
23895 
23896  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
23897  OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
23898  if (status != noErr) {
23899  return ma_result_from_OSStatus(status);
23900  }
23901  }
23902 
23903  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
23904  OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
23905  if (status != noErr) {
23906  if (pDevice->type == ma_device_type_duplex) {
23907  ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
23908  }
23909  return ma_result_from_OSStatus(status);
23910  }
23911  }
23912 
23913  return MA_SUCCESS;
23914 }
23915 
23916 static ma_result ma_device_stop__coreaudio(ma_device* pDevice)
23917 {
23918  MA_ASSERT(pDevice != NULL);
23919 
23920  /* It's not clear from the documentation whether or not AudioOutputUnitStop() actually drains the device or not. */
23921 
23922  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
23923  OSStatus status = ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
23924  if (status != noErr) {
23925  return ma_result_from_OSStatus(status);
23926  }
23927  }
23928 
23929  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
23930  OSStatus status = ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
23931  if (status != noErr) {
23932  return ma_result_from_OSStatus(status);
23933  }
23934  }
23935 
23936  /* We need to wait for the callback to finish before returning. */
23937  ma_event_wait(&pDevice->coreaudio.stopEvent);
23938  return MA_SUCCESS;
23939 }
23940 
23941 
23942 static ma_result ma_context_uninit__coreaudio(ma_context* pContext)
23943 {
23944  MA_ASSERT(pContext != NULL);
23945  MA_ASSERT(pContext->backend == ma_backend_coreaudio);
23946 
23947 #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
23948  ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
23949  ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
23950  ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
23951 #endif
23952 
23953  (void)pContext;
23954  return MA_SUCCESS;
23955 }
23956 
23957 #if defined(MA_APPLE_MOBILE)
23958 static AVAudioSessionCategory ma_to_AVAudioSessionCategory(ma_ios_session_category category)
23959 {
23960  /* The "default" and "none" categories are treated different and should not be used as an input into this function. */
23963 
23964  switch (category) {
23965  case ma_ios_session_category_ambient: return AVAudioSessionCategoryAmbient;
23966  case ma_ios_session_category_solo_ambient: return AVAudioSessionCategorySoloAmbient;
23967  case ma_ios_session_category_playback: return AVAudioSessionCategoryPlayback;
23968  case ma_ios_session_category_record: return AVAudioSessionCategoryRecord;
23969  case ma_ios_session_category_play_and_record: return AVAudioSessionCategoryPlayAndRecord;
23970  case ma_ios_session_category_multi_route: return AVAudioSessionCategoryMultiRoute;
23971  case ma_ios_session_category_none: return AVAudioSessionCategoryAmbient;
23972  case ma_ios_session_category_default: return AVAudioSessionCategoryAmbient;
23973  default: return AVAudioSessionCategoryAmbient;
23974  }
23975 }
23976 #endif
23977 
23978 static ma_result ma_context_init__coreaudio(const ma_context_config* pConfig, ma_context* pContext)
23979 {
23980  MA_ASSERT(pConfig != NULL);
23981  MA_ASSERT(pContext != NULL);
23982 
23983 #if defined(MA_APPLE_MOBILE)
23984  @autoreleasepool {
23985  AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
23986  AVAudioSessionCategoryOptions options = pConfig->coreaudio.sessionCategoryOptions;
23987 
23988  MA_ASSERT(pAudioSession != NULL);
23989 
23991  /*
23992  I'm going to use trial and error to determine our default session category. First we'll try PlayAndRecord. If that fails
23993  we'll try Playback and if that fails we'll try record. If all of these fail we'll just not set the category.
23994  */
23995  #if !defined(MA_APPLE_TV) && !defined(MA_APPLE_WATCH)
23996  options |= AVAudioSessionCategoryOptionDefaultToSpeaker;
23997  #endif
23998 
23999  if ([pAudioSession setCategory: AVAudioSessionCategoryPlayAndRecord withOptions:options error:nil]) {
24000  /* Using PlayAndRecord */
24001  } else if ([pAudioSession setCategory: AVAudioSessionCategoryPlayback withOptions:options error:nil]) {
24002  /* Using Playback */
24003  } else if ([pAudioSession setCategory: AVAudioSessionCategoryRecord withOptions:options error:nil]) {
24004  /* Using Record */
24005  } else {
24006  /* Leave as default? */
24007  }
24008  } else {
24010  if (![pAudioSession setCategory: ma_to_AVAudioSessionCategory(pConfig->coreaudio.sessionCategory) withOptions:options error:nil]) {
24011  return MA_INVALID_OPERATION; /* Failed to set session category. */
24012  }
24013  }
24014  }
24015  }
24016 #endif
24017 
24018 #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
24019  pContext->coreaudio.hCoreFoundation = ma_dlopen(pContext, "CoreFoundation.framework/CoreFoundation");
24020  if (pContext->coreaudio.hCoreFoundation == NULL) {
24021  return MA_API_NOT_FOUND;
24022  }
24023 
24024  pContext->coreaudio.CFStringGetCString = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFStringGetCString");
24025  pContext->coreaudio.CFRelease = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFRelease");
24026 
24027 
24028  pContext->coreaudio.hCoreAudio = ma_dlopen(pContext, "CoreAudio.framework/CoreAudio");
24029  if (pContext->coreaudio.hCoreAudio == NULL) {
24030  ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
24031  return MA_API_NOT_FOUND;
24032  }
24033 
24034  pContext->coreaudio.AudioObjectGetPropertyData = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyData");
24035  pContext->coreaudio.AudioObjectGetPropertyDataSize = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize");
24036  pContext->coreaudio.AudioObjectSetPropertyData = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectSetPropertyData");
24037  pContext->coreaudio.AudioObjectAddPropertyListener = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener");
24038  pContext->coreaudio.AudioObjectRemovePropertyListener = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectRemovePropertyListener");
24039 
24040  /*
24041  It looks like Apple has moved some APIs from AudioUnit into AudioToolbox on more recent versions of macOS. They are still
24042  defined in AudioUnit, but just in case they decide to remove them from there entirely I'm going to implement a fallback.
24043  The way it'll work is that it'll first try AudioUnit, and if the required symbols are not present there we'll fall back to
24044  AudioToolbox.
24045  */
24046  pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioUnit.framework/AudioUnit");
24047  if (pContext->coreaudio.hAudioUnit == NULL) {
24048  ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
24049  ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
24050  return MA_API_NOT_FOUND;
24051  }
24052 
24053  if (ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext") == NULL) {
24054  /* Couldn't find the required symbols in AudioUnit, so fall back to AudioToolbox. */
24055  ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
24056  pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioToolbox.framework/AudioToolbox");
24057  if (pContext->coreaudio.hAudioUnit == NULL) {
24058  ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
24059  ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
24060  return MA_API_NOT_FOUND;
24061  }
24062  }
24063 
24064  pContext->coreaudio.AudioComponentFindNext = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext");
24065  pContext->coreaudio.AudioComponentInstanceDispose = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceDispose");
24066  pContext->coreaudio.AudioComponentInstanceNew = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceNew");
24067  pContext->coreaudio.AudioOutputUnitStart = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStart");
24068  pContext->coreaudio.AudioOutputUnitStop = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStop");
24069  pContext->coreaudio.AudioUnitAddPropertyListener = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitAddPropertyListener");
24070  pContext->coreaudio.AudioUnitGetPropertyInfo = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetPropertyInfo");
24071  pContext->coreaudio.AudioUnitGetProperty = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetProperty");
24072  pContext->coreaudio.AudioUnitSetProperty = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitSetProperty");
24073  pContext->coreaudio.AudioUnitInitialize = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitInitialize");
24074  pContext->coreaudio.AudioUnitRender = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitRender");
24075 #else
24076  pContext->coreaudio.CFStringGetCString = (ma_proc)CFStringGetCString;
24077  pContext->coreaudio.CFRelease = (ma_proc)CFRelease;
24078 
24079  #if defined(MA_APPLE_DESKTOP)
24080  pContext->coreaudio.AudioObjectGetPropertyData = (ma_proc)AudioObjectGetPropertyData;
24081  pContext->coreaudio.AudioObjectGetPropertyDataSize = (ma_proc)AudioObjectGetPropertyDataSize;
24082  pContext->coreaudio.AudioObjectSetPropertyData = (ma_proc)AudioObjectSetPropertyData;
24083  pContext->coreaudio.AudioObjectAddPropertyListener = (ma_proc)AudioObjectAddPropertyListener;
24084  pContext->coreaudio.AudioObjectRemovePropertyListener = (ma_proc)AudioObjectRemovePropertyListener;
24085  #endif
24086 
24087  pContext->coreaudio.AudioComponentFindNext = (ma_proc)AudioComponentFindNext;
24088  pContext->coreaudio.AudioComponentInstanceDispose = (ma_proc)AudioComponentInstanceDispose;
24089  pContext->coreaudio.AudioComponentInstanceNew = (ma_proc)AudioComponentInstanceNew;
24090  pContext->coreaudio.AudioOutputUnitStart = (ma_proc)AudioOutputUnitStart;
24091  pContext->coreaudio.AudioOutputUnitStop = (ma_proc)AudioOutputUnitStop;
24092  pContext->coreaudio.AudioUnitAddPropertyListener = (ma_proc)AudioUnitAddPropertyListener;
24093  pContext->coreaudio.AudioUnitGetPropertyInfo = (ma_proc)AudioUnitGetPropertyInfo;
24094  pContext->coreaudio.AudioUnitGetProperty = (ma_proc)AudioUnitGetProperty;
24095  pContext->coreaudio.AudioUnitSetProperty = (ma_proc)AudioUnitSetProperty;
24096  pContext->coreaudio.AudioUnitInitialize = (ma_proc)AudioUnitInitialize;
24097  pContext->coreaudio.AudioUnitRender = (ma_proc)AudioUnitRender;
24098 #endif
24099 
24100  pContext->isBackendAsynchronous = MA_TRUE;
24101 
24102  pContext->onUninit = ma_context_uninit__coreaudio;
24103  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__coreaudio;
24104  pContext->onEnumDevices = ma_context_enumerate_devices__coreaudio;
24105  pContext->onGetDeviceInfo = ma_context_get_device_info__coreaudio;
24106  pContext->onDeviceInit = ma_device_init__coreaudio;
24107  pContext->onDeviceUninit = ma_device_uninit__coreaudio;
24108  pContext->onDeviceStart = ma_device_start__coreaudio;
24109  pContext->onDeviceStop = ma_device_stop__coreaudio;
24110 
24111  /* Audio component. */
24112  {
24113  AudioComponentDescription desc;
24114  desc.componentType = kAudioUnitType_Output;
24115  #if defined(MA_APPLE_DESKTOP)
24116  desc.componentSubType = kAudioUnitSubType_HALOutput;
24117  #else
24118  desc.componentSubType = kAudioUnitSubType_RemoteIO;
24119  #endif
24120  desc.componentManufacturer = kAudioUnitManufacturer_Apple;
24121  desc.componentFlags = 0;
24122  desc.componentFlagsMask = 0;
24123 
24124  pContext->coreaudio.component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc);
24125  if (pContext->coreaudio.component == NULL) {
24126  #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
24127  ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
24128  ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
24129  ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
24130  #endif
24132  }
24133  }
24134 
24135  return MA_SUCCESS;
24136 }
24137 #endif /* Core Audio */
24138 
24139 
24140 
24141 /******************************************************************************
24142 
24143 sndio Backend
24144 
24145 ******************************************************************************/
24146 #ifdef MA_HAS_SNDIO
24147 #include <fcntl.h>
24148 #include <sys/stat.h>
24149 
24150 /*
24151 Only supporting OpenBSD. This did not work very well at all on FreeBSD when I tried it. Not sure if this is due
24152 to miniaudio's implementation or if it's some kind of system configuration issue, but basically the default device
24153 just doesn't emit any sound, or at times you'll hear tiny pieces. I will consider enabling this when there's
24154 demand for it or if I can get it tested and debugged more thoroughly.
24155 */
24156 #if 0
24157 #if defined(__NetBSD__) || defined(__OpenBSD__)
24158 #include <sys/audioio.h>
24159 #endif
24160 #if defined(__FreeBSD__) || defined(__DragonFly__)
24161 #include <sys/soundcard.h>
24162 #endif
24163 #endif
24164 
24165 #define MA_SIO_DEVANY "default"
24166 #define MA_SIO_PLAY 1
24167 #define MA_SIO_REC 2
24168 #define MA_SIO_NENC 8
24169 #define MA_SIO_NCHAN 8
24170 #define MA_SIO_NRATE 16
24171 #define MA_SIO_NCONF 4
24172 
24173 struct ma_sio_hdl; /* <-- Opaque */
24174 
24175 struct ma_sio_par
24176 {
24177  unsigned int bits;
24178  unsigned int bps;
24179  unsigned int sig;
24180  unsigned int le;
24181  unsigned int msb;
24182  unsigned int rchan;
24183  unsigned int pchan;
24184  unsigned int rate;
24185  unsigned int bufsz;
24186  unsigned int xrun;
24187  unsigned int round;
24188  unsigned int appbufsz;
24189  int __pad[3];
24190  unsigned int __magic;
24191 };
24192 
24193 struct ma_sio_enc
24194 {
24195  unsigned int bits;
24196  unsigned int bps;
24197  unsigned int sig;
24198  unsigned int le;
24199  unsigned int msb;
24200 };
24201 
24202 struct ma_sio_conf
24203 {
24204  unsigned int enc;
24205  unsigned int rchan;
24206  unsigned int pchan;
24207  unsigned int rate;
24208 };
24209 
24210 struct ma_sio_cap
24211 {
24212  struct ma_sio_enc enc[MA_SIO_NENC];
24213  unsigned int rchan[MA_SIO_NCHAN];
24214  unsigned int pchan[MA_SIO_NCHAN];
24215  unsigned int rate[MA_SIO_NRATE];
24216  int __pad[7];
24217  unsigned int nconf;
24218  struct ma_sio_conf confs[MA_SIO_NCONF];
24219 };
24220 
24221 typedef struct ma_sio_hdl* (* ma_sio_open_proc) (const char*, unsigned int, int);
24222 typedef void (* ma_sio_close_proc) (struct ma_sio_hdl*);
24223 typedef int (* ma_sio_setpar_proc) (struct ma_sio_hdl*, struct ma_sio_par*);
24224 typedef int (* ma_sio_getpar_proc) (struct ma_sio_hdl*, struct ma_sio_par*);
24225 typedef int (* ma_sio_getcap_proc) (struct ma_sio_hdl*, struct ma_sio_cap*);
24226 typedef size_t (* ma_sio_write_proc) (struct ma_sio_hdl*, const void*, size_t);
24227 typedef size_t (* ma_sio_read_proc) (struct ma_sio_hdl*, void*, size_t);
24228 typedef int (* ma_sio_start_proc) (struct ma_sio_hdl*);
24229 typedef int (* ma_sio_stop_proc) (struct ma_sio_hdl*);
24230 typedef int (* ma_sio_initpar_proc)(struct ma_sio_par*);
24231 
24232 static ma_uint32 ma_get_standard_sample_rate_priority_index__sndio(ma_uint32 sampleRate) /* Lower = higher priority */
24233 {
24234  ma_uint32 i;
24235  for (i = 0; i < ma_countof(g_maStandardSampleRatePriorities); ++i) {
24236  if (g_maStandardSampleRatePriorities[i] == sampleRate) {
24237  return i;
24238  }
24239  }
24240 
24241  return (ma_uint32)-1;
24242 }
24243 
24244 static ma_format ma_format_from_sio_enc__sndio(unsigned int bits, unsigned int bps, unsigned int sig, unsigned int le, unsigned int msb)
24245 {
24246  /* We only support native-endian right now. */
24247  if ((ma_is_little_endian() && le == 0) || (ma_is_big_endian() && le == 1)) {
24248  return ma_format_unknown;
24249  }
24250 
24251  if (bits == 8 && bps == 1 && sig == 0) {
24252  return ma_format_u8;
24253  }
24254  if (bits == 16 && bps == 2 && sig == 1) {
24255  return ma_format_s16;
24256  }
24257  if (bits == 24 && bps == 3 && sig == 1) {
24258  return ma_format_s24;
24259  }
24260  if (bits == 24 && bps == 4 && sig == 1 && msb == 0) {
24261  /*return ma_format_s24_32;*/
24262  }
24263  if (bits == 32 && bps == 4 && sig == 1) {
24264  return ma_format_s32;
24265  }
24266 
24267  return ma_format_unknown;
24268 }
24269 
24270 static ma_format ma_find_best_format_from_sio_cap__sndio(struct ma_sio_cap* caps)
24271 {
24272  ma_format bestFormat;
24273  unsigned int iConfig;
24274 
24275  MA_ASSERT(caps != NULL);
24276 
24277  bestFormat = ma_format_unknown;
24278  for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) {
24279  unsigned int iEncoding;
24280  for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
24281  unsigned int bits;
24282  unsigned int bps;
24283  unsigned int sig;
24284  unsigned int le;
24285  unsigned int msb;
24286  ma_format format;
24287 
24288  if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) {
24289  continue;
24290  }
24291 
24292  bits = caps->enc[iEncoding].bits;
24293  bps = caps->enc[iEncoding].bps;
24294  sig = caps->enc[iEncoding].sig;
24295  le = caps->enc[iEncoding].le;
24296  msb = caps->enc[iEncoding].msb;
24297  format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
24298  if (format == ma_format_unknown) {
24299  continue; /* Format not supported. */
24300  }
24301 
24302  if (bestFormat == ma_format_unknown) {
24303  bestFormat = format;
24304  } else {
24305  if (ma_get_format_priority_index(bestFormat) > ma_get_format_priority_index(format)) { /* <-- Lower = better. */
24306  bestFormat = format;
24307  }
24308  }
24309  }
24310  }
24311 
24312  return bestFormat;
24313 }
24314 
24315 static ma_uint32 ma_find_best_channels_from_sio_cap__sndio(struct ma_sio_cap* caps, ma_device_type deviceType, ma_format requiredFormat)
24316 {
24317  ma_uint32 maxChannels;
24318  unsigned int iConfig;
24319 
24320  MA_ASSERT(caps != NULL);
24321  MA_ASSERT(requiredFormat != ma_format_unknown);
24322 
24323  /* Just pick whatever configuration has the most channels. */
24324  maxChannels = 0;
24325  for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) {
24326  /* The encoding should be of requiredFormat. */
24327  unsigned int iEncoding;
24328  for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
24329  unsigned int iChannel;
24330  unsigned int bits;
24331  unsigned int bps;
24332  unsigned int sig;
24333  unsigned int le;
24334  unsigned int msb;
24335  ma_format format;
24336 
24337  if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) {
24338  continue;
24339  }
24340 
24341  bits = caps->enc[iEncoding].bits;
24342  bps = caps->enc[iEncoding].bps;
24343  sig = caps->enc[iEncoding].sig;
24344  le = caps->enc[iEncoding].le;
24345  msb = caps->enc[iEncoding].msb;
24346  format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
24347  if (format != requiredFormat) {
24348  continue;
24349  }
24350 
24351  /* Getting here means the format is supported. Iterate over each channel count and grab the biggest one. */
24352  for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) {
24353  unsigned int chan = 0;
24354  unsigned int channels;
24355 
24356  if (deviceType == ma_device_type_playback) {
24357  chan = caps->confs[iConfig].pchan;
24358  } else {
24359  chan = caps->confs[iConfig].rchan;
24360  }
24361 
24362  if ((chan & (1UL << iChannel)) == 0) {
24363  continue;
24364  }
24365 
24366  if (deviceType == ma_device_type_playback) {
24367  channels = caps->pchan[iChannel];
24368  } else {
24369  channels = caps->rchan[iChannel];
24370  }
24371 
24372  if (maxChannels < channels) {
24373  maxChannels = channels;
24374  }
24375  }
24376  }
24377  }
24378 
24379  return maxChannels;
24380 }
24381 
24382 static ma_uint32 ma_find_best_sample_rate_from_sio_cap__sndio(struct ma_sio_cap* caps, ma_device_type deviceType, ma_format requiredFormat, ma_uint32 requiredChannels)
24383 {
24384  ma_uint32 firstSampleRate;
24385  ma_uint32 bestSampleRate;
24386  unsigned int iConfig;
24387 
24388  MA_ASSERT(caps != NULL);
24389  MA_ASSERT(requiredFormat != ma_format_unknown);
24390  MA_ASSERT(requiredChannels > 0);
24391  MA_ASSERT(requiredChannels <= MA_MAX_CHANNELS);
24392 
24393  firstSampleRate = 0; /* <-- If the device does not support a standard rate we'll fall back to the first one that's found. */
24394  bestSampleRate = 0;
24395 
24396  for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) {
24397  /* The encoding should be of requiredFormat. */
24398  unsigned int iEncoding;
24399  for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
24400  unsigned int iChannel;
24401  unsigned int bits;
24402  unsigned int bps;
24403  unsigned int sig;
24404  unsigned int le;
24405  unsigned int msb;
24406  ma_format format;
24407 
24408  if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) {
24409  continue;
24410  }
24411 
24412  bits = caps->enc[iEncoding].bits;
24413  bps = caps->enc[iEncoding].bps;
24414  sig = caps->enc[iEncoding].sig;
24415  le = caps->enc[iEncoding].le;
24416  msb = caps->enc[iEncoding].msb;
24417  format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
24418  if (format != requiredFormat) {
24419  continue;
24420  }
24421 
24422  /* Getting here means the format is supported. Iterate over each channel count and grab the biggest one. */
24423  for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) {
24424  unsigned int chan = 0;
24425  unsigned int channels;
24426  unsigned int iRate;
24427 
24428  if (deviceType == ma_device_type_playback) {
24429  chan = caps->confs[iConfig].pchan;
24430  } else {
24431  chan = caps->confs[iConfig].rchan;
24432  }
24433 
24434  if ((chan & (1UL << iChannel)) == 0) {
24435  continue;
24436  }
24437 
24438  if (deviceType == ma_device_type_playback) {
24439  channels = caps->pchan[iChannel];
24440  } else {
24441  channels = caps->rchan[iChannel];
24442  }
24443 
24444  if (channels != requiredChannels) {
24445  continue;
24446  }
24447 
24448  /* Getting here means we have found a compatible encoding/channel pair. */
24449  for (iRate = 0; iRate < MA_SIO_NRATE; iRate += 1) {
24450  ma_uint32 rate = (ma_uint32)caps->rate[iRate];
24451  ma_uint32 ratePriority;
24452 
24453  if (firstSampleRate == 0) {
24454  firstSampleRate = rate;
24455  }
24456 
24457  /* Disregard this rate if it's not a standard one. */
24458  ratePriority = ma_get_standard_sample_rate_priority_index__sndio(rate);
24459  if (ratePriority == (ma_uint32)-1) {
24460  continue;
24461  }
24462 
24463  if (ma_get_standard_sample_rate_priority_index__sndio(bestSampleRate) > ratePriority) { /* Lower = better. */
24464  bestSampleRate = rate;
24465  }
24466  }
24467  }
24468  }
24469  }
24470 
24471  /* If a standard sample rate was not found just fall back to the first one that was iterated. */
24472  if (bestSampleRate == 0) {
24473  bestSampleRate = firstSampleRate;
24474  }
24475 
24476  return bestSampleRate;
24477 }
24478 
24479 
24480 static ma_bool32 ma_context_is_device_id_equal__sndio(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
24481 {
24482  MA_ASSERT(pContext != NULL);
24483  MA_ASSERT(pID0 != NULL);
24484  MA_ASSERT(pID1 != NULL);
24485  (void)pContext;
24486 
24487  return ma_strcmp(pID0->sndio, pID1->sndio) == 0;
24488 }
24489 
24490 static ma_result ma_context_enumerate_devices__sndio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
24491 {
24492  ma_bool32 isTerminating = MA_FALSE;
24493  struct ma_sio_hdl* handle;
24494 
24495  MA_ASSERT(pContext != NULL);
24496  MA_ASSERT(callback != NULL);
24497 
24498  /* sndio doesn't seem to have a good device enumeration API, so I'm therefore only enumerating over default devices for now. */
24499 
24500  /* Playback. */
24501  if (!isTerminating) {
24502  handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(MA_SIO_DEVANY, MA_SIO_PLAY, 0);
24503  if (handle != NULL) {
24504  /* Supports playback. */
24505  ma_device_info deviceInfo;
24506  MA_ZERO_OBJECT(&deviceInfo);
24507  ma_strcpy_s(deviceInfo.id.sndio, sizeof(deviceInfo.id.sndio), MA_SIO_DEVANY);
24508  ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME);
24509 
24510  isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
24511 
24512  ((ma_sio_close_proc)pContext->sndio.sio_close)(handle);
24513  }
24514  }
24515 
24516  /* Capture. */
24517  if (!isTerminating) {
24518  handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(MA_SIO_DEVANY, MA_SIO_REC, 0);
24519  if (handle != NULL) {
24520  /* Supports capture. */
24521  ma_device_info deviceInfo;
24522  MA_ZERO_OBJECT(&deviceInfo);
24523  ma_strcpy_s(deviceInfo.id.sndio, sizeof(deviceInfo.id.sndio), "default");
24524  ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME);
24525 
24526  isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
24527 
24528  ((ma_sio_close_proc)pContext->sndio.sio_close)(handle);
24529  }
24530  }
24531 
24532  return MA_SUCCESS;
24533 }
24534 
24535 static ma_result ma_context_get_device_info__sndio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
24536 {
24537  char devid[256];
24538  struct ma_sio_hdl* handle;
24539  struct ma_sio_cap caps;
24540  unsigned int iConfig;
24541 
24542  MA_ASSERT(pContext != NULL);
24543  (void)shareMode;
24544 
24545  /* We need to open the device before we can get information about it. */
24546  if (pDeviceID == NULL) {
24547  ma_strcpy_s(devid, sizeof(devid), MA_SIO_DEVANY);
24548  ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (deviceType == ma_device_type_playback) ? MA_DEFAULT_PLAYBACK_DEVICE_NAME : MA_DEFAULT_CAPTURE_DEVICE_NAME);
24549  } else {
24550  ma_strcpy_s(devid, sizeof(devid), pDeviceID->sndio);
24551  ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), devid);
24552  }
24553 
24554  handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(devid, (deviceType == ma_device_type_playback) ? MA_SIO_PLAY : MA_SIO_REC, 0);
24555  if (handle == NULL) {
24556  return MA_NO_DEVICE;
24557  }
24558 
24559  if (((ma_sio_getcap_proc)pContext->sndio.sio_getcap)(handle, &caps) == 0) {
24560  return MA_ERROR;
24561  }
24562 
24563  for (iConfig = 0; iConfig < caps.nconf; iConfig += 1) {
24564  /*
24565  The main thing we care about is that the encoding is supported by miniaudio. If it is, we want to give
24566  preference to some formats over others.
24567  */
24568  unsigned int iEncoding;
24569  unsigned int iChannel;
24570  unsigned int iRate;
24571 
24572  for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
24573  unsigned int bits;
24574  unsigned int bps;
24575  unsigned int sig;
24576  unsigned int le;
24577  unsigned int msb;
24578  ma_format format;
24579  ma_bool32 formatExists = MA_FALSE;
24580  ma_uint32 iExistingFormat;
24581 
24582  if ((caps.confs[iConfig].enc & (1UL << iEncoding)) == 0) {
24583  continue;
24584  }
24585 
24586  bits = caps.enc[iEncoding].bits;
24587  bps = caps.enc[iEncoding].bps;
24588  sig = caps.enc[iEncoding].sig;
24589  le = caps.enc[iEncoding].le;
24590  msb = caps.enc[iEncoding].msb;
24591  format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
24592  if (format == ma_format_unknown) {
24593  continue; /* Format not supported. */
24594  }
24595 
24596  /* Add this format if it doesn't already exist. */
24597  for (iExistingFormat = 0; iExistingFormat < pDeviceInfo->formatCount; iExistingFormat += 1) {
24598  if (pDeviceInfo->formats[iExistingFormat] == format) {
24599  formatExists = MA_TRUE;
24600  break;
24601  }
24602  }
24603 
24604  if (!formatExists) {
24605  pDeviceInfo->formats[pDeviceInfo->formatCount++] = format;
24606  }
24607  }
24608 
24609  /* Channels. */
24610  for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) {
24611  unsigned int chan = 0;
24612  unsigned int channels;
24613 
24614  if (deviceType == ma_device_type_playback) {
24615  chan = caps.confs[iConfig].pchan;
24616  } else {
24617  chan = caps.confs[iConfig].rchan;
24618  }
24619 
24620  if ((chan & (1UL << iChannel)) == 0) {
24621  continue;
24622  }
24623 
24624  if (deviceType == ma_device_type_playback) {
24625  channels = caps.pchan[iChannel];
24626  } else {
24627  channels = caps.rchan[iChannel];
24628  }
24629 
24630  if (pDeviceInfo->minChannels > channels) {
24631  pDeviceInfo->minChannels = channels;
24632  }
24633  if (pDeviceInfo->maxChannels < channels) {
24634  pDeviceInfo->maxChannels = channels;
24635  }
24636  }
24637 
24638  /* Sample rates. */
24639  for (iRate = 0; iRate < MA_SIO_NRATE; iRate += 1) {
24640  if ((caps.confs[iConfig].rate & (1UL << iRate)) != 0) {
24641  unsigned int rate = caps.rate[iRate];
24642  if (pDeviceInfo->minSampleRate > rate) {
24643  pDeviceInfo->minSampleRate = rate;
24644  }
24645  if (pDeviceInfo->maxSampleRate < rate) {
24646  pDeviceInfo->maxSampleRate = rate;
24647  }
24648  }
24649  }
24650  }
24651 
24652  ((ma_sio_close_proc)pContext->sndio.sio_close)(handle);
24653  return MA_SUCCESS;
24654 }
24655 
24656 static void ma_device_uninit__sndio(ma_device* pDevice)
24657 {
24658  MA_ASSERT(pDevice != NULL);
24659 
24660  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
24661  ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handleCapture);
24662  }
24663 
24664  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
24665  ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback);
24666  }
24667 }
24668 
24669 static ma_result ma_device_init_handle__sndio(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice)
24670 {
24671  const char* pDeviceName;
24672  ma_ptr handle;
24673  int openFlags = 0;
24674  struct ma_sio_cap caps;
24675  struct ma_sio_par par;
24676  ma_device_id* pDeviceID;
24677  ma_format format;
24678  ma_uint32 channels;
24679  ma_uint32 sampleRate;
24680  ma_format internalFormat;
24681  ma_uint32 internalChannels;
24682  ma_uint32 internalSampleRate;
24683  ma_uint32 internalPeriodSizeInFrames;
24684  ma_uint32 internalPeriods;
24685 
24686  MA_ASSERT(pContext != NULL);
24687  MA_ASSERT(pConfig != NULL);
24688  MA_ASSERT(deviceType != ma_device_type_duplex);
24689  MA_ASSERT(pDevice != NULL);
24690 
24691  if (deviceType == ma_device_type_capture) {
24692  openFlags = MA_SIO_REC;
24693  pDeviceID = pConfig->capture.pDeviceID;
24694  format = pConfig->capture.format;
24695  channels = pConfig->capture.channels;
24696  sampleRate = pConfig->sampleRate;
24697  } else {
24698  openFlags = MA_SIO_PLAY;
24699  pDeviceID = pConfig->playback.pDeviceID;
24700  format = pConfig->playback.format;
24701  channels = pConfig->playback.channels;
24702  sampleRate = pConfig->sampleRate;
24703  }
24704 
24705  pDeviceName = MA_SIO_DEVANY;
24706  if (pDeviceID != NULL) {
24707  pDeviceName = pDeviceID->sndio;
24708  }
24709 
24710  handle = (ma_ptr)((ma_sio_open_proc)pContext->sndio.sio_open)(pDeviceName, openFlags, 0);
24711  if (handle == NULL) {
24712  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to open device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
24713  }
24714 
24715  /* We need to retrieve the device caps to determine the most appropriate format to use. */
24716  if (((ma_sio_getcap_proc)pContext->sndio.sio_getcap)((struct ma_sio_hdl*)handle, &caps) == 0) {
24717  ((ma_sio_close_proc)pContext->sndio.sio_close)((struct ma_sio_hdl*)handle);
24718  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve device caps.", MA_ERROR);
24719  }
24720 
24721  /*
24722  Note: sndio reports a huge range of available channels. This is inconvenient for us because there's no real
24723  way, as far as I can tell, to get the _actual_ channel count of the device. I'm therefore restricting this
24724  to the requested channels, regardless of whether or not the default channel count is requested.
24725 
24726  For hardware devices, I'm suspecting only a single channel count will be reported and we can safely use the
24727  value returned by ma_find_best_channels_from_sio_cap__sndio().
24728  */
24729  if (deviceType == ma_device_type_capture) {
24730  if (pDevice->capture.usingDefaultFormat) {
24731  format = ma_find_best_format_from_sio_cap__sndio(&caps);
24732  }
24733  if (pDevice->capture.usingDefaultChannels) {
24734  if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) {
24735  channels = ma_find_best_channels_from_sio_cap__sndio(&caps, deviceType, format);
24736  }
24737  }
24738  } else {
24739  if (pDevice->playback.usingDefaultFormat) {
24740  format = ma_find_best_format_from_sio_cap__sndio(&caps);
24741  }
24742  if (pDevice->playback.usingDefaultChannels) {
24743  if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) {
24744  channels = ma_find_best_channels_from_sio_cap__sndio(&caps, deviceType, format);
24745  }
24746  }
24747  }
24748 
24749  if (pDevice->usingDefaultSampleRate) {
24750  sampleRate = ma_find_best_sample_rate_from_sio_cap__sndio(&caps, pConfig->deviceType, format, channels);
24751  }
24752 
24753 
24754  ((ma_sio_initpar_proc)pDevice->pContext->sndio.sio_initpar)(&par);
24755  par.msb = 0;
24756  par.le = ma_is_little_endian();
24757 
24758  switch (format) {
24759  case ma_format_u8:
24760  {
24761  par.bits = 8;
24762  par.bps = 1;
24763  par.sig = 0;
24764  } break;
24765 
24766  case ma_format_s24:
24767  {
24768  par.bits = 24;
24769  par.bps = 3;
24770  par.sig = 1;
24771  } break;
24772 
24773  case ma_format_s32:
24774  {
24775  par.bits = 32;
24776  par.bps = 4;
24777  par.sig = 1;
24778  } break;
24779 
24780  case ma_format_s16:
24781  case ma_format_f32:
24782  default:
24783  {
24784  par.bits = 16;
24785  par.bps = 2;
24786  par.sig = 1;
24787  } break;
24788  }
24789 
24790  if (deviceType == ma_device_type_capture) {
24791  par.rchan = channels;
24792  } else {
24793  par.pchan = channels;
24794  }
24795 
24796  par.rate = sampleRate;
24797 
24798  internalPeriodSizeInFrames = pConfig->periodSizeInFrames;
24799  if (internalPeriodSizeInFrames == 0) {
24800  internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, par.rate);
24801  }
24802 
24803  par.round = internalPeriodSizeInFrames;
24804  par.appbufsz = par.round * pConfig->periods;
24805 
24806  if (((ma_sio_setpar_proc)pContext->sndio.sio_setpar)((struct ma_sio_hdl*)handle, &par) == 0) {
24807  ((ma_sio_close_proc)pContext->sndio.sio_close)((struct ma_sio_hdl*)handle);
24808  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to set buffer size.", MA_FORMAT_NOT_SUPPORTED);
24809  }
24810  if (((ma_sio_getpar_proc)pContext->sndio.sio_getpar)((struct ma_sio_hdl*)handle, &par) == 0) {
24811  ((ma_sio_close_proc)pContext->sndio.sio_close)((struct ma_sio_hdl*)handle);
24812  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve buffer size.", MA_FORMAT_NOT_SUPPORTED);
24813  }
24814 
24815  internalFormat = ma_format_from_sio_enc__sndio(par.bits, par.bps, par.sig, par.le, par.msb);
24816  internalChannels = (deviceType == ma_device_type_capture) ? par.rchan : par.pchan;
24817  internalSampleRate = par.rate;
24818  internalPeriods = par.appbufsz / par.round;
24819  internalPeriodSizeInFrames = par.round;
24820 
24821  if (deviceType == ma_device_type_capture) {
24822  pDevice->sndio.handleCapture = handle;
24823  pDevice->capture.internalFormat = internalFormat;
24824  pDevice->capture.internalChannels = internalChannels;
24825  pDevice->capture.internalSampleRate = internalSampleRate;
24827  pDevice->capture.internalPeriodSizeInFrames = internalPeriodSizeInFrames;
24828  pDevice->capture.internalPeriods = internalPeriods;
24829  } else {
24830  pDevice->sndio.handlePlayback = handle;
24831  pDevice->playback.internalFormat = internalFormat;
24832  pDevice->playback.internalChannels = internalChannels;
24833  pDevice->playback.internalSampleRate = internalSampleRate;
24835  pDevice->playback.internalPeriodSizeInFrames = internalPeriodSizeInFrames;
24836  pDevice->playback.internalPeriods = internalPeriods;
24837  }
24838 
24839 #ifdef MA_DEBUG_OUTPUT
24840  printf("DEVICE INFO\n");
24841  printf(" Format: %s\n", ma_get_format_name(internalFormat));
24842  printf(" Channels: %d\n", internalChannels);
24843  printf(" Sample Rate: %d\n", internalSampleRate);
24844  printf(" Period Size: %d\n", internalPeriodSizeInFrames);
24845  printf(" Periods: %d\n", internalPeriods);
24846  printf(" appbufsz: %d\n", par.appbufsz);
24847  printf(" round: %d\n", par.round);
24848 #endif
24849 
24850  return MA_SUCCESS;
24851 }
24852 
24853 static ma_result ma_device_init__sndio(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
24854 {
24855  MA_ASSERT(pDevice != NULL);
24856 
24857  MA_ZERO_OBJECT(&pDevice->sndio);
24858 
24859  if (pConfig->deviceType == ma_device_type_loopback) {
24861  }
24862 
24863  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
24864  ma_result result = ma_device_init_handle__sndio(pContext, pConfig, ma_device_type_capture, pDevice);
24865  if (result != MA_SUCCESS) {
24866  return result;
24867  }
24868  }
24869 
24870  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
24871  ma_result result = ma_device_init_handle__sndio(pContext, pConfig, ma_device_type_playback, pDevice);
24872  if (result != MA_SUCCESS) {
24873  return result;
24874  }
24875  }
24876 
24877  return MA_SUCCESS;
24878 }
24879 
24880 static ma_result ma_device_stop__sndio(ma_device* pDevice)
24881 {
24882  MA_ASSERT(pDevice != NULL);
24883 
24884  /*
24885  From the documentation:
24886 
24887  The sio_stop() function puts the audio subsystem in the same state as before sio_start() is called. It stops recording, drains the play buffer and then
24888  stops playback. If samples to play are queued but playback hasn't started yet then playback is forced immediately; playback will actually stop once the
24889  buffer is drained. In no case are samples in the play buffer discarded.
24890 
24891  Therefore, sio_stop() performs all of the necessary draining for us.
24892  */
24893 
24894  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
24895  ((ma_sio_stop_proc)pDevice->pContext->sndio.sio_stop)((struct ma_sio_hdl*)pDevice->sndio.handleCapture);
24896  }
24897 
24898  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
24899  ((ma_sio_stop_proc)pDevice->pContext->sndio.sio_stop)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback);
24900  }
24901 
24902  return MA_SUCCESS;
24903 }
24904 
24905 static ma_result ma_device_write__sndio(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
24906 {
24907  int result;
24908 
24909  if (pFramesWritten != NULL) {
24910  *pFramesWritten = 0;
24911  }
24912 
24913  result = ((ma_sio_write_proc)pDevice->pContext->sndio.sio_write)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
24914  if (result == 0) {
24915  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to send data from the client to the device.", MA_IO_ERROR);
24916  }
24917 
24918  if (pFramesWritten != NULL) {
24919  *pFramesWritten = frameCount;
24920  }
24921 
24922  return MA_SUCCESS;
24923 }
24924 
24925 static ma_result ma_device_read__sndio(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
24926 {
24927  int result;
24928 
24929  if (pFramesRead != NULL) {
24930  *pFramesRead = 0;
24931  }
24932 
24933  result = ((ma_sio_read_proc)pDevice->pContext->sndio.sio_read)((struct ma_sio_hdl*)pDevice->sndio.handleCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
24934  if (result == 0) {
24935  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to read data from the device to be sent to the device.", MA_IO_ERROR);
24936  }
24937 
24938  if (pFramesRead != NULL) {
24939  *pFramesRead = frameCount;
24940  }
24941 
24942  return MA_SUCCESS;
24943 }
24944 
24945 static ma_result ma_device_main_loop__sndio(ma_device* pDevice)
24946 {
24947  ma_result result = MA_SUCCESS;
24948  ma_bool32 exitLoop = MA_FALSE;
24949 
24950  /* Devices need to be started here. */
24951  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
24952  ((ma_sio_start_proc)pDevice->pContext->sndio.sio_start)((struct ma_sio_hdl*)pDevice->sndio.handleCapture);
24953  }
24954  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
24955  ((ma_sio_start_proc)pDevice->pContext->sndio.sio_start)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback); /* <-- Doesn't actually playback until data is written. */
24956  }
24957 
24958  while (ma_device__get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
24959  switch (pDevice->type)
24960  {
24961  case ma_device_type_duplex:
24962  {
24963  /* The process is: device_read -> convert -> callback -> convert -> device_write */
24964  ma_uint32 totalCapturedDeviceFramesProcessed = 0;
24965  ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
24966 
24967  while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
24968  ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
24969  ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
24970  ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
24971  ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
24972  ma_uint32 capturedDeviceFramesRemaining;
24973  ma_uint32 capturedDeviceFramesProcessed;
24974  ma_uint32 capturedDeviceFramesToProcess;
24975  ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed;
24976  if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) {
24977  capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames;
24978  }
24979 
24980  result = ma_device_read__sndio(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess);
24981  if (result != MA_SUCCESS) {
24982  exitLoop = MA_TRUE;
24983  break;
24984  }
24985 
24986  capturedDeviceFramesRemaining = capturedDeviceFramesToProcess;
24987  capturedDeviceFramesProcessed = 0;
24988 
24989  for (;;) {
24990  ma_uint8 capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
24991  ma_uint8 playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
24992  ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
24993  ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
24994  ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames);
24995  ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining;
24996  ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
24997 
24998  /* Convert capture data from device format to client format. */
24999  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration);
25000  if (result != MA_SUCCESS) {
25001  break;
25002  }
25003 
25004  /*
25005  If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small
25006  which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
25007  */
25008  if (capturedClientFramesToProcessThisIteration == 0) {
25009  break;
25010  }
25011 
25012  ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/
25013 
25014  capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
25015  capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
25016 
25017  /* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */
25018  for (;;) {
25019  ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration;
25020  ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames;
25021  result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount);
25022  if (result != MA_SUCCESS) {
25023  break;
25024  }
25025 
25026  result = ma_device_write__sndio(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL); /* Safe cast. */
25027  if (result != MA_SUCCESS) {
25028  exitLoop = MA_TRUE;
25029  break;
25030  }
25031 
25032  capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount; /* Safe cast. */
25033  if (capturedClientFramesToProcessThisIteration == 0) {
25034  break;
25035  }
25036  }
25037 
25038  /* In case an error happened from ma_device_write__sndio()... */
25039  if (result != MA_SUCCESS) {
25040  exitLoop = MA_TRUE;
25041  break;
25042  }
25043  }
25044 
25045  totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed;
25046  }
25047  } break;
25048 
25050  {
25051  /* We read in chunks of the period size, but use a stack allocated buffer for the intermediary. */
25052  ma_uint8 intermediaryBuffer[8192];
25053  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
25054  ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
25055  ma_uint32 framesReadThisPeriod = 0;
25056  while (framesReadThisPeriod < periodSizeInFrames) {
25057  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
25058  ma_uint32 framesProcessed;
25059  ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
25060  if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
25061  framesToReadThisIteration = intermediaryBufferSizeInFrames;
25062  }
25063 
25064  result = ma_device_read__sndio(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
25065  if (result != MA_SUCCESS) {
25066  exitLoop = MA_TRUE;
25067  break;
25068  }
25069 
25070  ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
25071 
25072  framesReadThisPeriod += framesProcessed;
25073  }
25074  } break;
25075 
25077  {
25078  /* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
25079  ma_uint8 intermediaryBuffer[8192];
25080  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
25081  ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
25082  ma_uint32 framesWrittenThisPeriod = 0;
25083  while (framesWrittenThisPeriod < periodSizeInFrames) {
25084  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
25085  ma_uint32 framesProcessed;
25086  ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
25087  if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
25088  framesToWriteThisIteration = intermediaryBufferSizeInFrames;
25089  }
25090 
25091  ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
25092 
25093  result = ma_device_write__sndio(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
25094  if (result != MA_SUCCESS) {
25095  exitLoop = MA_TRUE;
25096  break;
25097  }
25098 
25099  framesWrittenThisPeriod += framesProcessed;
25100  }
25101  } break;
25102 
25103  /* To silence a warning. Will never hit this. */
25105  default: break;
25106  }
25107  }
25108 
25109 
25110  /* Here is where the device is stopped. */
25111  ma_device_stop__sndio(pDevice);
25112 
25113  return result;
25114 }
25115 
25116 static ma_result ma_context_uninit__sndio(ma_context* pContext)
25117 {
25118  MA_ASSERT(pContext != NULL);
25119  MA_ASSERT(pContext->backend == ma_backend_sndio);
25120 
25121  (void)pContext;
25122  return MA_SUCCESS;
25123 }
25124 
25125 static ma_result ma_context_init__sndio(const ma_context_config* pConfig, ma_context* pContext)
25126 {
25127 #ifndef MA_NO_RUNTIME_LINKING
25128  const char* libsndioNames[] = {
25129  "libsndio.so"
25130  };
25131  size_t i;
25132 
25133  for (i = 0; i < ma_countof(libsndioNames); ++i) {
25134  pContext->sndio.sndioSO = ma_dlopen(pContext, libsndioNames[i]);
25135  if (pContext->sndio.sndioSO != NULL) {
25136  break;
25137  }
25138  }
25139 
25140  if (pContext->sndio.sndioSO == NULL) {
25141  return MA_NO_BACKEND;
25142  }
25143 
25144  pContext->sndio.sio_open = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_open");
25145  pContext->sndio.sio_close = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_close");
25146  pContext->sndio.sio_setpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_setpar");
25147  pContext->sndio.sio_getpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getpar");
25148  pContext->sndio.sio_getcap = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getcap");
25149  pContext->sndio.sio_write = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_write");
25150  pContext->sndio.sio_read = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_read");
25151  pContext->sndio.sio_start = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_start");
25152  pContext->sndio.sio_stop = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_stop");
25153  pContext->sndio.sio_initpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_initpar");
25154 #else
25155  pContext->sndio.sio_open = sio_open;
25156  pContext->sndio.sio_close = sio_close;
25157  pContext->sndio.sio_setpar = sio_setpar;
25158  pContext->sndio.sio_getpar = sio_getpar;
25159  pContext->sndio.sio_getcap = sio_getcap;
25160  pContext->sndio.sio_write = sio_write;
25161  pContext->sndio.sio_read = sio_read;
25162  pContext->sndio.sio_start = sio_start;
25163  pContext->sndio.sio_stop = sio_stop;
25164  pContext->sndio.sio_initpar = sio_initpar;
25165 #endif
25166 
25167  pContext->onUninit = ma_context_uninit__sndio;
25168  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__sndio;
25169  pContext->onEnumDevices = ma_context_enumerate_devices__sndio;
25170  pContext->onGetDeviceInfo = ma_context_get_device_info__sndio;
25171  pContext->onDeviceInit = ma_device_init__sndio;
25172  pContext->onDeviceUninit = ma_device_uninit__sndio;
25173  pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */
25174  pContext->onDeviceStop = NULL; /* Not required for synchronous backends. */
25175  pContext->onDeviceMainLoop = ma_device_main_loop__sndio;
25176 
25177  (void)pConfig;
25178  return MA_SUCCESS;
25179 }
25180 #endif /* sndio */
25181 
25182 
25183 
25184 /******************************************************************************
25185 
25186 audio(4) Backend
25187 
25188 ******************************************************************************/
25189 #ifdef MA_HAS_AUDIO4
25190 #include <fcntl.h>
25191 #include <poll.h>
25192 #include <errno.h>
25193 #include <sys/stat.h>
25194 #include <sys/types.h>
25195 #include <sys/ioctl.h>
25196 #include <sys/audioio.h>
25197 
25198 #if defined(__OpenBSD__)
25199  #include <sys/param.h>
25200  #if defined(OpenBSD) && OpenBSD >= 201709
25201  #define MA_AUDIO4_USE_NEW_API
25202  #endif
25203 #endif
25204 
25205 static void ma_construct_device_id__audio4(char* id, size_t idSize, const char* base, int deviceIndex)
25206 {
25207  size_t baseLen;
25208 
25209  MA_ASSERT(id != NULL);
25210  MA_ASSERT(idSize > 0);
25211  MA_ASSERT(deviceIndex >= 0);
25212 
25213  baseLen = strlen(base);
25214  MA_ASSERT(idSize > baseLen);
25215 
25216  ma_strcpy_s(id, idSize, base);
25217  ma_itoa_s(deviceIndex, id+baseLen, idSize-baseLen, 10);
25218 }
25219 
25220 static ma_result ma_extract_device_index_from_id__audio4(const char* id, const char* base, int* pIndexOut)
25221 {
25222  size_t idLen;
25223  size_t baseLen;
25224  const char* deviceIndexStr;
25225 
25226  MA_ASSERT(id != NULL);
25227  MA_ASSERT(base != NULL);
25228  MA_ASSERT(pIndexOut != NULL);
25229 
25230  idLen = strlen(id);
25231  baseLen = strlen(base);
25232  if (idLen <= baseLen) {
25233  return MA_ERROR; /* Doesn't look like the id starts with the base. */
25234  }
25235 
25236  if (strncmp(id, base, baseLen) != 0) {
25237  return MA_ERROR; /* ID does not begin with base. */
25238  }
25239 
25240  deviceIndexStr = id + baseLen;
25241  if (deviceIndexStr[0] == '\0') {
25242  return MA_ERROR; /* No index specified in the ID. */
25243  }
25244 
25245  if (pIndexOut) {
25246  *pIndexOut = atoi(deviceIndexStr);
25247  }
25248 
25249  return MA_SUCCESS;
25250 }
25251 
25252 static ma_bool32 ma_context_is_device_id_equal__audio4(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
25253 {
25254  MA_ASSERT(pContext != NULL);
25255  MA_ASSERT(pID0 != NULL);
25256  MA_ASSERT(pID1 != NULL);
25257  (void)pContext;
25258 
25259  return ma_strcmp(pID0->audio4, pID1->audio4) == 0;
25260 }
25261 
25262 #if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */
25263 static ma_format ma_format_from_encoding__audio4(unsigned int encoding, unsigned int precision)
25264 {
25265  if (precision == 8 && (encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR_LE || encoding == AUDIO_ENCODING_ULINEAR_BE)) {
25266  return ma_format_u8;
25267  } else {
25268  if (ma_is_little_endian() && encoding == AUDIO_ENCODING_SLINEAR_LE) {
25269  if (precision == 16) {
25270  return ma_format_s16;
25271  } else if (precision == 24) {
25272  return ma_format_s24;
25273  } else if (precision == 32) {
25274  return ma_format_s32;
25275  }
25276  } else if (ma_is_big_endian() && encoding == AUDIO_ENCODING_SLINEAR_BE) {
25277  if (precision == 16) {
25278  return ma_format_s16;
25279  } else if (precision == 24) {
25280  return ma_format_s24;
25281  } else if (precision == 32) {
25282  return ma_format_s32;
25283  }
25284  }
25285  }
25286 
25287  return ma_format_unknown; /* Encoding not supported. */
25288 }
25289 
25290 static void ma_encoding_from_format__audio4(ma_format format, unsigned int* pEncoding, unsigned int* pPrecision)
25291 {
25292  MA_ASSERT(format != ma_format_unknown);
25293  MA_ASSERT(pEncoding != NULL);
25294  MA_ASSERT(pPrecision != NULL);
25295 
25296  switch (format)
25297  {
25298  case ma_format_u8:
25299  {
25300  *pEncoding = AUDIO_ENCODING_ULINEAR;
25301  *pPrecision = 8;
25302  } break;
25303 
25304  case ma_format_s24:
25305  {
25306  *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
25307  *pPrecision = 24;
25308  } break;
25309 
25310  case ma_format_s32:
25311  {
25312  *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
25313  *pPrecision = 32;
25314  } break;
25315 
25316  case ma_format_s16:
25317  case ma_format_f32:
25318  default:
25319  {
25320  *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
25321  *pPrecision = 16;
25322  } break;
25323  }
25324 }
25325 
25326 static ma_format ma_format_from_prinfo__audio4(struct audio_prinfo* prinfo)
25327 {
25328  return ma_format_from_encoding__audio4(prinfo->encoding, prinfo->precision);
25329 }
25330 #else
25331 static ma_format ma_format_from_swpar__audio4(struct audio_swpar* par)
25332 {
25333  if (par->bits == 8 && par->bps == 1 && par->sig == 0) {
25334  return ma_format_u8;
25335  }
25336  if (par->bits == 16 && par->bps == 2 && par->sig == 1 && par->le == ma_is_little_endian()) {
25337  return ma_format_s16;
25338  }
25339  if (par->bits == 24 && par->bps == 3 && par->sig == 1 && par->le == ma_is_little_endian()) {
25340  return ma_format_s24;
25341  }
25342  if (par->bits == 32 && par->bps == 4 && par->sig == 1 && par->le == ma_is_little_endian()) {
25343  return ma_format_f32;
25344  }
25345 
25346  /* Format not supported. */
25347  return ma_format_unknown;
25348 }
25349 #endif
25350 
25351 static ma_result ma_context_get_device_info_from_fd__audio4(ma_context* pContext, ma_device_type deviceType, int fd, ma_device_info* pInfoOut)
25352 {
25353  audio_device_t fdDevice;
25354 #if !defined(MA_AUDIO4_USE_NEW_API)
25355  int counter = 0;
25356  audio_info_t fdInfo;
25357 #else
25358  struct audio_swpar fdPar;
25359  ma_format format;
25360 #endif
25361 
25362  MA_ASSERT(pContext != NULL);
25363  MA_ASSERT(fd >= 0);
25364  MA_ASSERT(pInfoOut != NULL);
25365 
25366  (void)pContext;
25367  (void)deviceType;
25368 
25369  if (ioctl(fd, AUDIO_GETDEV, &fdDevice) < 0) {
25370  return MA_ERROR; /* Failed to retrieve device info. */
25371  }
25372 
25373  /* Name. */
25374  ma_strcpy_s(pInfoOut->name, sizeof(pInfoOut->name), fdDevice.name);
25375 
25376 #if !defined(MA_AUDIO4_USE_NEW_API)
25377  /* Supported formats. We get this by looking at the encodings. */
25378  for (;;) {
25379  audio_encoding_t encoding;
25380  ma_format format;
25381 
25382  MA_ZERO_OBJECT(&encoding);
25383  encoding.index = counter;
25384  if (ioctl(fd, AUDIO_GETENC, &encoding) < 0) {
25385  break;
25386  }
25387 
25388  format = ma_format_from_encoding__audio4(encoding.encoding, encoding.precision);
25389  if (format != ma_format_unknown) {
25390  pInfoOut->formats[pInfoOut->formatCount++] = format;
25391  }
25392 
25393  counter += 1;
25394  }
25395 
25396  if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) {
25397  return MA_ERROR;
25398  }
25399 
25400  if (deviceType == ma_device_type_playback) {
25401  pInfoOut->minChannels = fdInfo.play.channels;
25402  pInfoOut->maxChannels = fdInfo.play.channels;
25403  pInfoOut->minSampleRate = fdInfo.play.sample_rate;
25404  pInfoOut->maxSampleRate = fdInfo.play.sample_rate;
25405  } else {
25406  pInfoOut->minChannels = fdInfo.record.channels;
25407  pInfoOut->maxChannels = fdInfo.record.channels;
25408  pInfoOut->minSampleRate = fdInfo.record.sample_rate;
25409  pInfoOut->maxSampleRate = fdInfo.record.sample_rate;
25410  }
25411 #else
25412  if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) {
25413  return MA_ERROR;
25414  }
25415 
25416  format = ma_format_from_swpar__audio4(&fdPar);
25417  if (format == ma_format_unknown) {
25418  return MA_FORMAT_NOT_SUPPORTED;
25419  }
25420  pInfoOut->formats[pInfoOut->formatCount++] = format;
25421 
25422  if (deviceType == ma_device_type_playback) {
25423  pInfoOut->minChannels = fdPar.pchan;
25424  pInfoOut->maxChannels = fdPar.pchan;
25425  } else {
25426  pInfoOut->minChannels = fdPar.rchan;
25427  pInfoOut->maxChannels = fdPar.rchan;
25428  }
25429 
25430  pInfoOut->minSampleRate = fdPar.rate;
25431  pInfoOut->maxSampleRate = fdPar.rate;
25432 #endif
25433 
25434  return MA_SUCCESS;
25435 }
25436 
25437 static ma_result ma_context_enumerate_devices__audio4(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
25438 {
25439  const int maxDevices = 64;
25440  char devpath[256];
25441  int iDevice;
25442 
25443  MA_ASSERT(pContext != NULL);
25444  MA_ASSERT(callback != NULL);
25445 
25446  /*
25447  Every device will be named "/dev/audioN", with a "/dev/audioctlN" equivalent. We use the "/dev/audioctlN"
25448  version here since we can open it even when another process has control of the "/dev/audioN" device.
25449  */
25450  for (iDevice = 0; iDevice < maxDevices; ++iDevice) {
25451  struct stat st;
25452  int fd;
25453  ma_bool32 isTerminating = MA_FALSE;
25454 
25455  ma_strcpy_s(devpath, sizeof(devpath), "/dev/audioctl");
25456  ma_itoa_s(iDevice, devpath+strlen(devpath), sizeof(devpath)-strlen(devpath), 10);
25457 
25458  if (stat(devpath, &st) < 0) {
25459  break;
25460  }
25461 
25462  /* The device exists, but we need to check if it's usable as playback and/or capture. */
25463 
25464  /* Playback. */
25465  if (!isTerminating) {
25466  fd = open(devpath, O_RDONLY, 0);
25467  if (fd >= 0) {
25468  /* Supports playback. */
25469  ma_device_info deviceInfo;
25470  MA_ZERO_OBJECT(&deviceInfo);
25471  ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice);
25472  if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_playback, fd, &deviceInfo) == MA_SUCCESS) {
25473  isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
25474  }
25475 
25476  close(fd);
25477  }
25478  }
25479 
25480  /* Capture. */
25481  if (!isTerminating) {
25482  fd = open(devpath, O_WRONLY, 0);
25483  if (fd >= 0) {
25484  /* Supports capture. */
25485  ma_device_info deviceInfo;
25486  MA_ZERO_OBJECT(&deviceInfo);
25487  ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice);
25488  if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_capture, fd, &deviceInfo) == MA_SUCCESS) {
25489  isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
25490  }
25491 
25492  close(fd);
25493  }
25494  }
25495 
25496  if (isTerminating) {
25497  break;
25498  }
25499  }
25500 
25501  return MA_SUCCESS;
25502 }
25503 
25504 static ma_result ma_context_get_device_info__audio4(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
25505 {
25506  int fd = -1;
25507  int deviceIndex = -1;
25508  char ctlid[256];
25509  ma_result result;
25510 
25511  MA_ASSERT(pContext != NULL);
25512  (void)shareMode;
25513 
25514  /*
25515  We need to open the "/dev/audioctlN" device to get the info. To do this we need to extract the number
25516  from the device ID which will be in "/dev/audioN" format.
25517  */
25518  if (pDeviceID == NULL) {
25519  /* Default device. */
25520  ma_strcpy_s(ctlid, sizeof(ctlid), "/dev/audioctl");
25521  } else {
25522  /* Specific device. We need to convert from "/dev/audioN" to "/dev/audioctlN". */
25523  result = ma_extract_device_index_from_id__audio4(pDeviceID->audio4, "/dev/audio", &deviceIndex);
25524  if (result != MA_SUCCESS) {
25525  return result;
25526  }
25527 
25528  ma_construct_device_id__audio4(ctlid, sizeof(ctlid), "/dev/audioctl", deviceIndex);
25529  }
25530 
25531  fd = open(ctlid, (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY, 0);
25532  if (fd == -1) {
25533  return MA_NO_DEVICE;
25534  }
25535 
25536  if (deviceIndex == -1) {
25537  ma_strcpy_s(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio");
25538  } else {
25539  ma_construct_device_id__audio4(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio", deviceIndex);
25540  }
25541 
25542  result = ma_context_get_device_info_from_fd__audio4(pContext, deviceType, fd, pDeviceInfo);
25543 
25544  close(fd);
25545  return result;
25546 }
25547 
25548 static void ma_device_uninit__audio4(ma_device* pDevice)
25549 {
25550  MA_ASSERT(pDevice != NULL);
25551 
25552  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
25553  close(pDevice->audio4.fdCapture);
25554  }
25555 
25556  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
25557  close(pDevice->audio4.fdPlayback);
25558  }
25559 }
25560 
25561 static ma_result ma_device_init_fd__audio4(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice)
25562 {
25563  const char* pDefaultDeviceNames[] = {
25564  "/dev/audio",
25565  "/dev/audio0"
25566  };
25567  int fd;
25568  int fdFlags = 0;
25569 #if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */
25570  audio_info_t fdInfo;
25571 #else
25572  struct audio_swpar fdPar;
25573 #endif
25574  ma_format internalFormat;
25575  ma_uint32 internalChannels;
25576  ma_uint32 internalSampleRate;
25577  ma_uint32 internalPeriodSizeInFrames;
25578  ma_uint32 internalPeriods;
25579 
25580  MA_ASSERT(pContext != NULL);
25581  MA_ASSERT(pConfig != NULL);
25582  MA_ASSERT(deviceType != ma_device_type_duplex);
25583  MA_ASSERT(pDevice != NULL);
25584 
25585  (void)pContext;
25586 
25587  /* The first thing to do is open the file. */
25588  if (deviceType == ma_device_type_capture) {
25589  fdFlags = O_RDONLY;
25590  } else {
25591  fdFlags = O_WRONLY;
25592  }
25593  /*fdFlags |= O_NONBLOCK;*/
25594 
25595  if ((deviceType == ma_device_type_capture && pConfig->capture.pDeviceID == NULL) || (deviceType == ma_device_type_playback && pConfig->playback.pDeviceID == NULL)) {
25596  /* Default device. */
25597  size_t iDevice;
25598  for (iDevice = 0; iDevice < ma_countof(pDefaultDeviceNames); ++iDevice) {
25599  fd = open(pDefaultDeviceNames[iDevice], fdFlags, 0);
25600  if (fd != -1) {
25601  break;
25602  }
25603  }
25604  } else {
25605  /* Specific device. */
25606  fd = open((deviceType == ma_device_type_capture) ? pConfig->capture.pDeviceID->audio4 : pConfig->playback.pDeviceID->audio4, fdFlags, 0);
25607  }
25608 
25609  if (fd == -1) {
25610  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to open device.", ma_result_from_errno(errno));
25611  }
25612 
25613 #if !defined(MA_AUDIO4_USE_NEW_API) /* Old API */
25614  AUDIO_INITINFO(&fdInfo);
25615 
25616  /* We get the driver to do as much of the data conversion as possible. */
25617  if (deviceType == ma_device_type_capture) {
25618  fdInfo.mode = AUMODE_RECORD;
25619  ma_encoding_from_format__audio4(pConfig->capture.format, &fdInfo.record.encoding, &fdInfo.record.precision);
25620  fdInfo.record.channels = pConfig->capture.channels;
25621  fdInfo.record.sample_rate = pConfig->sampleRate;
25622  } else {
25623  fdInfo.mode = AUMODE_PLAY;
25624  ma_encoding_from_format__audio4(pConfig->playback.format, &fdInfo.play.encoding, &fdInfo.play.precision);
25625  fdInfo.play.channels = pConfig->playback.channels;
25626  fdInfo.play.sample_rate = pConfig->sampleRate;
25627  }
25628 
25629  if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) {
25630  close(fd);
25631  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device format. AUDIO_SETINFO failed.", MA_FORMAT_NOT_SUPPORTED);
25632  }
25633 
25634  if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) {
25635  close(fd);
25636  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed.", MA_FORMAT_NOT_SUPPORTED);
25637  }
25638 
25639  if (deviceType == ma_device_type_capture) {
25640  internalFormat = ma_format_from_prinfo__audio4(&fdInfo.record);
25641  internalChannels = fdInfo.record.channels;
25642  internalSampleRate = fdInfo.record.sample_rate;
25643  } else {
25644  internalFormat = ma_format_from_prinfo__audio4(&fdInfo.play);
25645  internalChannels = fdInfo.play.channels;
25646  internalSampleRate = fdInfo.play.sample_rate;
25647  }
25648 
25649  if (internalFormat == ma_format_unknown) {
25650  close(fd);
25651  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED);
25652  }
25653 
25654  /* Buffer. */
25655  {
25656  ma_uint32 internalPeriodSizeInBytes;
25657 
25658  internalPeriodSizeInFrames = pConfig->periodSizeInFrames;
25659  if (internalPeriodSizeInFrames == 0) {
25660  internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, internalSampleRate);
25661  }
25662 
25663  internalPeriodSizeInBytes = internalPeriodSizeInFrames * ma_get_bytes_per_frame(internalFormat, internalChannels);
25664  if (internalPeriodSizeInBytes < 16) {
25665  internalPeriodSizeInBytes = 16;
25666  }
25667 
25668  internalPeriods = pConfig->periods;
25669  if (internalPeriods < 2) {
25670  internalPeriods = 2;
25671  }
25672 
25673  /* What miniaudio calls a period, audio4 calls a block. */
25674  AUDIO_INITINFO(&fdInfo);
25675  fdInfo.hiwat = internalPeriods;
25676  fdInfo.lowat = internalPeriods-1;
25677  fdInfo.blocksize = internalPeriodSizeInBytes;
25678  if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) {
25679  close(fd);
25680  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set internal buffer size. AUDIO_SETINFO failed.", MA_FORMAT_NOT_SUPPORTED);
25681  }
25682 
25683  internalPeriods = fdInfo.hiwat;
25684  internalPeriodSizeInFrames = fdInfo.blocksize / ma_get_bytes_per_frame(internalFormat, internalChannels);
25685  }
25686 #else
25687  /* We need to retrieve the format of the device so we can know the channel count and sample rate. Then we can calculate the buffer size. */
25688  if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) {
25689  close(fd);
25690  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve initial device parameters.", MA_FORMAT_NOT_SUPPORTED);
25691  }
25692 
25693  internalFormat = ma_format_from_swpar__audio4(&fdPar);
25694  internalChannels = (deviceType == ma_device_type_capture) ? fdPar.rchan : fdPar.pchan;
25695  internalSampleRate = fdPar.rate;
25696 
25697  if (internalFormat == ma_format_unknown) {
25698  close(fd);
25699  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED);
25700  }
25701 
25702  /* Buffer. */
25703  {
25704  ma_uint32 internalPeriodSizeInBytes;
25705 
25706  internalPeriodSizeInFrames = pConfig->periodSizeInFrames;
25707  if (internalPeriodSizeInFrames == 0) {
25708  internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, internalSampleRate);
25709  }
25710 
25711  /* What miniaudio calls a period, audio4 calls a block. */
25712  internalPeriodSizeInBytes = internalPeriodSizeInFrames * ma_get_bytes_per_frame(internalFormat, internalChannels);
25713  if (internalPeriodSizeInBytes < 16) {
25714  internalPeriodSizeInBytes = 16;
25715  }
25716 
25717  fdPar.nblks = pConfig->periods;
25718  fdPar.round = internalPeriodSizeInBytes;
25719 
25720  if (ioctl(fd, AUDIO_SETPAR, &fdPar) < 0) {
25721  close(fd);
25722  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device parameters.", MA_FORMAT_NOT_SUPPORTED);
25723  }
25724 
25725  if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) {
25726  close(fd);
25727  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve actual device parameters.", MA_FORMAT_NOT_SUPPORTED);
25728  }
25729  }
25730 
25731  internalFormat = ma_format_from_swpar__audio4(&fdPar);
25732  internalChannels = (deviceType == ma_device_type_capture) ? fdPar.rchan : fdPar.pchan;
25733  internalSampleRate = fdPar.rate;
25734  internalPeriods = fdPar.nblks;
25735  internalPeriodSizeInFrames = fdPar.round / ma_get_bytes_per_frame(internalFormat, internalChannels);
25736 #endif
25737 
25738  if (internalFormat == ma_format_unknown) {
25739  close(fd);
25740  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED);
25741  }
25742 
25743  if (deviceType == ma_device_type_capture) {
25744  pDevice->audio4.fdCapture = fd;
25745  pDevice->capture.internalFormat = internalFormat;
25746  pDevice->capture.internalChannels = internalChannels;
25747  pDevice->capture.internalSampleRate = internalSampleRate;
25749  pDevice->capture.internalPeriodSizeInFrames = internalPeriodSizeInFrames;
25750  pDevice->capture.internalPeriods = internalPeriods;
25751  } else {
25752  pDevice->audio4.fdPlayback = fd;
25753  pDevice->playback.internalFormat = internalFormat;
25754  pDevice->playback.internalChannels = internalChannels;
25755  pDevice->playback.internalSampleRate = internalSampleRate;
25757  pDevice->playback.internalPeriodSizeInFrames = internalPeriodSizeInFrames;
25758  pDevice->playback.internalPeriods = internalPeriods;
25759  }
25760 
25761  return MA_SUCCESS;
25762 }
25763 
25764 static ma_result ma_device_init__audio4(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
25765 {
25766  MA_ASSERT(pDevice != NULL);
25767 
25768  MA_ZERO_OBJECT(&pDevice->audio4);
25769 
25770  if (pConfig->deviceType == ma_device_type_loopback) {
25772  }
25773 
25774  pDevice->audio4.fdCapture = -1;
25775  pDevice->audio4.fdPlayback = -1;
25776 
25777  /*
25778  The version of the operating system dictates whether or not the device is exclusive or shared. NetBSD
25779  introduced in-kernel mixing which means it's shared. All other BSD flavours are exclusive as far as
25780  I'm aware.
25781  */
25782 #if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 800000000
25783  /* NetBSD 8.0+ */
25787  }
25788 #else
25789  /* All other flavors. */
25790 #endif
25791 
25792  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
25793  ma_result result = ma_device_init_fd__audio4(pContext, pConfig, ma_device_type_capture, pDevice);
25794  if (result != MA_SUCCESS) {
25795  return result;
25796  }
25797  }
25798 
25799  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
25800  ma_result result = ma_device_init_fd__audio4(pContext, pConfig, ma_device_type_playback, pDevice);
25801  if (result != MA_SUCCESS) {
25802  if (pConfig->deviceType == ma_device_type_duplex) {
25803  close(pDevice->audio4.fdCapture);
25804  }
25805  return result;
25806  }
25807  }
25808 
25809  return MA_SUCCESS;
25810 }
25811 
25812 #if 0
25813 static ma_result ma_device_start__audio4(ma_device* pDevice)
25814 {
25815  MA_ASSERT(pDevice != NULL);
25816 
25817  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
25818  if (pDevice->audio4.fdCapture == -1) {
25819  return MA_INVALID_ARGS;
25820  }
25821  }
25822 
25823  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
25824  if (pDevice->audio4.fdPlayback == -1) {
25825  return MA_INVALID_ARGS;
25826  }
25827  }
25828 
25829  return MA_SUCCESS;
25830 }
25831 #endif
25832 
25833 static ma_result ma_device_stop_fd__audio4(ma_device* pDevice, int fd)
25834 {
25835  if (fd == -1) {
25836  return MA_INVALID_ARGS;
25837  }
25838 
25839 #if !defined(MA_AUDIO4_USE_NEW_API)
25840  if (ioctl(fd, AUDIO_FLUSH, 0) < 0) {
25841  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_FLUSH failed.", ma_result_from_errno(errno));
25842  }
25843 #else
25844  if (ioctl(fd, AUDIO_STOP, 0) < 0) {
25845  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_STOP failed.", ma_result_from_errno(errno));
25846  }
25847 #endif
25848 
25849  return MA_SUCCESS;
25850 }
25851 
25852 static ma_result ma_device_stop__audio4(ma_device* pDevice)
25853 {
25854  MA_ASSERT(pDevice != NULL);
25855 
25856  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
25857  ma_result result;
25858 
25859  result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdCapture);
25860  if (result != MA_SUCCESS) {
25861  return result;
25862  }
25863  }
25864 
25865  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
25866  ma_result result;
25867 
25868  /* Drain the device first. If this fails we'll just need to flush without draining. Unfortunately draining isn't available on newer version of OpenBSD. */
25869  #if !defined(MA_AUDIO4_USE_NEW_API)
25870  ioctl(pDevice->audio4.fdPlayback, AUDIO_DRAIN, 0);
25871  #endif
25872 
25873  /* Here is where the device is stopped immediately. */
25874  result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdPlayback);
25875  if (result != MA_SUCCESS) {
25876  return result;
25877  }
25878  }
25879 
25880  return MA_SUCCESS;
25881 }
25882 
25883 static ma_result ma_device_write__audio4(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
25884 {
25885  int result;
25886 
25887  if (pFramesWritten != NULL) {
25888  *pFramesWritten = 0;
25889  }
25890 
25891  result = write(pDevice->audio4.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
25892  if (result < 0) {
25893  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to write data to the device.", ma_result_from_errno(errno));
25894  }
25895 
25896  if (pFramesWritten != NULL) {
25897  *pFramesWritten = (ma_uint32)result / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
25898  }
25899 
25900  return MA_SUCCESS;
25901 }
25902 
25903 static ma_result ma_device_read__audio4(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
25904 {
25905  int result;
25906 
25907  if (pFramesRead != NULL) {
25908  *pFramesRead = 0;
25909  }
25910 
25911  result = read(pDevice->audio4.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
25912  if (result < 0) {
25913  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to read data from the device.", ma_result_from_errno(errno));
25914  }
25915 
25916  if (pFramesRead != NULL) {
25917  *pFramesRead = (ma_uint32)result / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
25918  }
25919 
25920  return MA_SUCCESS;
25921 }
25922 
25923 static ma_result ma_device_main_loop__audio4(ma_device* pDevice)
25924 {
25925  ma_result result = MA_SUCCESS;
25926  ma_bool32 exitLoop = MA_FALSE;
25927 
25928  /* No need to explicitly start the device like the other backends. */
25929 
25930  while (ma_device__get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
25931  switch (pDevice->type)
25932  {
25933  case ma_device_type_duplex:
25934  {
25935  /* The process is: device_read -> convert -> callback -> convert -> device_write */
25936  ma_uint32 totalCapturedDeviceFramesProcessed = 0;
25937  ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
25938 
25939  while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
25940  ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
25941  ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
25942  ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
25943  ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
25944  ma_uint32 capturedDeviceFramesRemaining;
25945  ma_uint32 capturedDeviceFramesProcessed;
25946  ma_uint32 capturedDeviceFramesToProcess;
25947  ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed;
25948  if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) {
25949  capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames;
25950  }
25951 
25952  result = ma_device_read__audio4(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess);
25953  if (result != MA_SUCCESS) {
25954  exitLoop = MA_TRUE;
25955  break;
25956  }
25957 
25958  capturedDeviceFramesRemaining = capturedDeviceFramesToProcess;
25959  capturedDeviceFramesProcessed = 0;
25960 
25961  for (;;) {
25962  ma_uint8 capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
25963  ma_uint8 playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
25964  ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
25965  ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
25966  ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames);
25967  ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining;
25968  ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
25969 
25970  /* Convert capture data from device format to client format. */
25971  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration);
25972  if (result != MA_SUCCESS) {
25973  break;
25974  }
25975 
25976  /*
25977  If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small
25978  which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
25979  */
25980  if (capturedClientFramesToProcessThisIteration == 0) {
25981  break;
25982  }
25983 
25984  ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/
25985 
25986  capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
25987  capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
25988 
25989  /* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */
25990  for (;;) {
25991  ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration;
25992  ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames;
25993  result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount);
25994  if (result != MA_SUCCESS) {
25995  break;
25996  }
25997 
25998  result = ma_device_write__audio4(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL); /* Safe cast. */
25999  if (result != MA_SUCCESS) {
26000  exitLoop = MA_TRUE;
26001  break;
26002  }
26003 
26004  capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount; /* Safe cast. */
26005  if (capturedClientFramesToProcessThisIteration == 0) {
26006  break;
26007  }
26008  }
26009 
26010  /* In case an error happened from ma_device_write__audio4()... */
26011  if (result != MA_SUCCESS) {
26012  exitLoop = MA_TRUE;
26013  break;
26014  }
26015  }
26016 
26017  totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed;
26018  }
26019  } break;
26020 
26022  {
26023  /* We read in chunks of the period size, but use a stack allocated buffer for the intermediary. */
26024  ma_uint8 intermediaryBuffer[8192];
26025  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
26026  ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
26027  ma_uint32 framesReadThisPeriod = 0;
26028  while (framesReadThisPeriod < periodSizeInFrames) {
26029  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
26030  ma_uint32 framesProcessed;
26031  ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
26032  if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
26033  framesToReadThisIteration = intermediaryBufferSizeInFrames;
26034  }
26035 
26036  result = ma_device_read__audio4(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
26037  if (result != MA_SUCCESS) {
26038  exitLoop = MA_TRUE;
26039  break;
26040  }
26041 
26042  ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
26043 
26044  framesReadThisPeriod += framesProcessed;
26045  }
26046  } break;
26047 
26049  {
26050  /* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
26051  ma_uint8 intermediaryBuffer[8192];
26052  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
26053  ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
26054  ma_uint32 framesWrittenThisPeriod = 0;
26055  while (framesWrittenThisPeriod < periodSizeInFrames) {
26056  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
26057  ma_uint32 framesProcessed;
26058  ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
26059  if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
26060  framesToWriteThisIteration = intermediaryBufferSizeInFrames;
26061  }
26062 
26063  ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
26064 
26065  result = ma_device_write__audio4(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
26066  if (result != MA_SUCCESS) {
26067  exitLoop = MA_TRUE;
26068  break;
26069  }
26070 
26071  framesWrittenThisPeriod += framesProcessed;
26072  }
26073  } break;
26074 
26075  /* To silence a warning. Will never hit this. */
26077  default: break;
26078  }
26079  }
26080 
26081 
26082  /* Here is where the device is stopped. */
26083  ma_device_stop__audio4(pDevice);
26084 
26085  return result;
26086 }
26087 
26088 static ma_result ma_context_uninit__audio4(ma_context* pContext)
26089 {
26090  MA_ASSERT(pContext != NULL);
26091  MA_ASSERT(pContext->backend == ma_backend_audio4);
26092 
26093  (void)pContext;
26094  return MA_SUCCESS;
26095 }
26096 
26097 static ma_result ma_context_init__audio4(const ma_context_config* pConfig, ma_context* pContext)
26098 {
26099  MA_ASSERT(pContext != NULL);
26100 
26101  (void)pConfig;
26102 
26103  pContext->onUninit = ma_context_uninit__audio4;
26104  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__audio4;
26105  pContext->onEnumDevices = ma_context_enumerate_devices__audio4;
26106  pContext->onGetDeviceInfo = ma_context_get_device_info__audio4;
26107  pContext->onDeviceInit = ma_device_init__audio4;
26108  pContext->onDeviceUninit = ma_device_uninit__audio4;
26109  pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */
26110  pContext->onDeviceStop = NULL; /* Not required for synchronous backends. */
26111  pContext->onDeviceMainLoop = ma_device_main_loop__audio4;
26112 
26113  return MA_SUCCESS;
26114 }
26115 #endif /* audio4 */
26116 
26117 
26118 /******************************************************************************
26119 
26120 OSS Backend
26121 
26122 ******************************************************************************/
26123 #ifdef MA_HAS_OSS
26124 #include <sys/ioctl.h>
26125 #include <unistd.h>
26126 #include <fcntl.h>
26127 #include <sys/soundcard.h>
26128 
26129 #ifndef SNDCTL_DSP_HALT
26130 #define SNDCTL_DSP_HALT SNDCTL_DSP_RESET
26131 #endif
26132 
26133 static int ma_open_temp_device__oss()
26134 {
26135  /* The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. */
26136  int fd = open("/dev/mixer", O_RDONLY, 0);
26137  if (fd >= 0) {
26138  return fd;
26139  }
26140 
26141  return -1;
26142 }
26143 
26144 static ma_result ma_context_open_device__oss(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, int* pfd)
26145 {
26146  const char* deviceName;
26147  int flags;
26148 
26149  MA_ASSERT(pContext != NULL);
26150  MA_ASSERT(pfd != NULL);
26151  (void)pContext;
26152 
26153  *pfd = -1;
26154 
26155  /* This function should only be called for playback or capture, not duplex. */
26156  if (deviceType == ma_device_type_duplex) {
26157  return MA_INVALID_ARGS;
26158  }
26159 
26160  deviceName = "/dev/dsp";
26161  if (pDeviceID != NULL) {
26162  deviceName = pDeviceID->oss;
26163  }
26164 
26165  flags = (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY;
26166  if (shareMode == ma_share_mode_exclusive) {
26167  flags |= O_EXCL;
26168  }
26169 
26170  *pfd = open(deviceName, flags, 0);
26171  if (*pfd == -1) {
26172  return ma_result_from_errno(errno);
26173  }
26174 
26175  return MA_SUCCESS;
26176 }
26177 
26178 static ma_bool32 ma_context_is_device_id_equal__oss(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
26179 {
26180  MA_ASSERT(pContext != NULL);
26181  MA_ASSERT(pID0 != NULL);
26182  MA_ASSERT(pID1 != NULL);
26183  (void)pContext;
26184 
26185  return ma_strcmp(pID0->oss, pID1->oss) == 0;
26186 }
26187 
26188 static ma_result ma_context_enumerate_devices__oss(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
26189 {
26190  int fd;
26191  oss_sysinfo si;
26192  int result;
26193 
26194  MA_ASSERT(pContext != NULL);
26195  MA_ASSERT(callback != NULL);
26196 
26197  fd = ma_open_temp_device__oss();
26198  if (fd == -1) {
26199  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MA_NO_BACKEND);
26200  }
26201 
26202  result = ioctl(fd, SNDCTL_SYSINFO, &si);
26203  if (result != -1) {
26204  int iAudioDevice;
26205  for (iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) {
26206  oss_audioinfo ai;
26207  ai.dev = iAudioDevice;
26208  result = ioctl(fd, SNDCTL_AUDIOINFO, &ai);
26209  if (result != -1) {
26210  if (ai.devnode[0] != '\0') { /* <-- Can be blank, according to documentation. */
26211  ma_device_info deviceInfo;
26212  ma_bool32 isTerminating = MA_FALSE;
26213 
26214  MA_ZERO_OBJECT(&deviceInfo);
26215 
26216  /* ID */
26217  ma_strncpy_s(deviceInfo.id.oss, sizeof(deviceInfo.id.oss), ai.devnode, (size_t)-1);
26218 
26219  /*
26220  The human readable device name should be in the "ai.handle" variable, but it can
26221  sometimes be empty in which case we just fall back to "ai.name" which is less user
26222  friendly, but usually has a value.
26223  */
26224  if (ai.handle[0] != '\0') {
26225  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ai.handle, (size_t)-1);
26226  } else {
26227  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ai.name, (size_t)-1);
26228  }
26229 
26230  /* The device can be both playback and capture. */
26231  if (!isTerminating && (ai.caps & PCM_CAP_OUTPUT) != 0) {
26232  isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
26233  }
26234  if (!isTerminating && (ai.caps & PCM_CAP_INPUT) != 0) {
26235  isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
26236  }
26237 
26238  if (isTerminating) {
26239  break;
26240  }
26241  }
26242  }
26243  }
26244  } else {
26245  close(fd);
26246  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.", MA_NO_BACKEND);
26247  }
26248 
26249  close(fd);
26250  return MA_SUCCESS;
26251 }
26252 
26253 static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
26254 {
26255  ma_bool32 foundDevice;
26256  int fdTemp;
26257  oss_sysinfo si;
26258  int result;
26259 
26260  MA_ASSERT(pContext != NULL);
26261  (void)shareMode;
26262 
26263  /* Handle the default device a little differently. */
26264  if (pDeviceID == NULL) {
26265  if (deviceType == ma_device_type_playback) {
26266  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
26267  } else {
26268  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
26269  }
26270 
26271  return MA_SUCCESS;
26272  }
26273 
26274 
26275  /* If we get here it means we are _not_ using the default device. */
26276  foundDevice = MA_FALSE;
26277 
26278  fdTemp = ma_open_temp_device__oss();
26279  if (fdTemp == -1) {
26280  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MA_NO_BACKEND);
26281  }
26282 
26283  result = ioctl(fdTemp, SNDCTL_SYSINFO, &si);
26284  if (result != -1) {
26285  int iAudioDevice;
26286  for (iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) {
26287  oss_audioinfo ai;
26288  ai.dev = iAudioDevice;
26289  result = ioctl(fdTemp, SNDCTL_AUDIOINFO, &ai);
26290  if (result != -1) {
26291  if (ma_strcmp(ai.devnode, pDeviceID->oss) == 0) {
26292  /* It has the same name, so now just confirm the type. */
26293  if ((deviceType == ma_device_type_playback && ((ai.caps & PCM_CAP_OUTPUT) != 0)) ||
26294  (deviceType == ma_device_type_capture && ((ai.caps & PCM_CAP_INPUT) != 0))) {
26295  unsigned int formatMask;
26296 
26297  /* ID */
26298  ma_strncpy_s(pDeviceInfo->id.oss, sizeof(pDeviceInfo->id.oss), ai.devnode, (size_t)-1);
26299 
26300  /*
26301  The human readable device name should be in the "ai.handle" variable, but it can
26302  sometimes be empty in which case we just fall back to "ai.name" which is less user
26303  friendly, but usually has a value.
26304  */
26305  if (ai.handle[0] != '\0') {
26306  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.handle, (size_t)-1);
26307  } else {
26308  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.name, (size_t)-1);
26309  }
26310 
26311  pDeviceInfo->minChannels = ai.min_channels;
26312  pDeviceInfo->maxChannels = ai.max_channels;
26313  pDeviceInfo->minSampleRate = ai.min_rate;
26314  pDeviceInfo->maxSampleRate = ai.max_rate;
26315  pDeviceInfo->formatCount = 0;
26316 
26317  if (deviceType == ma_device_type_playback) {
26318  formatMask = ai.oformats;
26319  } else {
26320  formatMask = ai.iformats;
26321  }
26322 
26323  if ((formatMask & AFMT_U8) != 0) {
26324  pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_u8;
26325  }
26326  if (((formatMask & AFMT_S16_LE) != 0 && ma_is_little_endian()) || (AFMT_S16_BE && ma_is_big_endian())) {
26327  pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s16;
26328  }
26329  if (((formatMask & AFMT_S32_LE) != 0 && ma_is_little_endian()) || (AFMT_S32_BE && ma_is_big_endian())) {
26330  pDeviceInfo->formats[pDeviceInfo->formatCount++] = ma_format_s32;
26331  }
26332 
26333  foundDevice = MA_TRUE;
26334  break;
26335  }
26336  }
26337  }
26338  }
26339  } else {
26340  close(fdTemp);
26341  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.", MA_NO_BACKEND);
26342  }
26343 
26344 
26345  close(fdTemp);
26346 
26347  if (!foundDevice) {
26348  return MA_NO_DEVICE;
26349  }
26350 
26351  return MA_SUCCESS;
26352 }
26353 
26354 static void ma_device_uninit__oss(ma_device* pDevice)
26355 {
26356  MA_ASSERT(pDevice != NULL);
26357 
26358  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
26359  close(pDevice->oss.fdCapture);
26360  }
26361 
26362  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
26363  close(pDevice->oss.fdPlayback);
26364  }
26365 }
26366 
26367 static int ma_format_to_oss(ma_format format)
26368 {
26369  int ossFormat = AFMT_U8;
26370  switch (format) {
26371  case ma_format_s16: ossFormat = (ma_is_little_endian()) ? AFMT_S16_LE : AFMT_S16_BE; break;
26372  case ma_format_s24: ossFormat = (ma_is_little_endian()) ? AFMT_S32_LE : AFMT_S32_BE; break;
26373  case ma_format_s32: ossFormat = (ma_is_little_endian()) ? AFMT_S32_LE : AFMT_S32_BE; break;
26374  case ma_format_f32: ossFormat = (ma_is_little_endian()) ? AFMT_S16_LE : AFMT_S16_BE; break;
26375  case ma_format_u8:
26376  default: ossFormat = AFMT_U8; break;
26377  }
26378 
26379  return ossFormat;
26380 }
26381 
26382 static ma_format ma_format_from_oss(int ossFormat)
26383 {
26384  if (ossFormat == AFMT_U8) {
26385  return ma_format_u8;
26386  } else {
26387  if (ma_is_little_endian()) {
26388  switch (ossFormat) {
26389  case AFMT_S16_LE: return ma_format_s16;
26390  case AFMT_S32_LE: return ma_format_s32;
26391  default: return ma_format_unknown;
26392  }
26393  } else {
26394  switch (ossFormat) {
26395  case AFMT_S16_BE: return ma_format_s16;
26396  case AFMT_S32_BE: return ma_format_s32;
26397  default: return ma_format_unknown;
26398  }
26399  }
26400  }
26401 
26402  return ma_format_unknown;
26403 }
26404 
26405 static ma_result ma_device_init_fd__oss(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice)
26406 {
26407  ma_result result;
26408  int ossResult;
26409  int fd;
26410  const ma_device_id* pDeviceID = NULL;
26411  ma_share_mode shareMode;
26412  int ossFormat;
26413  int ossChannels;
26414  int ossSampleRate;
26415  int ossFragment;
26416 
26417  MA_ASSERT(pContext != NULL);
26418  MA_ASSERT(pConfig != NULL);
26419  MA_ASSERT(deviceType != ma_device_type_duplex);
26420  MA_ASSERT(pDevice != NULL);
26421 
26422  (void)pContext;
26423 
26424  if (deviceType == ma_device_type_capture) {
26425  pDeviceID = pConfig->capture.pDeviceID;
26426  shareMode = pConfig->capture.shareMode;
26427  ossFormat = ma_format_to_oss(pConfig->capture.format);
26428  ossChannels = (int)pConfig->capture.channels;
26429  ossSampleRate = (int)pConfig->sampleRate;
26430  } else {
26431  pDeviceID = pConfig->playback.pDeviceID;
26432  shareMode = pConfig->playback.shareMode;
26433  ossFormat = ma_format_to_oss(pConfig->playback.format);
26434  ossChannels = (int)pConfig->playback.channels;
26435  ossSampleRate = (int)pConfig->sampleRate;
26436  }
26437 
26438  result = ma_context_open_device__oss(pContext, deviceType, pDeviceID, shareMode, &fd);
26439  if (result != MA_SUCCESS) {
26440  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result);
26441  }
26442 
26443  /*
26444  The OSS documantation is very clear about the order we should be initializing the device's properties:
26445  1) Format
26446  2) Channels
26447  3) Sample rate.
26448  */
26449 
26450  /* Format. */
26451  ossResult = ioctl(fd, SNDCTL_DSP_SETFMT, &ossFormat);
26452  if (ossResult == -1) {
26453  close(fd);
26454  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set format.", MA_FORMAT_NOT_SUPPORTED);
26455  }
26456 
26457  /* Channels. */
26458  ossResult = ioctl(fd, SNDCTL_DSP_CHANNELS, &ossChannels);
26459  if (ossResult == -1) {
26460  close(fd);
26461  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set channel count.", MA_FORMAT_NOT_SUPPORTED);
26462  }
26463 
26464  /* Sample Rate. */
26465  ossResult = ioctl(fd, SNDCTL_DSP_SPEED, &ossSampleRate);
26466  if (ossResult == -1) {
26467  close(fd);
26468  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set sample rate.", MA_FORMAT_NOT_SUPPORTED);
26469  }
26470 
26471  /*
26472  Buffer.
26473 
26474  The documentation says that the fragment settings should be set as soon as possible, but I'm not sure if
26475  it should be done before or after format/channels/rate.
26476 
26477  OSS wants the fragment size in bytes and a power of 2. When setting, we specify the power, not the actual
26478  value.
26479  */
26480  {
26481  ma_uint32 periodSizeInFrames;
26482  ma_uint32 periodSizeInBytes;
26483  ma_uint32 ossFragmentSizePower;
26484 
26485  periodSizeInFrames = pConfig->periodSizeInFrames;
26486  if (periodSizeInFrames == 0) {
26487  periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, (ma_uint32)ossSampleRate);
26488  }
26489 
26490  periodSizeInBytes = ma_round_to_power_of_2(periodSizeInFrames * ma_get_bytes_per_frame(ma_format_from_oss(ossFormat), ossChannels));
26491  if (periodSizeInBytes < 16) {
26492  periodSizeInBytes = 16;
26493  }
26494 
26495  ossFragmentSizePower = 4;
26496  periodSizeInBytes >>= 4;
26497  while (periodSizeInBytes >>= 1) {
26498  ossFragmentSizePower += 1;
26499  }
26500 
26501  ossFragment = (int)((pConfig->periods << 16) | ossFragmentSizePower);
26502  ossResult = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &ossFragment);
26503  if (ossResult == -1) {
26504  close(fd);
26505  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set fragment size and period count.", MA_FORMAT_NOT_SUPPORTED);
26506  }
26507  }
26508 
26509  /* Internal settings. */
26510  if (deviceType == ma_device_type_capture) {
26511  pDevice->oss.fdCapture = fd;
26512  pDevice->capture.internalFormat = ma_format_from_oss(ossFormat);
26513  pDevice->capture.internalChannels = ossChannels;
26514  pDevice->capture.internalSampleRate = ossSampleRate;
26516  pDevice->capture.internalPeriods = (ma_uint32)(ossFragment >> 16);
26517  pDevice->capture.internalPeriodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
26518 
26519  if (pDevice->capture.internalFormat == ma_format_unknown) {
26520  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED);
26521  }
26522  } else {
26523  pDevice->oss.fdPlayback = fd;
26524  pDevice->playback.internalFormat = ma_format_from_oss(ossFormat);
26525  pDevice->playback.internalChannels = ossChannels;
26526  pDevice->playback.internalSampleRate = ossSampleRate;
26528  pDevice->playback.internalPeriods = (ma_uint32)(ossFragment >> 16);
26529  pDevice->playback.internalPeriodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
26530 
26531  if (pDevice->playback.internalFormat == ma_format_unknown) {
26532  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED);
26533  }
26534  }
26535 
26536  return MA_SUCCESS;
26537 }
26538 
26539 static ma_result ma_device_init__oss(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
26540 {
26541  MA_ASSERT(pContext != NULL);
26542  MA_ASSERT(pConfig != NULL);
26543  MA_ASSERT(pDevice != NULL);
26544 
26545  MA_ZERO_OBJECT(&pDevice->oss);
26546 
26547  if (pConfig->deviceType == ma_device_type_loopback) {
26549  }
26550 
26551  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
26552  ma_result result = ma_device_init_fd__oss(pContext, pConfig, ma_device_type_capture, pDevice);
26553  if (result != MA_SUCCESS) {
26554  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result);
26555  }
26556  }
26557 
26558  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
26559  ma_result result = ma_device_init_fd__oss(pContext, pConfig, ma_device_type_playback, pDevice);
26560  if (result != MA_SUCCESS) {
26561  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result);
26562  }
26563  }
26564 
26565  return MA_SUCCESS;
26566 }
26567 
26568 static ma_result ma_device_stop__oss(ma_device* pDevice)
26569 {
26570  MA_ASSERT(pDevice != NULL);
26571 
26572  /*
26573  We want to use SNDCTL_DSP_HALT. From the documentation:
26574 
26575  In multithreaded applications SNDCTL_DSP_HALT (SNDCTL_DSP_RESET) must only be called by the thread
26576  that actually reads/writes the audio device. It must not be called by some master thread to kill the
26577  audio thread. The audio thread will not stop or get any kind of notification that the device was
26578  stopped by the master thread. The device gets stopped but the next read or write call will silently
26579  restart the device.
26580 
26581  This is actually safe in our case, because this function is only ever called from within our worker
26582  thread anyway. Just keep this in mind, though...
26583  */
26584 
26585  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
26586  int result = ioctl(pDevice->oss.fdCapture, SNDCTL_DSP_HALT, 0);
26587  if (result == -1) {
26588  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", ma_result_from_errno(errno));
26589  }
26590  }
26591 
26592  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
26593  int result = ioctl(pDevice->oss.fdPlayback, SNDCTL_DSP_HALT, 0);
26594  if (result == -1) {
26595  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to stop device. SNDCTL_DSP_HALT failed.", ma_result_from_errno(errno));
26596  }
26597  }
26598 
26599  return MA_SUCCESS;
26600 }
26601 
26602 static ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
26603 {
26604  int resultOSS;
26605 
26606  if (pFramesWritten != NULL) {
26607  *pFramesWritten = 0;
26608  }
26609 
26610  resultOSS = write(pDevice->oss.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
26611  if (resultOSS < 0) {
26612  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device.", ma_result_from_errno(errno));
26613  }
26614 
26615  if (pFramesWritten != NULL) {
26616  *pFramesWritten = (ma_uint32)resultOSS / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
26617  }
26618 
26619  return MA_SUCCESS;
26620 }
26621 
26622 static ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
26623 {
26624  int resultOSS;
26625 
26626  if (pFramesRead != NULL) {
26627  *pFramesRead = 0;
26628  }
26629 
26630  resultOSS = read(pDevice->oss.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
26631  if (resultOSS < 0) {
26632  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client.", ma_result_from_errno(errno));
26633  }
26634 
26635  if (pFramesRead != NULL) {
26636  *pFramesRead = (ma_uint32)resultOSS / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
26637  }
26638 
26639  return MA_SUCCESS;
26640 }
26641 
26642 static ma_result ma_device_main_loop__oss(ma_device* pDevice)
26643 {
26644  ma_result result = MA_SUCCESS;
26645  ma_bool32 exitLoop = MA_FALSE;
26646 
26647  /* No need to explicitly start the device like the other backends. */
26648 
26649  while (ma_device__get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
26650  switch (pDevice->type)
26651  {
26652  case ma_device_type_duplex:
26653  {
26654  /* The process is: device_read -> convert -> callback -> convert -> device_write */
26655  ma_uint32 totalCapturedDeviceFramesProcessed = 0;
26656  ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
26657 
26658  while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
26659  ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
26660  ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
26661  ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
26662  ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
26663  ma_uint32 capturedDeviceFramesRemaining;
26664  ma_uint32 capturedDeviceFramesProcessed;
26665  ma_uint32 capturedDeviceFramesToProcess;
26666  ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed;
26667  if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) {
26668  capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames;
26669  }
26670 
26671  result = ma_device_read__oss(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess);
26672  if (result != MA_SUCCESS) {
26673  exitLoop = MA_TRUE;
26674  break;
26675  }
26676 
26677  capturedDeviceFramesRemaining = capturedDeviceFramesToProcess;
26678  capturedDeviceFramesProcessed = 0;
26679 
26680  for (;;) {
26681  ma_uint8 capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
26682  ma_uint8 playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
26683  ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
26684  ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
26685  ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames);
26686  ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining;
26687  ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
26688 
26689  /* Convert capture data from device format to client format. */
26690  result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration);
26691  if (result != MA_SUCCESS) {
26692  break;
26693  }
26694 
26695  /*
26696  If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small
26697  which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
26698  */
26699  if (capturedClientFramesToProcessThisIteration == 0) {
26700  break;
26701  }
26702 
26703  ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration); /* Safe cast .*/
26704 
26705  capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
26706  capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
26707 
26708  /* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */
26709  for (;;) {
26710  ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration;
26711  ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames;
26712  result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount);
26713  if (result != MA_SUCCESS) {
26714  break;
26715  }
26716 
26717  result = ma_device_write__oss(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL); /* Safe cast. */
26718  if (result != MA_SUCCESS) {
26719  exitLoop = MA_TRUE;
26720  break;
26721  }
26722 
26723  capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount; /* Safe cast. */
26724  if (capturedClientFramesToProcessThisIteration == 0) {
26725  break;
26726  }
26727  }
26728 
26729  /* In case an error happened from ma_device_write__oss()... */
26730  if (result != MA_SUCCESS) {
26731  exitLoop = MA_TRUE;
26732  break;
26733  }
26734  }
26735 
26736  totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed;
26737  }
26738  } break;
26739 
26741  {
26742  /* We read in chunks of the period size, but use a stack allocated buffer for the intermediary. */
26743  ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
26744  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
26745  ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
26746  ma_uint32 framesReadThisPeriod = 0;
26747  while (framesReadThisPeriod < periodSizeInFrames) {
26748  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
26749  ma_uint32 framesProcessed;
26750  ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
26751  if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
26752  framesToReadThisIteration = intermediaryBufferSizeInFrames;
26753  }
26754 
26755  result = ma_device_read__oss(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
26756  if (result != MA_SUCCESS) {
26757  exitLoop = MA_TRUE;
26758  break;
26759  }
26760 
26761  ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
26762 
26763  framesReadThisPeriod += framesProcessed;
26764  }
26765  } break;
26766 
26768  {
26769  /* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
26770  ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
26771  ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
26772  ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
26773  ma_uint32 framesWrittenThisPeriod = 0;
26774  while (framesWrittenThisPeriod < periodSizeInFrames) {
26775  ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
26776  ma_uint32 framesProcessed;
26777  ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
26778  if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
26779  framesToWriteThisIteration = intermediaryBufferSizeInFrames;
26780  }
26781 
26782  ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
26783 
26784  result = ma_device_write__oss(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
26785  if (result != MA_SUCCESS) {
26786  exitLoop = MA_TRUE;
26787  break;
26788  }
26789 
26790  framesWrittenThisPeriod += framesProcessed;
26791  }
26792  } break;
26793 
26794  /* To silence a warning. Will never hit this. */
26796  default: break;
26797  }
26798  }
26799 
26800 
26801  /* Here is where the device is stopped. */
26802  ma_device_stop__oss(pDevice);
26803 
26804  return result;
26805 }
26806 
26807 static ma_result ma_context_uninit__oss(ma_context* pContext)
26808 {
26809  MA_ASSERT(pContext != NULL);
26810  MA_ASSERT(pContext->backend == ma_backend_oss);
26811 
26812  (void)pContext;
26813  return MA_SUCCESS;
26814 }
26815 
26816 static ma_result ma_context_init__oss(const ma_context_config* pConfig, ma_context* pContext)
26817 {
26818  int fd;
26819  int ossVersion;
26820  int result;
26821 
26822  MA_ASSERT(pContext != NULL);
26823 
26824  (void)pConfig;
26825 
26826  /* Try opening a temporary device first so we can get version information. This is closed at the end. */
26827  fd = ma_open_temp_device__oss();
26828  if (fd == -1) {
26829  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open temporary device for retrieving system properties.", MA_NO_BACKEND); /* Looks liks OSS isn't installed, or there are no available devices. */
26830  }
26831 
26832  /* Grab the OSS version. */
26833  ossVersion = 0;
26834  result = ioctl(fd, OSS_GETVERSION, &ossVersion);
26835  if (result == -1) {
26836  close(fd);
26837  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve OSS version.", MA_NO_BACKEND);
26838  }
26839 
26840  pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16);
26841  pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8);
26842 
26843  pContext->onUninit = ma_context_uninit__oss;
26844  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__oss;
26845  pContext->onEnumDevices = ma_context_enumerate_devices__oss;
26846  pContext->onGetDeviceInfo = ma_context_get_device_info__oss;
26847  pContext->onDeviceInit = ma_device_init__oss;
26848  pContext->onDeviceUninit = ma_device_uninit__oss;
26849  pContext->onDeviceStart = NULL; /* Not required for synchronous backends. */
26850  pContext->onDeviceStop = NULL; /* Not required for synchronous backends. */
26851  pContext->onDeviceMainLoop = ma_device_main_loop__oss;
26852 
26853  close(fd);
26854  return MA_SUCCESS;
26855 }
26856 #endif /* OSS */
26857 
26858 
26859 /******************************************************************************
26860 
26861 AAudio Backend
26862 
26863 ******************************************************************************/
26864 #ifdef MA_HAS_AAUDIO
26865 /*#include <AAudio/AAudio.h>*/
26866 
26867 #define MA_AAUDIO_UNSPECIFIED 0
26868 
26869 typedef int32_t ma_aaudio_result_t;
26870 typedef int32_t ma_aaudio_direction_t;
26871 typedef int32_t ma_aaudio_sharing_mode_t;
26872 typedef int32_t ma_aaudio_format_t;
26873 typedef int32_t ma_aaudio_stream_state_t;
26874 typedef int32_t ma_aaudio_performance_mode_t;
26875 typedef int32_t ma_aaudio_data_callback_result_t;
26876 
26877 /* Result codes. miniaudio only cares about the success code. */
26878 #define MA_AAUDIO_OK 0
26879 
26880 /* Directions. */
26881 #define MA_AAUDIO_DIRECTION_OUTPUT 0
26882 #define MA_AAUDIO_DIRECTION_INPUT 1
26883 
26884 /* Sharing modes. */
26885 #define MA_AAUDIO_SHARING_MODE_EXCLUSIVE 0
26886 #define MA_AAUDIO_SHARING_MODE_SHARED 1
26887 
26888 /* Formats. */
26889 #define MA_AAUDIO_FORMAT_PCM_I16 1
26890 #define MA_AAUDIO_FORMAT_PCM_FLOAT 2
26891 
26892 /* Stream states. */
26893 #define MA_AAUDIO_STREAM_STATE_UNINITIALIZED 0
26894 #define MA_AAUDIO_STREAM_STATE_UNKNOWN 1
26895 #define MA_AAUDIO_STREAM_STATE_OPEN 2
26896 #define MA_AAUDIO_STREAM_STATE_STARTING 3
26897 #define MA_AAUDIO_STREAM_STATE_STARTED 4
26898 #define MA_AAUDIO_STREAM_STATE_PAUSING 5
26899 #define MA_AAUDIO_STREAM_STATE_PAUSED 6
26900 #define MA_AAUDIO_STREAM_STATE_FLUSHING 7
26901 #define MA_AAUDIO_STREAM_STATE_FLUSHED 8
26902 #define MA_AAUDIO_STREAM_STATE_STOPPING 9
26903 #define MA_AAUDIO_STREAM_STATE_STOPPED 10
26904 #define MA_AAUDIO_STREAM_STATE_CLOSING 11
26905 #define MA_AAUDIO_STREAM_STATE_CLOSED 12
26906 #define MA_AAUDIO_STREAM_STATE_DISCONNECTED 13
26907 
26908 /* Performance modes. */
26909 #define MA_AAUDIO_PERFORMANCE_MODE_NONE 10
26910 #define MA_AAUDIO_PERFORMANCE_MODE_POWER_SAVING 11
26911 #define MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY 12
26912 
26913 /* Callback results. */
26914 #define MA_AAUDIO_CALLBACK_RESULT_CONTINUE 0
26915 #define MA_AAUDIO_CALLBACK_RESULT_STOP 1
26916 
26917 /* Objects. */
26918 typedef struct ma_AAudioStreamBuilder_t* ma_AAudioStreamBuilder;
26919 typedef struct ma_AAudioStream_t* ma_AAudioStream;
26920 
26921 typedef ma_aaudio_data_callback_result_t (* ma_AAudioStream_dataCallback) (ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t numFrames);
26922 typedef void (* ma_AAudioStream_errorCallback)(ma_AAudioStream *pStream, void *pUserData, ma_aaudio_result_t error);
26923 
26924 typedef ma_aaudio_result_t (* MA_PFN_AAudio_createStreamBuilder) (ma_AAudioStreamBuilder** ppBuilder);
26925 typedef ma_aaudio_result_t (* MA_PFN_AAudioStreamBuilder_delete) (ma_AAudioStreamBuilder* pBuilder);
26926 typedef void (* MA_PFN_AAudioStreamBuilder_setDeviceId) (ma_AAudioStreamBuilder* pBuilder, int32_t deviceId);
26927 typedef void (* MA_PFN_AAudioStreamBuilder_setDirection) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_direction_t direction);
26928 typedef void (* MA_PFN_AAudioStreamBuilder_setSharingMode) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_sharing_mode_t sharingMode);
26929 typedef void (* MA_PFN_AAudioStreamBuilder_setFormat) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_format_t format);
26930 typedef void (* MA_PFN_AAudioStreamBuilder_setChannelCount) (ma_AAudioStreamBuilder* pBuilder, int32_t channelCount);
26931 typedef void (* MA_PFN_AAudioStreamBuilder_setSampleRate) (ma_AAudioStreamBuilder* pBuilder, int32_t sampleRate);
26932 typedef void (* MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)(ma_AAudioStreamBuilder* pBuilder, int32_t numFrames);
26933 typedef void (* MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback) (ma_AAudioStreamBuilder* pBuilder, int32_t numFrames);
26934 typedef void (* MA_PFN_AAudioStreamBuilder_setDataCallback) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream_dataCallback callback, void* pUserData);
26935 typedef void (* MA_PFN_AAudioStreamBuilder_setErrorCallback) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream_errorCallback callback, void* pUserData);
26936 typedef void (* MA_PFN_AAudioStreamBuilder_setPerformanceMode) (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_performance_mode_t mode);
26937 typedef ma_aaudio_result_t (* MA_PFN_AAudioStreamBuilder_openStream) (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream** ppStream);
26938 typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_close) (ma_AAudioStream* pStream);
26939 typedef ma_aaudio_stream_state_t (* MA_PFN_AAudioStream_getState) (ma_AAudioStream* pStream);
26940 typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_waitForStateChange) (ma_AAudioStream* pStream, ma_aaudio_stream_state_t inputState, ma_aaudio_stream_state_t* pNextState, int64_t timeoutInNanoseconds);
26941 typedef ma_aaudio_format_t (* MA_PFN_AAudioStream_getFormat) (ma_AAudioStream* pStream);
26942 typedef int32_t (* MA_PFN_AAudioStream_getChannelCount) (ma_AAudioStream* pStream);
26943 typedef int32_t (* MA_PFN_AAudioStream_getSampleRate) (ma_AAudioStream* pStream);
26944 typedef int32_t (* MA_PFN_AAudioStream_getBufferCapacityInFrames) (ma_AAudioStream* pStream);
26945 typedef int32_t (* MA_PFN_AAudioStream_getFramesPerDataCallback) (ma_AAudioStream* pStream);
26946 typedef int32_t (* MA_PFN_AAudioStream_getFramesPerBurst) (ma_AAudioStream* pStream);
26947 typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_requestStart) (ma_AAudioStream* pStream);
26948 typedef ma_aaudio_result_t (* MA_PFN_AAudioStream_requestStop) (ma_AAudioStream* pStream);
26949 
26950 static ma_result ma_result_from_aaudio(ma_aaudio_result_t resultAA)
26951 {
26952  switch (resultAA)
26953  {
26954  case MA_AAUDIO_OK: return MA_SUCCESS;
26955  default: break;
26956  }
26957 
26958  return MA_ERROR;
26959 }
26960 
26961 static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUserData, ma_aaudio_result_t error)
26962 {
26963  ma_device* pDevice = (ma_device*)pUserData;
26964  MA_ASSERT(pDevice != NULL);
26965 
26966  (void)error;
26967 
26968 #if defined(MA_DEBUG_OUTPUT)
26969  printf("[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream));
26970 #endif
26971 
26972  /*
26973  From the documentation for AAudio, when a device is disconnected all we can do is stop it. However, we cannot stop it from the callback - we need
26974  to do it from another thread. Therefore we are going to use an event thread for the AAudio backend to do this cleanly and safely.
26975  */
26976  if (((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream) == MA_AAUDIO_STREAM_STATE_DISCONNECTED) {
26977 #if defined(MA_DEBUG_OUTPUT)
26978  printf("[AAudio] Device Disconnected.\n");
26979 #endif
26980  }
26981 }
26982 
26983 static ma_aaudio_data_callback_result_t ma_stream_data_callback_capture__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount)
26984 {
26985  ma_device* pDevice = (ma_device*)pUserData;
26986  MA_ASSERT(pDevice != NULL);
26987 
26988  if (pDevice->type == ma_device_type_duplex) {
26989  ma_device__handle_duplex_callback_capture(pDevice, frameCount, pAudioData, &pDevice->aaudio.duplexRB);
26990  } else {
26991  ma_device__send_frames_to_client(pDevice, frameCount, pAudioData); /* Send directly to the client. */
26992  }
26993 
26994  (void)pStream;
26995  return MA_AAUDIO_CALLBACK_RESULT_CONTINUE;
26996 }
26997 
26998 static ma_aaudio_data_callback_result_t ma_stream_data_callback_playback__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount)
26999 {
27000  ma_device* pDevice = (ma_device*)pUserData;
27001  MA_ASSERT(pDevice != NULL);
27002 
27003  if (pDevice->type == ma_device_type_duplex) {
27004  ma_device__handle_duplex_callback_playback(pDevice, frameCount, pAudioData, &pDevice->aaudio.duplexRB);
27005  } else {
27006  ma_device__read_frames_from_client(pDevice, frameCount, pAudioData); /* Read directly from the client. */
27007  }
27008 
27009  (void)pStream;
27010  return MA_AAUDIO_CALLBACK_RESULT_CONTINUE;
27011 }
27012 
27013 static ma_result ma_open_stream__aaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, const ma_device_config* pConfig, const ma_device* pDevice, ma_AAudioStream** ppStream)
27014 {
27015  ma_AAudioStreamBuilder* pBuilder;
27016  ma_aaudio_result_t resultAA;
27017 
27018  MA_ASSERT(deviceType != ma_device_type_duplex); /* This function should not be called for a full-duplex device type. */
27019 
27020  *ppStream = NULL;
27021 
27022  resultAA = ((MA_PFN_AAudio_createStreamBuilder)pContext->aaudio.AAudio_createStreamBuilder)(&pBuilder);
27023  if (resultAA != MA_AAUDIO_OK) {
27024  return ma_result_from_aaudio(resultAA);
27025  }
27026 
27027  if (pDeviceID != NULL) {
27028  ((MA_PFN_AAudioStreamBuilder_setDeviceId)pContext->aaudio.AAudioStreamBuilder_setDeviceId)(pBuilder, pDeviceID->aaudio);
27029  }
27030 
27031  ((MA_PFN_AAudioStreamBuilder_setDirection)pContext->aaudio.AAudioStreamBuilder_setDirection)(pBuilder, (deviceType == ma_device_type_playback) ? MA_AAUDIO_DIRECTION_OUTPUT : MA_AAUDIO_DIRECTION_INPUT);
27032  ((MA_PFN_AAudioStreamBuilder_setSharingMode)pContext->aaudio.AAudioStreamBuilder_setSharingMode)(pBuilder, (shareMode == ma_share_mode_shared) ? MA_AAUDIO_SHARING_MODE_SHARED : MA_AAUDIO_SHARING_MODE_EXCLUSIVE);
27033 
27034  if (pConfig != NULL) {
27035  ma_uint32 bufferCapacityInFrames;
27036 
27037  if (pDevice == NULL || !pDevice->usingDefaultSampleRate) {
27038  ((MA_PFN_AAudioStreamBuilder_setSampleRate)pContext->aaudio.AAudioStreamBuilder_setSampleRate)(pBuilder, pConfig->sampleRate);
27039  }
27040 
27041  if (deviceType == ma_device_type_capture) {
27042  if (pDevice == NULL || !pDevice->capture.usingDefaultChannels) {
27043  ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pConfig->capture.channels);
27044  }
27045  if (pDevice == NULL || !pDevice->capture.usingDefaultFormat) {
27046  ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pConfig->capture.format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT);
27047  }
27048  } else {
27049  if (pDevice == NULL || !pDevice->playback.usingDefaultChannels) {
27050  ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pConfig->playback.channels);
27051  }
27052  if (pDevice == NULL || !pDevice->playback.usingDefaultFormat) {
27053  ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pConfig->playback.format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT);
27054  }
27055  }
27056 
27057  bufferCapacityInFrames = pConfig->periodSizeInFrames * pConfig->periods;
27058  if (bufferCapacityInFrames == 0) {
27059  bufferCapacityInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, pConfig->sampleRate) * pConfig->periods;
27060  }
27061 
27062  ((MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames)(pBuilder, bufferCapacityInFrames);
27063  ((MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback)pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback)(pBuilder, bufferCapacityInFrames / pConfig->periods);
27064 
27065  if (deviceType == ma_device_type_capture) {
27066  ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_capture__aaudio, (void*)pDevice);
27067  } else {
27068  ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_playback__aaudio, (void*)pDevice);
27069  }
27070 
27071  /* Not sure how this affects things, but since there's a mapping between miniaudio's performance profiles and AAudio's performance modes, let go ahead and set it. */
27072  ((MA_PFN_AAudioStreamBuilder_setPerformanceMode)pContext->aaudio.AAudioStreamBuilder_setPerformanceMode)(pBuilder, (pConfig->performanceProfile == ma_performance_profile_low_latency) ? MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY : MA_AAUDIO_PERFORMANCE_MODE_NONE);
27073  }
27074 
27075  ((MA_PFN_AAudioStreamBuilder_setErrorCallback)pContext->aaudio.AAudioStreamBuilder_setErrorCallback)(pBuilder, ma_stream_error_callback__aaudio, (void*)pDevice);
27076 
27077  resultAA = ((MA_PFN_AAudioStreamBuilder_openStream)pContext->aaudio.AAudioStreamBuilder_openStream)(pBuilder, ppStream);
27078  if (resultAA != MA_AAUDIO_OK) {
27079  *ppStream = NULL;
27080  ((MA_PFN_AAudioStreamBuilder_delete)pContext->aaudio.AAudioStreamBuilder_delete)(pBuilder);
27081  return ma_result_from_aaudio(resultAA);
27082  }
27083 
27084  ((MA_PFN_AAudioStreamBuilder_delete)pContext->aaudio.AAudioStreamBuilder_delete)(pBuilder);
27085  return MA_SUCCESS;
27086 }
27087 
27088 static ma_result ma_close_stream__aaudio(ma_context* pContext, ma_AAudioStream* pStream)
27089 {
27090  return ma_result_from_aaudio(((MA_PFN_AAudioStream_close)pContext->aaudio.AAudioStream_close)(pStream));
27091 }
27092 
27093 static ma_bool32 ma_has_default_device__aaudio(ma_context* pContext, ma_device_type deviceType)
27094 {
27095  /* The only way to know this is to try creating a stream. */
27096  ma_AAudioStream* pStream;
27097  ma_result result = ma_open_stream__aaudio(pContext, deviceType, NULL, ma_share_mode_shared, NULL, NULL, &pStream);
27098  if (result != MA_SUCCESS) {
27099  return MA_FALSE;
27100  }
27101 
27102  ma_close_stream__aaudio(pContext, pStream);
27103  return MA_TRUE;
27104 }
27105 
27106 static ma_result ma_wait_for_simple_state_transition__aaudio(ma_context* pContext, ma_AAudioStream* pStream, ma_aaudio_stream_state_t oldState, ma_aaudio_stream_state_t newState)
27107 {
27108  ma_aaudio_stream_state_t actualNewState;
27109  ma_aaudio_result_t resultAA = ((MA_PFN_AAudioStream_waitForStateChange)pContext->aaudio.AAudioStream_waitForStateChange)(pStream, oldState, &actualNewState, 5000000000); /* 5 second timeout. */
27110  if (resultAA != MA_AAUDIO_OK) {
27111  return ma_result_from_aaudio(resultAA);
27112  }
27113 
27114  if (newState != actualNewState) {
27115  return MA_ERROR; /* Failed to transition into the expected state. */
27116  }
27117 
27118  return MA_SUCCESS;
27119 }
27120 
27121 
27122 static ma_bool32 ma_context_is_device_id_equal__aaudio(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
27123 {
27124  MA_ASSERT(pContext != NULL);
27125  MA_ASSERT(pID0 != NULL);
27126  MA_ASSERT(pID1 != NULL);
27127  (void)pContext;
27128 
27129  return pID0->aaudio == pID1->aaudio;
27130 }
27131 
27132 static ma_result ma_context_enumerate_devices__aaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
27133 {
27134  ma_bool32 cbResult = MA_TRUE;
27135 
27136  MA_ASSERT(pContext != NULL);
27137  MA_ASSERT(callback != NULL);
27138 
27139  /* Unfortunately AAudio does not have an enumeration API. Therefore I'm only going to report default devices, but only if it can instantiate a stream. */
27140 
27141  /* Playback. */
27142  if (cbResult) {
27143  ma_device_info deviceInfo;
27144  MA_ZERO_OBJECT(&deviceInfo);
27145  deviceInfo.id.aaudio = MA_AAUDIO_UNSPECIFIED;
27146  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
27147 
27148  if (ma_has_default_device__aaudio(pContext, ma_device_type_playback)) {
27149  cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
27150  }
27151  }
27152 
27153  /* Capture. */
27154  if (cbResult) {
27155  ma_device_info deviceInfo;
27156  MA_ZERO_OBJECT(&deviceInfo);
27157  deviceInfo.id.aaudio = MA_AAUDIO_UNSPECIFIED;
27158  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
27159 
27160  if (ma_has_default_device__aaudio(pContext, ma_device_type_capture)) {
27161  cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
27162  }
27163  }
27164 
27165  return MA_SUCCESS;
27166 }
27167 
27168 static ma_result ma_context_get_device_info__aaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
27169 {
27170  ma_AAudioStream* pStream;
27171  ma_result result;
27172 
27173  MA_ASSERT(pContext != NULL);
27174 
27175  /* No exclusive mode with AAudio. */
27176  if (shareMode == ma_share_mode_exclusive) {
27178  }
27179 
27180  /* ID */
27181  if (pDeviceID != NULL) {
27182  pDeviceInfo->id.aaudio = pDeviceID->aaudio;
27183  } else {
27184  pDeviceInfo->id.aaudio = MA_AAUDIO_UNSPECIFIED;
27185  }
27186 
27187  /* Name */
27188  if (deviceType == ma_device_type_playback) {
27189  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
27190  } else {
27191  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
27192  }
27193 
27194 
27195  /* We'll need to open the device to get accurate sample rate and channel count information. */
27196  result = ma_open_stream__aaudio(pContext, deviceType, pDeviceID, shareMode, NULL, NULL, &pStream);
27197  if (result != MA_SUCCESS) {
27198  return result;
27199  }
27200 
27201  pDeviceInfo->minChannels = ((MA_PFN_AAudioStream_getChannelCount)pContext->aaudio.AAudioStream_getChannelCount)(pStream);
27202  pDeviceInfo->maxChannels = pDeviceInfo->minChannels;
27203  pDeviceInfo->minSampleRate = ((MA_PFN_AAudioStream_getSampleRate)pContext->aaudio.AAudioStream_getSampleRate)(pStream);
27204  pDeviceInfo->maxSampleRate = pDeviceInfo->minSampleRate;
27205 
27206  ma_close_stream__aaudio(pContext, pStream);
27207  pStream = NULL;
27208 
27209 
27210  /* AAudio supports s16 and f32. */
27211  pDeviceInfo->formatCount = 2;
27212  pDeviceInfo->formats[0] = ma_format_s16;
27213  pDeviceInfo->formats[1] = ma_format_f32;
27214 
27215  return MA_SUCCESS;
27216 }
27217 
27218 
27219 static void ma_device_uninit__aaudio(ma_device* pDevice)
27220 {
27221  MA_ASSERT(pDevice != NULL);
27222 
27223  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
27224  ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
27225  pDevice->aaudio.pStreamCapture = NULL;
27226  }
27227 
27228  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
27229  ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
27230  pDevice->aaudio.pStreamPlayback = NULL;
27231  }
27232 
27233  if (pDevice->type == ma_device_type_duplex) {
27234  ma_pcm_rb_uninit(&pDevice->aaudio.duplexRB);
27235  }
27236 }
27237 
27238 static ma_result ma_device_init__aaudio(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
27239 {
27240  ma_result result;
27241 
27242  MA_ASSERT(pDevice != NULL);
27243 
27244  if (pConfig->deviceType == ma_device_type_loopback) {
27246  }
27247 
27248  /* No exclusive mode with AAudio. */
27252  }
27253 
27254  /* We first need to try opening the stream. */
27255  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
27256  int32_t bufferCapacityInFrames;
27257  int32_t framesPerDataCallback;
27258 
27259  result = ma_open_stream__aaudio(pContext, ma_device_type_capture, pConfig->capture.pDeviceID, pConfig->capture.shareMode, pConfig, pDevice, (ma_AAudioStream**)&pDevice->aaudio.pStreamCapture);
27260  if (result != MA_SUCCESS) {
27261  return result; /* Failed to open the AAudio stream. */
27262  }
27263 
27264  pDevice->capture.internalFormat = (((MA_PFN_AAudioStream_getFormat)pContext->aaudio.AAudioStream_getFormat)((ma_AAudioStream*)pDevice->aaudio.pStreamCapture) == MA_AAUDIO_FORMAT_PCM_I16) ? ma_format_s16 : ma_format_f32;
27265  pDevice->capture.internalChannels = ((MA_PFN_AAudioStream_getChannelCount)pContext->aaudio.AAudioStream_getChannelCount)((ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
27266  pDevice->capture.internalSampleRate = ((MA_PFN_AAudioStream_getSampleRate)pContext->aaudio.AAudioStream_getSampleRate)((ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
27267  ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap); /* <-- Cannot find info on channel order, so assuming a default. */
27268 
27269  bufferCapacityInFrames = ((MA_PFN_AAudioStream_getBufferCapacityInFrames)pContext->aaudio.AAudioStream_getBufferCapacityInFrames)((ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
27270  framesPerDataCallback = ((MA_PFN_AAudioStream_getFramesPerDataCallback)pContext->aaudio.AAudioStream_getFramesPerDataCallback)((ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
27271 
27272  if (framesPerDataCallback > 0) {
27273  pDevice->capture.internalPeriodSizeInFrames = framesPerDataCallback;
27274  pDevice->capture.internalPeriods = bufferCapacityInFrames / framesPerDataCallback;
27275  } else {
27276  pDevice->capture.internalPeriodSizeInFrames = bufferCapacityInFrames;
27277  pDevice->capture.internalPeriods = 1;
27278  }
27279  }
27280 
27281  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
27282  int32_t bufferCapacityInFrames;
27283  int32_t framesPerDataCallback;
27284 
27285  result = ma_open_stream__aaudio(pContext, ma_device_type_playback, pConfig->playback.pDeviceID, pConfig->playback.shareMode, pConfig, pDevice, (ma_AAudioStream**)&pDevice->aaudio.pStreamPlayback);
27286  if (result != MA_SUCCESS) {
27287  return result; /* Failed to open the AAudio stream. */
27288  }
27289 
27290  pDevice->playback.internalFormat = (((MA_PFN_AAudioStream_getFormat)pContext->aaudio.AAudioStream_getFormat)((ma_AAudioStream*)pDevice->aaudio.pStreamPlayback) == MA_AAUDIO_FORMAT_PCM_I16) ? ma_format_s16 : ma_format_f32;
27291  pDevice->playback.internalChannels = ((MA_PFN_AAudioStream_getChannelCount)pContext->aaudio.AAudioStream_getChannelCount)((ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
27292  pDevice->playback.internalSampleRate = ((MA_PFN_AAudioStream_getSampleRate)pContext->aaudio.AAudioStream_getSampleRate)((ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
27293  ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap); /* <-- Cannot find info on channel order, so assuming a default. */
27294 
27295  bufferCapacityInFrames = ((MA_PFN_AAudioStream_getBufferCapacityInFrames)pContext->aaudio.AAudioStream_getBufferCapacityInFrames)((ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
27296  framesPerDataCallback = ((MA_PFN_AAudioStream_getFramesPerDataCallback)pContext->aaudio.AAudioStream_getFramesPerDataCallback)((ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
27297 
27298  if (framesPerDataCallback > 0) {
27299  pDevice->playback.internalPeriodSizeInFrames = framesPerDataCallback;
27300  pDevice->playback.internalPeriods = bufferCapacityInFrames / framesPerDataCallback;
27301  } else {
27302  pDevice->playback.internalPeriodSizeInFrames = bufferCapacityInFrames;
27303  pDevice->playback.internalPeriods = 1;
27304  }
27305  }
27306 
27307  if (pConfig->deviceType == ma_device_type_duplex) {
27309  ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->aaudio.duplexRB);
27310  if (result != MA_SUCCESS) {
27311  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
27312  ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
27313  }
27314  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
27315  ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
27316  }
27317  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[AAudio] Failed to initialize ring buffer.", result);
27318  }
27319 
27320  /* We need a period to act as a buffer for cases where the playback and capture device's end up desyncing. */
27321  {
27322  ma_uint32 marginSizeInFrames = rbSizeInFrames / pDevice->capture.internalPeriods;
27323  void* pMarginData;
27324  ma_pcm_rb_acquire_write(&pDevice->aaudio.duplexRB, &marginSizeInFrames, &pMarginData);
27325  {
27326  MA_ZERO_MEMORY(pMarginData, marginSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
27327  }
27328  ma_pcm_rb_commit_write(&pDevice->aaudio.duplexRB, marginSizeInFrames, pMarginData);
27329  }
27330  }
27331 
27332  return MA_SUCCESS;
27333 }
27334 
27335 static ma_result ma_device_start_stream__aaudio(ma_device* pDevice, ma_AAudioStream* pStream)
27336 {
27337  ma_aaudio_result_t resultAA;
27338  ma_aaudio_stream_state_t currentState;
27339 
27340  MA_ASSERT(pDevice != NULL);
27341 
27342  resultAA = ((MA_PFN_AAudioStream_requestStart)pDevice->pContext->aaudio.AAudioStream_requestStart)(pStream);
27343  if (resultAA != MA_AAUDIO_OK) {
27344  return ma_result_from_aaudio(resultAA);
27345  }
27346 
27347  /* Do we actually need to wait for the device to transition into it's started state? */
27348 
27349  /* The device should be in either a starting or started state. If it's not set to started we need to wait for it to transition. It should go from starting to started. */
27350  currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream);
27351  if (currentState != MA_AAUDIO_STREAM_STATE_STARTED) {
27352  ma_result result;
27353 
27354  if (currentState != MA_AAUDIO_STREAM_STATE_STARTING) {
27355  return MA_ERROR; /* Expecting the stream to be a starting or started state. */
27356  }
27357 
27358  result = ma_wait_for_simple_state_transition__aaudio(pDevice->pContext, pStream, currentState, MA_AAUDIO_STREAM_STATE_STARTED);
27359  if (result != MA_SUCCESS) {
27360  return result;
27361  }
27362  }
27363 
27364  return MA_SUCCESS;
27365 }
27366 
27367 static ma_result ma_device_stop_stream__aaudio(ma_device* pDevice, ma_AAudioStream* pStream)
27368 {
27369  ma_aaudio_result_t resultAA;
27370  ma_aaudio_stream_state_t currentState;
27371 
27372  MA_ASSERT(pDevice != NULL);
27373 
27374  /*
27375  From the AAudio documentation:
27376 
27377  The stream will stop after all of the data currently buffered has been played.
27378 
27379  This maps with miniaudio's requirement that device's be drained which means we don't need to implement any draining logic.
27380  */
27381 
27382  resultAA = ((MA_PFN_AAudioStream_requestStop)pDevice->pContext->aaudio.AAudioStream_requestStop)(pStream);
27383  if (resultAA != MA_AAUDIO_OK) {
27384  return ma_result_from_aaudio(resultAA);
27385  }
27386 
27387  /* The device should be in either a stopping or stopped state. If it's not set to started we need to wait for it to transition. It should go from stopping to stopped. */
27388  currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream);
27389  if (currentState != MA_AAUDIO_STREAM_STATE_STOPPED) {
27390  ma_result result;
27391 
27392  if (currentState != MA_AAUDIO_STREAM_STATE_STOPPING) {
27393  return MA_ERROR; /* Expecting the stream to be a stopping or stopped state. */
27394  }
27395 
27396  result = ma_wait_for_simple_state_transition__aaudio(pDevice->pContext, pStream, currentState, MA_AAUDIO_STREAM_STATE_STOPPED);
27397  if (result != MA_SUCCESS) {
27398  return result;
27399  }
27400  }
27401 
27402  return MA_SUCCESS;
27403 }
27404 
27405 static ma_result ma_device_start__aaudio(ma_device* pDevice)
27406 {
27407  MA_ASSERT(pDevice != NULL);
27408 
27409  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
27410  ma_result result = ma_device_start_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
27411  if (result != MA_SUCCESS) {
27412  return result;
27413  }
27414  }
27415 
27416  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
27417  ma_result result = ma_device_start_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
27418  if (result != MA_SUCCESS) {
27419  if (pDevice->type == ma_device_type_duplex) {
27420  ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
27421  }
27422  return result;
27423  }
27424  }
27425 
27426  return MA_SUCCESS;
27427 }
27428 
27429 static ma_result ma_device_stop__aaudio(ma_device* pDevice)
27430 {
27431  ma_stop_proc onStop;
27432 
27433  MA_ASSERT(pDevice != NULL);
27434 
27435  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
27436  ma_result result = ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
27437  if (result != MA_SUCCESS) {
27438  return result;
27439  }
27440  }
27441 
27442  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
27443  ma_result result = ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
27444  if (result != MA_SUCCESS) {
27445  return result;
27446  }
27447  }
27448 
27449  onStop = pDevice->onStop;
27450  if (onStop) {
27451  onStop(pDevice);
27452  }
27453 
27454  return MA_SUCCESS;
27455 }
27456 
27457 
27458 static ma_result ma_context_uninit__aaudio(ma_context* pContext)
27459 {
27460  MA_ASSERT(pContext != NULL);
27461  MA_ASSERT(pContext->backend == ma_backend_aaudio);
27462 
27463  ma_dlclose(pContext, pContext->aaudio.hAAudio);
27464  pContext->aaudio.hAAudio = NULL;
27465 
27466  return MA_SUCCESS;
27467 }
27468 
27469 static ma_result ma_context_init__aaudio(const ma_context_config* pConfig, ma_context* pContext)
27470 {
27471  const char* libNames[] = {
27472  "libaaudio.so"
27473  };
27474  size_t i;
27475 
27476  for (i = 0; i < ma_countof(libNames); ++i) {
27477  pContext->aaudio.hAAudio = ma_dlopen(pContext, libNames[i]);
27478  if (pContext->aaudio.hAAudio != NULL) {
27479  break;
27480  }
27481  }
27482 
27483  if (pContext->aaudio.hAAudio == NULL) {
27485  }
27486 
27487  pContext->aaudio.AAudio_createStreamBuilder = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudio_createStreamBuilder");
27488  pContext->aaudio.AAudioStreamBuilder_delete = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_delete");
27489  pContext->aaudio.AAudioStreamBuilder_setDeviceId = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDeviceId");
27490  pContext->aaudio.AAudioStreamBuilder_setDirection = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDirection");
27491  pContext->aaudio.AAudioStreamBuilder_setSharingMode = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSharingMode");
27492  pContext->aaudio.AAudioStreamBuilder_setFormat = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFormat");
27493  pContext->aaudio.AAudioStreamBuilder_setChannelCount = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setChannelCount");
27494  pContext->aaudio.AAudioStreamBuilder_setSampleRate = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSampleRate");
27495  pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setBufferCapacityInFrames");
27496  pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFramesPerDataCallback");
27497  pContext->aaudio.AAudioStreamBuilder_setDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDataCallback");
27498  pContext->aaudio.AAudioStreamBuilder_setErrorCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setErrorCallback");
27499  pContext->aaudio.AAudioStreamBuilder_setPerformanceMode = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setPerformanceMode");
27500  pContext->aaudio.AAudioStreamBuilder_openStream = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_openStream");
27501  pContext->aaudio.AAudioStream_close = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_close");
27502  pContext->aaudio.AAudioStream_getState = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getState");
27503  pContext->aaudio.AAudioStream_waitForStateChange = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_waitForStateChange");
27504  pContext->aaudio.AAudioStream_getFormat = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFormat");
27505  pContext->aaudio.AAudioStream_getChannelCount = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getChannelCount");
27506  pContext->aaudio.AAudioStream_getSampleRate = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getSampleRate");
27507  pContext->aaudio.AAudioStream_getBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getBufferCapacityInFrames");
27508  pContext->aaudio.AAudioStream_getFramesPerDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerDataCallback");
27509  pContext->aaudio.AAudioStream_getFramesPerBurst = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerBurst");
27510  pContext->aaudio.AAudioStream_requestStart = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStart");
27511  pContext->aaudio.AAudioStream_requestStop = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStop");
27512 
27513  pContext->isBackendAsynchronous = MA_TRUE;
27514 
27515  pContext->onUninit = ma_context_uninit__aaudio;
27516  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__aaudio;
27517  pContext->onEnumDevices = ma_context_enumerate_devices__aaudio;
27518  pContext->onGetDeviceInfo = ma_context_get_device_info__aaudio;
27519  pContext->onDeviceInit = ma_device_init__aaudio;
27520  pContext->onDeviceUninit = ma_device_uninit__aaudio;
27521  pContext->onDeviceStart = ma_device_start__aaudio;
27522  pContext->onDeviceStop = ma_device_stop__aaudio;
27523 
27524  (void)pConfig;
27525  return MA_SUCCESS;
27526 }
27527 #endif /* AAudio */
27528 
27529 
27530 /******************************************************************************
27531 
27532 OpenSL|ES Backend
27533 
27534 ******************************************************************************/
27535 #ifdef MA_HAS_OPENSL
27536 #include <SLES/OpenSLES.h>
27537 #ifdef MA_ANDROID
27538 #include <SLES/OpenSLES_Android.h>
27539 #endif
27540 
27541 /* OpenSL|ES has one-per-application objects :( */
27542 SLObjectItf g_maEngineObjectSL = NULL;
27543 SLEngineItf g_maEngineSL = NULL;
27544 ma_uint32 g_maOpenSLInitCounter = 0;
27545 
27546 #define MA_OPENSL_OBJ(p) (*((SLObjectItf)(p)))
27547 #define MA_OPENSL_OUTPUTMIX(p) (*((SLOutputMixItf)(p)))
27548 #define MA_OPENSL_PLAY(p) (*((SLPlayItf)(p)))
27549 #define MA_OPENSL_RECORD(p) (*((SLRecordItf)(p)))
27550 
27551 #ifdef MA_ANDROID
27552 #define MA_OPENSL_BUFFERQUEUE(p) (*((SLAndroidSimpleBufferQueueItf)(p)))
27553 #else
27554 #define MA_OPENSL_BUFFERQUEUE(p) (*((SLBufferQueueItf)(p)))
27555 #endif
27556 
27557 static ma_result ma_result_from_OpenSL(SLuint32 result)
27558 {
27559  switch (result)
27560  {
27561  case SL_RESULT_SUCCESS: return MA_SUCCESS;
27562  case SL_RESULT_PRECONDITIONS_VIOLATED: return MA_ERROR;
27563  case SL_RESULT_PARAMETER_INVALID: return MA_INVALID_ARGS;
27564  case SL_RESULT_MEMORY_FAILURE: return MA_OUT_OF_MEMORY;
27565  case SL_RESULT_RESOURCE_ERROR: return MA_INVALID_DATA;
27566  case SL_RESULT_RESOURCE_LOST: return MA_ERROR;
27567  case SL_RESULT_IO_ERROR: return MA_IO_ERROR;
27568  case SL_RESULT_BUFFER_INSUFFICIENT: return MA_NO_SPACE;
27569  case SL_RESULT_CONTENT_CORRUPTED: return MA_INVALID_DATA;
27570  case SL_RESULT_CONTENT_UNSUPPORTED: return MA_FORMAT_NOT_SUPPORTED;
27571  case SL_RESULT_CONTENT_NOT_FOUND: return MA_ERROR;
27572  case SL_RESULT_PERMISSION_DENIED: return MA_ACCESS_DENIED;
27573  case SL_RESULT_FEATURE_UNSUPPORTED: return MA_NOT_IMPLEMENTED;
27574  case SL_RESULT_INTERNAL_ERROR: return MA_ERROR;
27575  case SL_RESULT_UNKNOWN_ERROR: return MA_ERROR;
27576  case SL_RESULT_OPERATION_ABORTED: return MA_ERROR;
27577  case SL_RESULT_CONTROL_LOST: return MA_ERROR;
27578  default: return MA_ERROR;
27579  }
27580 }
27581 
27582 /* Converts an individual OpenSL-style channel identifier (SL_SPEAKER_FRONT_LEFT, etc.) to miniaudio. */
27583 static ma_uint8 ma_channel_id_to_ma__opensl(SLuint32 id)
27584 {
27585  switch (id)
27586  {
27587  case SL_SPEAKER_FRONT_LEFT: return MA_CHANNEL_FRONT_LEFT;
27588  case SL_SPEAKER_FRONT_RIGHT: return MA_CHANNEL_FRONT_RIGHT;
27589  case SL_SPEAKER_FRONT_CENTER: return MA_CHANNEL_FRONT_CENTER;
27590  case SL_SPEAKER_LOW_FREQUENCY: return MA_CHANNEL_LFE;
27591  case SL_SPEAKER_BACK_LEFT: return MA_CHANNEL_BACK_LEFT;
27592  case SL_SPEAKER_BACK_RIGHT: return MA_CHANNEL_BACK_RIGHT;
27593  case SL_SPEAKER_FRONT_LEFT_OF_CENTER: return MA_CHANNEL_FRONT_LEFT_CENTER;
27594  case SL_SPEAKER_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER;
27595  case SL_SPEAKER_BACK_CENTER: return MA_CHANNEL_BACK_CENTER;
27596  case SL_SPEAKER_SIDE_LEFT: return MA_CHANNEL_SIDE_LEFT;
27597  case SL_SPEAKER_SIDE_RIGHT: return MA_CHANNEL_SIDE_RIGHT;
27598  case SL_SPEAKER_TOP_CENTER: return MA_CHANNEL_TOP_CENTER;
27599  case SL_SPEAKER_TOP_FRONT_LEFT: return MA_CHANNEL_TOP_FRONT_LEFT;
27600  case SL_SPEAKER_TOP_FRONT_CENTER: return MA_CHANNEL_TOP_FRONT_CENTER;
27601  case SL_SPEAKER_TOP_FRONT_RIGHT: return MA_CHANNEL_TOP_FRONT_RIGHT;
27602  case SL_SPEAKER_TOP_BACK_LEFT: return MA_CHANNEL_TOP_BACK_LEFT;
27603  case SL_SPEAKER_TOP_BACK_CENTER: return MA_CHANNEL_TOP_BACK_CENTER;
27604  case SL_SPEAKER_TOP_BACK_RIGHT: return MA_CHANNEL_TOP_BACK_RIGHT;
27605  default: return 0;
27606  }
27607 }
27608 
27609 /* Converts an individual miniaudio channel identifier (MA_CHANNEL_FRONT_LEFT, etc.) to OpenSL-style. */
27610 static SLuint32 ma_channel_id_to_opensl(ma_uint8 id)
27611 {
27612  switch (id)
27613  {
27614  case MA_CHANNEL_MONO: return SL_SPEAKER_FRONT_CENTER;
27615  case MA_CHANNEL_FRONT_LEFT: return SL_SPEAKER_FRONT_LEFT;
27616  case MA_CHANNEL_FRONT_RIGHT: return SL_SPEAKER_FRONT_RIGHT;
27617  case MA_CHANNEL_FRONT_CENTER: return SL_SPEAKER_FRONT_CENTER;
27618  case MA_CHANNEL_LFE: return SL_SPEAKER_LOW_FREQUENCY;
27619  case MA_CHANNEL_BACK_LEFT: return SL_SPEAKER_BACK_LEFT;
27620  case MA_CHANNEL_BACK_RIGHT: return SL_SPEAKER_BACK_RIGHT;
27621  case MA_CHANNEL_FRONT_LEFT_CENTER: return SL_SPEAKER_FRONT_LEFT_OF_CENTER;
27622  case MA_CHANNEL_FRONT_RIGHT_CENTER: return SL_SPEAKER_FRONT_RIGHT_OF_CENTER;
27623  case MA_CHANNEL_BACK_CENTER: return SL_SPEAKER_BACK_CENTER;
27624  case MA_CHANNEL_SIDE_LEFT: return SL_SPEAKER_SIDE_LEFT;
27625  case MA_CHANNEL_SIDE_RIGHT: return SL_SPEAKER_SIDE_RIGHT;
27626  case MA_CHANNEL_TOP_CENTER: return SL_SPEAKER_TOP_CENTER;
27627  case MA_CHANNEL_TOP_FRONT_LEFT: return SL_SPEAKER_TOP_FRONT_LEFT;
27628  case MA_CHANNEL_TOP_FRONT_CENTER: return SL_SPEAKER_TOP_FRONT_CENTER;
27629  case MA_CHANNEL_TOP_FRONT_RIGHT: return SL_SPEAKER_TOP_FRONT_RIGHT;
27630  case MA_CHANNEL_TOP_BACK_LEFT: return SL_SPEAKER_TOP_BACK_LEFT;
27631  case MA_CHANNEL_TOP_BACK_CENTER: return SL_SPEAKER_TOP_BACK_CENTER;
27632  case MA_CHANNEL_TOP_BACK_RIGHT: return SL_SPEAKER_TOP_BACK_RIGHT;
27633  default: return 0;
27634  }
27635 }
27636 
27637 /* Converts a channel mapping to an OpenSL-style channel mask. */
27638 static SLuint32 ma_channel_map_to_channel_mask__opensl(const ma_channel channelMap[MA_MAX_CHANNELS], ma_uint32 channels)
27639 {
27640  SLuint32 channelMask = 0;
27641  ma_uint32 iChannel;
27642  for (iChannel = 0; iChannel < channels; ++iChannel) {
27643  channelMask |= ma_channel_id_to_opensl(channelMap[iChannel]);
27644  }
27645 
27646  return channelMask;
27647 }
27648 
27649 /* Converts an OpenSL-style channel mask to a miniaudio channel map. */
27650 static void ma_channel_mask_to_channel_map__opensl(SLuint32 channelMask, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS])
27651 {
27652  if (channels == 1 && channelMask == 0) {
27653  channelMap[0] = MA_CHANNEL_MONO;
27654  } else if (channels == 2 && channelMask == 0) {
27655  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
27656  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
27657  } else {
27658  if (channels == 1 && (channelMask & SL_SPEAKER_FRONT_CENTER) != 0) {
27659  channelMap[0] = MA_CHANNEL_MONO;
27660  } else {
27661  /* Just iterate over each bit. */
27662  ma_uint32 iChannel = 0;
27663  ma_uint32 iBit;
27664  for (iBit = 0; iBit < 32; ++iBit) {
27665  SLuint32 bitValue = (channelMask & (1UL << iBit));
27666  if (bitValue != 0) {
27667  /* The bit is set. */
27668  channelMap[iChannel] = ma_channel_id_to_ma__opensl(bitValue);
27669  iChannel += 1;
27670  }
27671  }
27672  }
27673  }
27674 }
27675 
27676 static SLuint32 ma_round_to_standard_sample_rate__opensl(SLuint32 samplesPerSec)
27677 {
27678  if (samplesPerSec <= SL_SAMPLINGRATE_8) {
27679  return SL_SAMPLINGRATE_8;
27680  }
27681  if (samplesPerSec <= SL_SAMPLINGRATE_11_025) {
27682  return SL_SAMPLINGRATE_11_025;
27683  }
27684  if (samplesPerSec <= SL_SAMPLINGRATE_12) {
27685  return SL_SAMPLINGRATE_12;
27686  }
27687  if (samplesPerSec <= SL_SAMPLINGRATE_16) {
27688  return SL_SAMPLINGRATE_16;
27689  }
27690  if (samplesPerSec <= SL_SAMPLINGRATE_22_05) {
27691  return SL_SAMPLINGRATE_22_05;
27692  }
27693  if (samplesPerSec <= SL_SAMPLINGRATE_24) {
27694  return SL_SAMPLINGRATE_24;
27695  }
27696  if (samplesPerSec <= SL_SAMPLINGRATE_32) {
27697  return SL_SAMPLINGRATE_32;
27698  }
27699  if (samplesPerSec <= SL_SAMPLINGRATE_44_1) {
27700  return SL_SAMPLINGRATE_44_1;
27701  }
27702  if (samplesPerSec <= SL_SAMPLINGRATE_48) {
27703  return SL_SAMPLINGRATE_48;
27704  }
27705 
27706  /* Android doesn't support more than 48000. */
27707 #ifndef MA_ANDROID
27708  if (samplesPerSec <= SL_SAMPLINGRATE_64) {
27709  return SL_SAMPLINGRATE_64;
27710  }
27711  if (samplesPerSec <= SL_SAMPLINGRATE_88_2) {
27712  return SL_SAMPLINGRATE_88_2;
27713  }
27714  if (samplesPerSec <= SL_SAMPLINGRATE_96) {
27715  return SL_SAMPLINGRATE_96;
27716  }
27717  if (samplesPerSec <= SL_SAMPLINGRATE_192) {
27718  return SL_SAMPLINGRATE_192;
27719  }
27720 #endif
27721 
27722  return SL_SAMPLINGRATE_16;
27723 }
27724 
27725 
27726 static ma_bool32 ma_context_is_device_id_equal__opensl(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
27727 {
27728  MA_ASSERT(pContext != NULL);
27729  MA_ASSERT(pID0 != NULL);
27730  MA_ASSERT(pID1 != NULL);
27731  (void)pContext;
27732 
27733  return pID0->opensl == pID1->opensl;
27734 }
27735 
27736 static ma_result ma_context_enumerate_devices__opensl(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
27737 {
27738  ma_bool32 cbResult;
27739 
27740  MA_ASSERT(pContext != NULL);
27741  MA_ASSERT(callback != NULL);
27742 
27743  MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it and then attempted to enumerate devices. */
27744  if (g_maOpenSLInitCounter == 0) {
27745  return MA_INVALID_OPERATION;
27746  }
27747 
27748  /*
27749  TODO: Test Me.
27750 
27751  This is currently untested, so for now we are just returning default devices.
27752  */
27753 #if 0 && !defined(MA_ANDROID)
27754  ma_bool32 isTerminated = MA_FALSE;
27755 
27756  SLuint32 pDeviceIDs[128];
27757  SLint32 deviceCount = sizeof(pDeviceIDs) / sizeof(pDeviceIDs[0]);
27758 
27759  SLAudioIODeviceCapabilitiesItf deviceCaps;
27760  SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps);
27761  if (resultSL != SL_RESULT_SUCCESS) {
27762  /* The interface may not be supported so just report a default device. */
27763  goto return_default_device;
27764  }
27765 
27766  /* Playback */
27767  if (!isTerminated) {
27768  resultSL = (*deviceCaps)->GetAvailableAudioOutputs(deviceCaps, &deviceCount, pDeviceIDs);
27769  if (resultSL != SL_RESULT_SUCCESS) {
27770  return ma_result_from_OpenSL(resultSL);
27771  }
27772 
27773  for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) {
27774  ma_device_info deviceInfo;
27775  MA_ZERO_OBJECT(&deviceInfo);
27776  deviceInfo.id.opensl = pDeviceIDs[iDevice];
27777 
27778  SLAudioOutputDescriptor desc;
27779  resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, deviceInfo.id.opensl, &desc);
27780  if (resultSL == SL_RESULT_SUCCESS) {
27781  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)desc.pDeviceName, (size_t)-1);
27782 
27783  ma_bool32 cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
27784  if (cbResult == MA_FALSE) {
27785  isTerminated = MA_TRUE;
27786  break;
27787  }
27788  }
27789  }
27790  }
27791 
27792  /* Capture */
27793  if (!isTerminated) {
27794  resultSL = (*deviceCaps)->GetAvailableAudioInputs(deviceCaps, &deviceCount, pDeviceIDs);
27795  if (resultSL != SL_RESULT_SUCCESS) {
27796  return ma_result_from_OpenSL(resultSL);
27797  }
27798 
27799  for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) {
27800  ma_device_info deviceInfo;
27801  MA_ZERO_OBJECT(&deviceInfo);
27802  deviceInfo.id.opensl = pDeviceIDs[iDevice];
27803 
27804  SLAudioInputDescriptor desc;
27805  resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, deviceInfo.id.opensl, &desc);
27806  if (resultSL == SL_RESULT_SUCCESS) {
27807  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)desc.deviceName, (size_t)-1);
27808 
27809  ma_bool32 cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
27810  if (cbResult == MA_FALSE) {
27811  isTerminated = MA_TRUE;
27812  break;
27813  }
27814  }
27815  }
27816  }
27817 
27818  return MA_SUCCESS;
27819 #else
27820  goto return_default_device;
27821 #endif
27822 
27823 return_default_device:;
27824  cbResult = MA_TRUE;
27825 
27826  /* Playback. */
27827  if (cbResult) {
27828  ma_device_info deviceInfo;
27829  MA_ZERO_OBJECT(&deviceInfo);
27830  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
27831  cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
27832  }
27833 
27834  /* Capture. */
27835  if (cbResult) {
27836  ma_device_info deviceInfo;
27837  MA_ZERO_OBJECT(&deviceInfo);
27838  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
27839  cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
27840  }
27841 
27842  return MA_SUCCESS;
27843 }
27844 
27845 static ma_result ma_context_get_device_info__opensl(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
27846 {
27847  MA_ASSERT(pContext != NULL);
27848 
27849  MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it and then attempted to get device info. */
27850  if (g_maOpenSLInitCounter == 0) {
27851  return MA_INVALID_OPERATION;
27852  }
27853 
27854  /* No exclusive mode with OpenSL|ES. */
27855  if (shareMode == ma_share_mode_exclusive) {
27857  }
27858 
27859  /*
27860  TODO: Test Me.
27861 
27862  This is currently untested, so for now we are just returning default devices.
27863  */
27864 #if 0 && !defined(MA_ANDROID)
27865  SLAudioIODeviceCapabilitiesItf deviceCaps;
27866  SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps);
27867  if (resultSL != SL_RESULT_SUCCESS) {
27868  /* The interface may not be supported so just report a default device. */
27869  goto return_default_device;
27870  }
27871 
27872  if (deviceType == ma_device_type_playback) {
27873  SLAudioOutputDescriptor desc;
27874  resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, pDeviceID->opensl, &desc);
27875  if (resultSL != SL_RESULT_SUCCESS) {
27876  return ma_result_from_OpenSL(resultSL);
27877  }
27878 
27879  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (const char*)desc.pDeviceName, (size_t)-1);
27880  } else {
27881  SLAudioInputDescriptor desc;
27882  resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, pDeviceID->opensl, &desc);
27883  if (resultSL != SL_RESULT_SUCCESS) {
27884  return ma_result_from_OpenSL(resultSL);
27885  }
27886 
27887  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (const char*)desc.deviceName, (size_t)-1);
27888  }
27889 
27890  goto return_detailed_info;
27891 #else
27892  goto return_default_device;
27893 #endif
27894 
27895 return_default_device:
27896  if (pDeviceID != NULL) {
27897  if ((deviceType == ma_device_type_playback && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOOUTPUT) ||
27898  (deviceType == ma_device_type_capture && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOINPUT)) {
27899  return MA_NO_DEVICE; /* Don't know the device. */
27900  }
27901  }
27902 
27903  /* Name / Description */
27904  if (deviceType == ma_device_type_playback) {
27905  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
27906  } else {
27907  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
27908  }
27909 
27910  goto return_detailed_info;
27911 
27912 
27913 return_detailed_info:
27914 
27915  /*
27916  For now we're just outputting a set of values that are supported by the API but not necessarily supported
27917  by the device natively. Later on we should work on this so that it more closely reflects the device's
27918  actual native format.
27919  */
27920  pDeviceInfo->minChannels = 1;
27921  pDeviceInfo->maxChannels = 2;
27922  pDeviceInfo->minSampleRate = 8000;
27923  pDeviceInfo->maxSampleRate = 48000;
27924  pDeviceInfo->formatCount = 2;
27925  pDeviceInfo->formats[0] = ma_format_u8;
27926  pDeviceInfo->formats[1] = ma_format_s16;
27927 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
27928  pDeviceInfo->formats[pDeviceInfo->formatCount] = ma_format_f32;
27929  pDeviceInfo->formatCount += 1;
27930 #endif
27931 
27932  return MA_SUCCESS;
27933 }
27934 
27935 
27936 #ifdef MA_ANDROID
27937 /*void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, SLuint32 eventFlags, const void* pBuffer, SLuint32 bufferSize, SLuint32 dataUsed, void* pContext)*/
27938 static void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData)
27939 {
27940  ma_device* pDevice = (ma_device*)pUserData;
27941  size_t periodSizeInBytes;
27942  ma_uint8* pBuffer;
27943  SLresult resultSL;
27944 
27945  MA_ASSERT(pDevice != NULL);
27946 
27947  (void)pBufferQueue;
27948 
27949  /*
27950  For now, don't do anything unless the buffer was fully processed. From what I can tell, it looks like
27951  OpenSL|ES 1.1 improves on buffer queues to the point that we could much more intelligently handle this,
27952  but unfortunately it looks like Android is only supporting OpenSL|ES 1.0.1 for now :(
27953  */
27954 
27955  /* Don't do anything if the device is not started. */
27956  if (pDevice->state != MA_STATE_STARTED) {
27957  return;
27958  }
27959 
27960  /* Don't do anything if the device is being drained. */
27961  if (pDevice->opensl.isDrainingCapture) {
27962  return;
27963  }
27964 
27965  periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
27966  pBuffer = pDevice->opensl.pBufferCapture + (pDevice->opensl.currentBufferIndexCapture * periodSizeInBytes);
27967 
27968  if (pDevice->type == ma_device_type_duplex) {
27969  ma_device__handle_duplex_callback_capture(pDevice, pDevice->capture.internalPeriodSizeInFrames, pBuffer, &pDevice->opensl.duplexRB);
27970  } else {
27972  }
27973 
27974  resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pBuffer, periodSizeInBytes);
27975  if (resultSL != SL_RESULT_SUCCESS) {
27976  return;
27977  }
27978 
27979  pDevice->opensl.currentBufferIndexCapture = (pDevice->opensl.currentBufferIndexCapture + 1) % pDevice->capture.internalPeriods;
27980 }
27981 
27982 static void ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData)
27983 {
27984  ma_device* pDevice = (ma_device*)pUserData;
27985  size_t periodSizeInBytes;
27986  ma_uint8* pBuffer;
27987  SLresult resultSL;
27988 
27989  MA_ASSERT(pDevice != NULL);
27990 
27991  (void)pBufferQueue;
27992 
27993  /* Don't do anything if the device is not started. */
27994  if (pDevice->state != MA_STATE_STARTED) {
27995  return;
27996  }
27997 
27998  /* Don't do anything if the device is being drained. */
27999  if (pDevice->opensl.isDrainingPlayback) {
28000  return;
28001  }
28002 
28004  pBuffer = pDevice->opensl.pBufferPlayback + (pDevice->opensl.currentBufferIndexPlayback * periodSizeInBytes);
28005 
28006  if (pDevice->type == ma_device_type_duplex) {
28007  ma_device__handle_duplex_callback_playback(pDevice, pDevice->playback.internalPeriodSizeInFrames, pBuffer, &pDevice->opensl.duplexRB);
28008  } else {
28010  }
28011 
28012  resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pBuffer, periodSizeInBytes);
28013  if (resultSL != SL_RESULT_SUCCESS) {
28014  return;
28015  }
28016 
28017  pDevice->opensl.currentBufferIndexPlayback = (pDevice->opensl.currentBufferIndexPlayback + 1) % pDevice->playback.internalPeriods;
28018 }
28019 #endif
28020 
28021 static void ma_device_uninit__opensl(ma_device* pDevice)
28022 {
28023  MA_ASSERT(pDevice != NULL);
28024 
28025  MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it before uninitializing the device. */
28026  if (g_maOpenSLInitCounter == 0) {
28027  return;
28028  }
28029 
28030  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28031  if (pDevice->opensl.pAudioRecorderObj) {
28032  MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioRecorderObj);
28033  }
28034 
28035  ma__free_from_callbacks(pDevice->opensl.pBufferCapture, &pDevice->pContext->allocationCallbacks);
28036  }
28037 
28038  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28039  if (pDevice->opensl.pAudioPlayerObj) {
28040  MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioPlayerObj);
28041  }
28042  if (pDevice->opensl.pOutputMixObj) {
28043  MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Destroy((SLObjectItf)pDevice->opensl.pOutputMixObj);
28044  }
28045 
28046  ma__free_from_callbacks(pDevice->opensl.pBufferPlayback, &pDevice->pContext->allocationCallbacks);
28047  }
28048 
28049  if (pDevice->type == ma_device_type_duplex) {
28050  ma_pcm_rb_uninit(&pDevice->opensl.duplexRB);
28051  }
28052 }
28053 
28054 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
28055 typedef SLAndroidDataFormat_PCM_EX ma_SLDataFormat_PCM;
28056 #else
28057 typedef SLDataFormat_PCM ma_SLDataFormat_PCM;
28058 #endif
28059 
28060 static ma_result ma_SLDataFormat_PCM_init__opensl(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const ma_channel* channelMap, ma_SLDataFormat_PCM* pDataFormat)
28061 {
28062 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
28063  if (format == ma_format_f32) {
28064  pDataFormat->formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
28065  pDataFormat->representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
28066  } else {
28067  pDataFormat->formatType = SL_DATAFORMAT_PCM;
28068  }
28069 #else
28070  pDataFormat->formatType = SL_DATAFORMAT_PCM;
28071 #endif
28072 
28073  pDataFormat->numChannels = channels;
28074  ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = ma_round_to_standard_sample_rate__opensl(sampleRate * 1000); /* In millihertz. Annoyingly, the sample rate variable is named differently between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM */
28075  pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format)*8;
28076  pDataFormat->channelMask = ma_channel_map_to_channel_mask__opensl(channelMap, channels);
28077  pDataFormat->endianness = (ma_is_little_endian()) ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN;
28078 
28079  /*
28080  Android has a few restrictions on the format as documented here: https://developer.android.com/ndk/guides/audio/opensl-for-android.html
28081  - Only mono and stereo is supported.
28082  - Only u8 and s16 formats are supported.
28083  - Maximum sample rate of 48000.
28084  */
28085 #ifdef MA_ANDROID
28086  if (pDataFormat->numChannels > 2) {
28087  pDataFormat->numChannels = 2;
28088  }
28089 #if __ANDROID_API__ >= 21
28090  if (pDataFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) {
28091  /* It's floating point. */
28092  MA_ASSERT(pDataFormat->representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT);
28093  if (pDataFormat->bitsPerSample > 32) {
28094  pDataFormat->bitsPerSample = 32;
28095  }
28096  } else {
28097  if (pDataFormat->bitsPerSample > 16) {
28098  pDataFormat->bitsPerSample = 16;
28099  }
28100  }
28101 #else
28102  if (pDataFormat->bitsPerSample > 16) {
28103  pDataFormat->bitsPerSample = 16;
28104  }
28105 #endif
28106  if (((SLDataFormat_PCM*)pDataFormat)->samplesPerSec > SL_SAMPLINGRATE_48) {
28107  ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = SL_SAMPLINGRATE_48;
28108  }
28109 #endif
28110 
28111  pDataFormat->containerSize = pDataFormat->bitsPerSample; /* Always tightly packed for now. */
28112 
28113  return MA_SUCCESS;
28114 }
28115 
28116 static ma_result ma_deconstruct_SLDataFormat_PCM__opensl(ma_SLDataFormat_PCM* pDataFormat, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap)
28117 {
28118  ma_bool32 isFloatingPoint = MA_FALSE;
28119 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
28120  if (pDataFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) {
28121  MA_ASSERT(pDataFormat->representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT);
28122  isFloatingPoint = MA_TRUE;
28123  }
28124 #endif
28125  if (isFloatingPoint) {
28126  if (pDataFormat->bitsPerSample == 32) {
28127  *pFormat = ma_format_f32;
28128  }
28129  } else {
28130  if (pDataFormat->bitsPerSample == 8) {
28131  *pFormat = ma_format_u8;
28132  } else if (pDataFormat->bitsPerSample == 16) {
28133  *pFormat = ma_format_s16;
28134  } else if (pDataFormat->bitsPerSample == 24) {
28135  *pFormat = ma_format_s24;
28136  } else if (pDataFormat->bitsPerSample == 32) {
28137  *pFormat = ma_format_s32;
28138  }
28139  }
28140 
28141  *pChannels = pDataFormat->numChannels;
28142  *pSampleRate = ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec / 1000;
28143  ma_channel_mask_to_channel_map__opensl(pDataFormat->channelMask, pDataFormat->numChannels, pChannelMap);
28144 
28145  return MA_SUCCESS;
28146 }
28147 
28148 static ma_result ma_device_init__opensl(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
28149 {
28150 #ifdef MA_ANDROID
28151  SLDataLocator_AndroidSimpleBufferQueue queue;
28152  SLresult resultSL;
28153  ma_uint32 periodSizeInFrames;
28154  size_t bufferSizeInBytes;
28155  const SLInterfaceID itfIDs1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
28156  const SLboolean itfIDsRequired1[] = {SL_BOOLEAN_TRUE};
28157 #endif
28158 
28159  (void)pContext;
28160 
28161  MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it and then attempted to initialize a new device. */
28162  if (g_maOpenSLInitCounter == 0) {
28163  return MA_INVALID_OPERATION;
28164  }
28165 
28166  if (pConfig->deviceType == ma_device_type_loopback) {
28168  }
28169 
28170  /*
28171  For now, only supporting Android implementations of OpenSL|ES since that's the only one I've
28172  been able to test with and I currently depend on Android-specific extensions (simple buffer
28173  queues).
28174  */
28175 #ifdef MA_ANDROID
28176  /* No exclusive mode with OpenSL|ES. */
28180  }
28181 
28182  /* Now we can start initializing the device properly. */
28183  MA_ASSERT(pDevice != NULL);
28184  MA_ZERO_OBJECT(&pDevice->opensl);
28185 
28186  queue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
28187  queue.numBuffers = pConfig->periods;
28188 
28189 
28190  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
28191  ma_SLDataFormat_PCM pcm;
28192  SLDataLocator_IODevice locatorDevice;
28193  SLDataSource source;
28194  SLDataSink sink;
28195 
28196  ma_SLDataFormat_PCM_init__opensl(pConfig->capture.format, pConfig->capture.channels, pConfig->sampleRate, pConfig->capture.channelMap, &pcm);
28197 
28198  locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE;
28199  locatorDevice.deviceType = SL_IODEVICE_AUDIOINPUT;
28200  locatorDevice.deviceID = (pConfig->capture.pDeviceID == NULL) ? SL_DEFAULTDEVICEID_AUDIOINPUT : pConfig->capture.pDeviceID->opensl;
28201  locatorDevice.device = NULL;
28202 
28203  source.pLocator = &locatorDevice;
28204  source.pFormat = NULL;
28205 
28206  sink.pLocator = &queue;
28207  sink.pFormat = (SLDataFormat_PCM*)&pcm;
28208 
28209  resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
28210  if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) {
28211  /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
28212  pcm.formatType = SL_DATAFORMAT_PCM;
28213  pcm.numChannels = 1;
28214  ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16; /* The name of the sample rate variable is different between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM. */
28215  pcm.bitsPerSample = 16;
28216  pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */
28217  pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
28218  resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
28219  }
28220 
28221  if (resultSL != SL_RESULT_SUCCESS) {
28222  ma_device_uninit__opensl(pDevice);
28223  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio recorder.", ma_result_from_OpenSL(resultSL));
28224  }
28225 
28226  resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Realize((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_BOOLEAN_FALSE);
28227  if (resultSL != SL_RESULT_SUCCESS) {
28228  ma_device_uninit__opensl(pDevice);
28229  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder.", ma_result_from_OpenSL(resultSL));
28230  }
28231 
28232  resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_IID_RECORD, &pDevice->opensl.pAudioRecorder);
28233  if (resultSL != SL_RESULT_SUCCESS) {
28234  ma_device_uninit__opensl(pDevice);
28235  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.", ma_result_from_OpenSL(resultSL));
28236  }
28237 
28238  resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueueCapture);
28239  if (resultSL != SL_RESULT_SUCCESS) {
28240  ma_device_uninit__opensl(pDevice);
28241  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL));
28242  }
28243 
28244  resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, ma_buffer_queue_callback_capture__opensl_android, pDevice);
28245  if (resultSL != SL_RESULT_SUCCESS) {
28246  ma_device_uninit__opensl(pDevice);
28247  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", ma_result_from_OpenSL(resultSL));
28248  }
28249 
28250  /* The internal format is determined by the "pcm" object. */
28251  ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDevice->capture.internalFormat, &pDevice->capture.internalChannels, &pDevice->capture.internalSampleRate, pDevice->capture.internalChannelMap);
28252 
28253  /* Buffer. */
28254  periodSizeInFrames = pConfig->periodSizeInFrames;
28255  if (periodSizeInFrames == 0) {
28257  }
28258  pDevice->capture.internalPeriods = pConfig->periods;
28259  pDevice->capture.internalPeriodSizeInFrames = periodSizeInFrames;
28260  pDevice->opensl.currentBufferIndexCapture = 0;
28261 
28263  pDevice->opensl.pBufferCapture = (ma_uint8*)ma__calloc_from_callbacks(bufferSizeInBytes, &pContext->allocationCallbacks);
28264  if (pDevice->opensl.pBufferCapture == NULL) {
28265  ma_device_uninit__opensl(pDevice);
28266  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY);
28267  }
28268  MA_ZERO_MEMORY(pDevice->opensl.pBufferCapture, bufferSizeInBytes);
28269  }
28270 
28271  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
28272  ma_SLDataFormat_PCM pcm;
28273  SLDataSource source;
28274  SLDataLocator_OutputMix outmixLocator;
28275  SLDataSink sink;
28276 
28277  ma_SLDataFormat_PCM_init__opensl(pConfig->playback.format, pConfig->playback.channels, pConfig->sampleRate, pConfig->playback.channelMap, &pcm);
28278 
28279  resultSL = (*g_maEngineSL)->CreateOutputMix(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pOutputMixObj, 0, NULL, NULL);
28280  if (resultSL != SL_RESULT_SUCCESS) {
28281  ma_device_uninit__opensl(pDevice);
28282  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create output mix.", ma_result_from_OpenSL(resultSL));
28283  }
28284 
28285  resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Realize((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_BOOLEAN_FALSE);
28286  if (resultSL != SL_RESULT_SUCCESS) {
28287  ma_device_uninit__opensl(pDevice);
28288  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object.", ma_result_from_OpenSL(resultSL));
28289  }
28290 
28291  resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->GetInterface((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_IID_OUTPUTMIX, &pDevice->opensl.pOutputMix);
28292  if (resultSL != SL_RESULT_SUCCESS) {
28293  ma_device_uninit__opensl(pDevice);
28294  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.", ma_result_from_OpenSL(resultSL));
28295  }
28296 
28297  /* Set the output device. */
28298  if (pConfig->playback.pDeviceID != NULL) {
28299  SLuint32 deviceID_OpenSL = pConfig->playback.pDeviceID->opensl;
28300  MA_OPENSL_OUTPUTMIX(pDevice->opensl.pOutputMix)->ReRoute((SLOutputMixItf)pDevice->opensl.pOutputMix, 1, &deviceID_OpenSL);
28301  }
28302 
28303  source.pLocator = &queue;
28304  source.pFormat = (SLDataFormat_PCM*)&pcm;
28305 
28306  outmixLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX;
28307  outmixLocator.outputMix = (SLObjectItf)pDevice->opensl.pOutputMixObj;
28308 
28309  sink.pLocator = &outmixLocator;
28310  sink.pFormat = NULL;
28311 
28312  resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
28313  if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) {
28314  /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
28315  pcm.formatType = SL_DATAFORMAT_PCM;
28316  pcm.numChannels = 2;
28317  ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16;
28318  pcm.bitsPerSample = 16;
28319  pcm.containerSize = pcm.bitsPerSample; /* Always tightly packed for now. */
28320  pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
28321  resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
28322  }
28323 
28324  if (resultSL != SL_RESULT_SUCCESS) {
28325  ma_device_uninit__opensl(pDevice);
28326  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio player.", ma_result_from_OpenSL(resultSL));
28327  }
28328 
28329  resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Realize((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_BOOLEAN_FALSE);
28330  if (resultSL != SL_RESULT_SUCCESS) {
28331  ma_device_uninit__opensl(pDevice);
28332  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player.", ma_result_from_OpenSL(resultSL));
28333  }
28334 
28335  resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_IID_PLAY, &pDevice->opensl.pAudioPlayer);
28336  if (resultSL != SL_RESULT_SUCCESS) {
28337  ma_device_uninit__opensl(pDevice);
28338  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.", ma_result_from_OpenSL(resultSL));
28339  }
28340 
28341  resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueuePlayback);
28342  if (resultSL != SL_RESULT_SUCCESS) {
28343  ma_device_uninit__opensl(pDevice);
28344  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL));
28345  }
28346 
28347  resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, ma_buffer_queue_callback_playback__opensl_android, pDevice);
28348  if (resultSL != SL_RESULT_SUCCESS) {
28349  ma_device_uninit__opensl(pDevice);
28350  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", ma_result_from_OpenSL(resultSL));
28351  }
28352 
28353  /* The internal format is determined by the "pcm" object. */
28354  ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDevice->playback.internalFormat, &pDevice->playback.internalChannels, &pDevice->playback.internalSampleRate, pDevice->playback.internalChannelMap);
28355 
28356  /* Buffer. */
28357  periodSizeInFrames = pConfig->periodSizeInFrames;
28358  if (periodSizeInFrames == 0) {
28360  }
28361  pDevice->playback.internalPeriods = pConfig->periods;
28362  pDevice->playback.internalPeriodSizeInFrames = periodSizeInFrames;
28363  pDevice->opensl.currentBufferIndexPlayback = 0;
28364 
28366  pDevice->opensl.pBufferPlayback = (ma_uint8*)ma__calloc_from_callbacks(bufferSizeInBytes, &pContext->allocationCallbacks);
28367  if (pDevice->opensl.pBufferPlayback == NULL) {
28368  ma_device_uninit__opensl(pDevice);
28369  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY);
28370  }
28371  MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, bufferSizeInBytes);
28372  }
28373 
28374  if (pConfig->deviceType == ma_device_type_duplex) {
28376  ma_result result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->opensl.duplexRB);
28377  if (result != MA_SUCCESS) {
28378  ma_device_uninit__opensl(pDevice);
28379  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to initialize ring buffer.", result);
28380  }
28381 
28382  /* We need a period to act as a buffer for cases where the playback and capture device's end up desyncing. */
28383  {
28384  ma_uint32 marginSizeInFrames = rbSizeInFrames / pDevice->capture.internalPeriods;
28385  void* pMarginData;
28386  ma_pcm_rb_acquire_write(&pDevice->opensl.duplexRB, &marginSizeInFrames, &pMarginData);
28387  {
28388  MA_ZERO_MEMORY(pMarginData, marginSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
28389  }
28390  ma_pcm_rb_commit_write(&pDevice->opensl.duplexRB, marginSizeInFrames, pMarginData);
28391  }
28392  }
28393 
28394  return MA_SUCCESS;
28395 #else
28396  return MA_NO_BACKEND; /* Non-Android implementations are not supported. */
28397 #endif
28398 }
28399 
28400 static ma_result ma_device_start__opensl(ma_device* pDevice)
28401 {
28402  SLresult resultSL;
28403  size_t periodSizeInBytes;
28404  ma_uint32 iPeriod;
28405 
28406  MA_ASSERT(pDevice != NULL);
28407 
28408  MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it and then attempted to start the device. */
28409  if (g_maOpenSLInitCounter == 0) {
28410  return MA_INVALID_OPERATION;
28411  }
28412 
28413  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28414  resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_RECORDING);
28415  if (resultSL != SL_RESULT_SUCCESS) {
28416  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal capture device.", ma_result_from_OpenSL(resultSL));
28417  }
28418 
28419  periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
28420  for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
28421  resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pDevice->opensl.pBufferCapture + (periodSizeInBytes * iPeriod), periodSizeInBytes);
28422  if (resultSL != SL_RESULT_SUCCESS) {
28423  MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED);
28424  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for capture device.", ma_result_from_OpenSL(resultSL));
28425  }
28426  }
28427  }
28428 
28429  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28430  resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_PLAYING);
28431  if (resultSL != SL_RESULT_SUCCESS) {
28432  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal playback device.", ma_result_from_OpenSL(resultSL));
28433  }
28434 
28435  /* In playback mode (no duplex) we need to load some initial buffers. In duplex mode we need to enqueu silent buffers. */
28436  if (pDevice->type == ma_device_type_duplex) {
28437  MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
28438  } else {
28439  ma_device__read_frames_from_client(pDevice, pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods, pDevice->opensl.pBufferPlayback);
28440  }
28441 
28443  for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) {
28444  resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pDevice->opensl.pBufferPlayback + (periodSizeInBytes * iPeriod), periodSizeInBytes);
28445  if (resultSL != SL_RESULT_SUCCESS) {
28446  MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED);
28447  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for playback device.", ma_result_from_OpenSL(resultSL));
28448  }
28449  }
28450  }
28451 
28452  return MA_SUCCESS;
28453 }
28454 
28455 static ma_result ma_device_drain__opensl(ma_device* pDevice, ma_device_type deviceType)
28456 {
28457  SLAndroidSimpleBufferQueueItf pBufferQueue;
28458 
28459  MA_ASSERT(deviceType == ma_device_type_capture || deviceType == ma_device_type_playback);
28460 
28461  if (pDevice->type == ma_device_type_capture) {
28462  pBufferQueue = (SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture;
28463  pDevice->opensl.isDrainingCapture = MA_TRUE;
28464  } else {
28465  pBufferQueue = (SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback;
28466  pDevice->opensl.isDrainingPlayback = MA_TRUE;
28467  }
28468 
28469  for (;;) {
28470  SLAndroidSimpleBufferQueueState state;
28471 
28472  MA_OPENSL_BUFFERQUEUE(pBufferQueue)->GetState(pBufferQueue, &state);
28473  if (state.count == 0) {
28474  break;
28475  }
28476 
28477  ma_sleep(10);
28478  }
28479 
28480  if (pDevice->type == ma_device_type_capture) {
28481  pDevice->opensl.isDrainingCapture = MA_FALSE;
28482  } else {
28483  pDevice->opensl.isDrainingPlayback = MA_FALSE;
28484  }
28485 
28486  return MA_SUCCESS;
28487 }
28488 
28489 static ma_result ma_device_stop__opensl(ma_device* pDevice)
28490 {
28491  SLresult resultSL;
28492  ma_stop_proc onStop;
28493 
28494  MA_ASSERT(pDevice != NULL);
28495 
28496  MA_ASSERT(g_maOpenSLInitCounter > 0); /* <-- If you trigger this it means you've either not initialized the context, or you've uninitialized it before stopping/uninitializing the device. */
28497  if (g_maOpenSLInitCounter == 0) {
28498  return MA_INVALID_OPERATION;
28499  }
28500 
28501  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28502  ma_device_drain__opensl(pDevice, ma_device_type_capture);
28503 
28504  resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED);
28505  if (resultSL != SL_RESULT_SUCCESS) {
28506  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal capture device.", ma_result_from_OpenSL(resultSL));
28507  }
28508 
28509  MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture);
28510  }
28511 
28512  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28513  ma_device_drain__opensl(pDevice, ma_device_type_playback);
28514 
28515  resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED);
28516  if (resultSL != SL_RESULT_SUCCESS) {
28517  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal playback device.", ma_result_from_OpenSL(resultSL));
28518  }
28519 
28520  MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback);
28521  }
28522 
28523  /* Make sure the client is aware that the device has stopped. There may be an OpenSL|ES callback for this, but I haven't found it. */
28524  onStop = pDevice->onStop;
28525  if (onStop) {
28526  onStop(pDevice);
28527  }
28528 
28529  return MA_SUCCESS;
28530 }
28531 
28532 
28533 static ma_result ma_context_uninit__opensl(ma_context* pContext)
28534 {
28535  MA_ASSERT(pContext != NULL);
28536  MA_ASSERT(pContext->backend == ma_backend_opensl);
28537  (void)pContext;
28538 
28539  /* Uninit global data. */
28540  if (g_maOpenSLInitCounter > 0) {
28541  if (ma_atomic_decrement_32(&g_maOpenSLInitCounter) == 0) {
28542  (*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL);
28543  }
28544  }
28545 
28546  return MA_SUCCESS;
28547 }
28548 
28549 static ma_result ma_context_init__opensl(const ma_context_config* pConfig, ma_context* pContext)
28550 {
28551  MA_ASSERT(pContext != NULL);
28552 
28553  (void)pConfig;
28554 
28555  /* Initialize global data first if applicable. */
28556  if (ma_atomic_increment_32(&g_maOpenSLInitCounter) == 1) {
28557  SLresult resultSL = slCreateEngine(&g_maEngineObjectSL, 0, NULL, 0, NULL, NULL);
28558  if (resultSL != SL_RESULT_SUCCESS) {
28559  ma_atomic_decrement_32(&g_maOpenSLInitCounter);
28560  return ma_result_from_OpenSL(resultSL);
28561  }
28562 
28563  (*g_maEngineObjectSL)->Realize(g_maEngineObjectSL, SL_BOOLEAN_FALSE);
28564 
28565  resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, SL_IID_ENGINE, &g_maEngineSL);
28566  if (resultSL != SL_RESULT_SUCCESS) {
28567  (*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL);
28568  ma_atomic_decrement_32(&g_maOpenSLInitCounter);
28569  return ma_result_from_OpenSL(resultSL);
28570  }
28571  }
28572 
28573  pContext->isBackendAsynchronous = MA_TRUE;
28574 
28575  pContext->onUninit = ma_context_uninit__opensl;
28576  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__opensl;
28577  pContext->onEnumDevices = ma_context_enumerate_devices__opensl;
28578  pContext->onGetDeviceInfo = ma_context_get_device_info__opensl;
28579  pContext->onDeviceInit = ma_device_init__opensl;
28580  pContext->onDeviceUninit = ma_device_uninit__opensl;
28581  pContext->onDeviceStart = ma_device_start__opensl;
28582  pContext->onDeviceStop = ma_device_stop__opensl;
28583 
28584  return MA_SUCCESS;
28585 }
28586 #endif /* OpenSL|ES */
28587 
28588 
28589 /******************************************************************************
28590 
28591 Web Audio Backend
28592 
28593 ******************************************************************************/
28594 #ifdef MA_HAS_WEBAUDIO
28595 #include <emscripten/emscripten.h>
28596 
28597 static ma_bool32 ma_is_capture_supported__webaudio()
28598 {
28599  return EM_ASM_INT({
28600  return (navigator.mediaDevices !== undefined && navigator.mediaDevices.getUserMedia !== undefined);
28601  }, 0) != 0; /* Must pass in a dummy argument for C99 compatibility. */
28602 }
28603 
28604 #ifdef __cplusplus
28605 extern "C" {
28606 #endif
28607 void EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_capture__webaudio(ma_device* pDevice, int frameCount, float* pFrames)
28608 {
28609  if (pDevice->type == ma_device_type_duplex) {
28610  ma_device__handle_duplex_callback_capture(pDevice, (ma_uint32)frameCount, pFrames, &pDevice->webaudio.duplexRB);
28611  } else {
28612  ma_device__send_frames_to_client(pDevice, (ma_uint32)frameCount, pFrames); /* Send directly to the client. */
28613  }
28614 }
28615 
28616 void EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_playback__webaudio(ma_device* pDevice, int frameCount, float* pFrames)
28617 {
28618  if (pDevice->type == ma_device_type_duplex) {
28619  ma_device__handle_duplex_callback_playback(pDevice, (ma_uint32)frameCount, pFrames, &pDevice->webaudio.duplexRB);
28620  } else {
28621  ma_device__read_frames_from_client(pDevice, (ma_uint32)frameCount, pFrames); /* Read directly from the device. */
28622  }
28623 }
28624 #ifdef __cplusplus
28625 }
28626 #endif
28627 
28628 static ma_bool32 ma_context_is_device_id_equal__webaudio(ma_context* pContext, const ma_device_id* pID0, const ma_device_id* pID1)
28629 {
28630  MA_ASSERT(pContext != NULL);
28631  MA_ASSERT(pID0 != NULL);
28632  MA_ASSERT(pID1 != NULL);
28633  (void)pContext;
28634 
28635  return ma_strcmp(pID0->webaudio, pID1->webaudio) == 0;
28636 }
28637 
28638 static ma_result ma_context_enumerate_devices__webaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
28639 {
28640  ma_bool32 cbResult = MA_TRUE;
28641 
28642  MA_ASSERT(pContext != NULL);
28643  MA_ASSERT(callback != NULL);
28644 
28645  /* Only supporting default devices for now. */
28646 
28647  /* Playback. */
28648  if (cbResult) {
28649  ma_device_info deviceInfo;
28650  MA_ZERO_OBJECT(&deviceInfo);
28651  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
28652  cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
28653  }
28654 
28655  /* Capture. */
28656  if (cbResult) {
28657  if (ma_is_capture_supported__webaudio()) {
28658  ma_device_info deviceInfo;
28659  MA_ZERO_OBJECT(&deviceInfo);
28660  ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
28661  cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
28662  }
28663  }
28664 
28665  return MA_SUCCESS;
28666 }
28667 
28668 static ma_result ma_context_get_device_info__webaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
28669 {
28670  MA_ASSERT(pContext != NULL);
28671 
28672  /* No exclusive mode with Web Audio. */
28673  if (shareMode == ma_share_mode_exclusive) {
28675  }
28676 
28677  if (deviceType == ma_device_type_capture && !ma_is_capture_supported__webaudio()) {
28678  return MA_NO_DEVICE;
28679  }
28680 
28681 
28682  MA_ZERO_MEMORY(pDeviceInfo->id.webaudio, sizeof(pDeviceInfo->id.webaudio));
28683 
28684  /* Only supporting default devices for now. */
28685  (void)pDeviceID;
28686  if (deviceType == ma_device_type_playback) {
28687  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
28688  } else {
28689  ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
28690  }
28691 
28692  /* Web Audio can support any number of channels and sample rates. It only supports f32 formats, however. */
28693  pDeviceInfo->minChannels = 1;
28694  pDeviceInfo->maxChannels = MA_MAX_CHANNELS;
28695  if (pDeviceInfo->maxChannels > 32) {
28696  pDeviceInfo->maxChannels = 32; /* Maximum output channel count is 32 for createScriptProcessor() (JavaScript). */
28697  }
28698 
28699  /* We can query the sample rate by just using a temporary audio context. */
28700  pDeviceInfo->minSampleRate = EM_ASM_INT({
28701  try {
28702  var temp = new (window.AudioContext || window.webkitAudioContext)();
28703  var sampleRate = temp.sampleRate;
28704  temp.close();
28705  return sampleRate;
28706  } catch(e) {
28707  return 0;
28708  }
28709  }, 0); /* Must pass in a dummy argument for C99 compatibility. */
28710  pDeviceInfo->maxSampleRate = pDeviceInfo->minSampleRate;
28711  if (pDeviceInfo->minSampleRate == 0) {
28712  return MA_NO_DEVICE;
28713  }
28714 
28715  /* Web Audio only supports f32. */
28716  pDeviceInfo->formatCount = 1;
28717  pDeviceInfo->formats[0] = ma_format_f32;
28718 
28719  return MA_SUCCESS;
28720 }
28721 
28722 
28723 static void ma_device_uninit_by_index__webaudio(ma_device* pDevice, ma_device_type deviceType, int deviceIndex)
28724 {
28725  MA_ASSERT(pDevice != NULL);
28726 
28727  EM_ASM({
28728  var device = miniaudio.get_device_by_index($0);
28729 
28730  /* Make sure all nodes are disconnected and marked for collection. */
28731  if (device.scriptNode !== undefined) {
28732  device.scriptNode.onaudioprocess = function(e) {}; /* We want to reset the callback to ensure it doesn't get called after AudioContext.close() has returned. Shouldn't happen since we're disconnecting, but just to be safe... */
28733  device.scriptNode.disconnect();
28734  device.scriptNode = undefined;
28735  }
28736  if (device.streamNode !== undefined) {
28737  device.streamNode.disconnect();
28738  device.streamNode = undefined;
28739  }
28740 
28741  /*
28742  Stop the device. I think there is a chance the callback could get fired after calling this, hence why we want
28743  to clear the callback before closing.
28744  */
28745  device.webaudio.close();
28746  device.webaudio = undefined;
28747 
28748  /* Can't forget to free the intermediary buffer. This is the buffer that's shared between JavaScript and C. */
28749  if (device.intermediaryBuffer !== undefined) {
28750  Module._free(device.intermediaryBuffer);
28751  device.intermediaryBuffer = undefined;
28752  device.intermediaryBufferView = undefined;
28753  device.intermediaryBufferSizeInBytes = undefined;
28754  }
28755 
28756  /* Make sure the device is untracked so the slot can be reused later. */
28757  miniaudio.untrack_device_by_index($0);
28758  }, deviceIndex, deviceType);
28759 }
28760 
28761 static void ma_device_uninit__webaudio(ma_device* pDevice)
28762 {
28763  MA_ASSERT(pDevice != NULL);
28764 
28765  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28766  ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture);
28767  }
28768 
28769  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28770  ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_playback, pDevice->webaudio.indexPlayback);
28771  }
28772 
28773  if (pDevice->type == ma_device_type_duplex) {
28774  ma_pcm_rb_uninit(&pDevice->webaudio.duplexRB);
28775  }
28776 }
28777 
28778 static ma_result ma_device_init_by_type__webaudio(ma_context* pContext, const ma_device_config* pConfig, ma_device_type deviceType, ma_device* pDevice)
28779 {
28780  int deviceIndex;
28781  ma_uint32 internalPeriodSizeInFrames;
28782 
28783  MA_ASSERT(pContext != NULL);
28784  MA_ASSERT(pConfig != NULL);
28785  MA_ASSERT(deviceType != ma_device_type_duplex);
28786  MA_ASSERT(pDevice != NULL);
28787 
28788  if (deviceType == ma_device_type_capture && !ma_is_capture_supported__webaudio()) {
28789  return MA_NO_DEVICE;
28790  }
28791 
28792  /* Try calculating an appropriate buffer size. */
28793  internalPeriodSizeInFrames = pConfig->periodSizeInFrames;
28794  if (internalPeriodSizeInFrames == 0) {
28795  internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pConfig->periodSizeInMilliseconds, pConfig->sampleRate);
28796  }
28797 
28798  /* The size of the buffer must be a power of 2 and between 256 and 16384. */
28799  if (internalPeriodSizeInFrames < 256) {
28800  internalPeriodSizeInFrames = 256;
28801  } else if (internalPeriodSizeInFrames > 16384) {
28802  internalPeriodSizeInFrames = 16384;
28803  } else {
28804  internalPeriodSizeInFrames = ma_next_power_of_2(internalPeriodSizeInFrames);
28805  }
28806 
28807  /* We create the device on the JavaScript side and reference it using an index. We use this to make it possible to reference the device between JavaScript and C. */
28808  deviceIndex = EM_ASM_INT({
28809  var channels = $0;
28810  var sampleRate = $1;
28811  var bufferSize = $2; /* In PCM frames. */
28812  var isCapture = $3;
28813  var pDevice = $4;
28814 
28815  if (typeof(miniaudio) === 'undefined') {
28816  return -1; /* Context not initialized. */
28817  }
28818 
28819  var device = {};
28820 
28821  /* The AudioContext must be created in a suspended state. */
28822  device.webaudio = new (window.AudioContext || window.webkitAudioContext)({sampleRate:sampleRate});
28823  device.webaudio.suspend();
28824 
28825  /*
28826  We need an intermediary buffer which we use for JavaScript and C interop. This buffer stores interleaved f32 PCM data. Because it's passed between
28827  JavaScript and C it needs to be allocated and freed using Module._malloc() and Module._free().
28828  */
28829  device.intermediaryBufferSizeInBytes = channels * bufferSize * 4;
28830  device.intermediaryBuffer = Module._malloc(device.intermediaryBufferSizeInBytes);
28831  device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes);
28832 
28833  /*
28834  Both playback and capture devices use a ScriptProcessorNode for performing per-sample operations.
28835 
28836  ScriptProcessorNode is actually deprecated so this is likely to be temporary. The way this works for playback is very simple. You just set a callback
28837  that's periodically fired, just like a normal audio callback function. But apparently this design is "flawed" and is now deprecated in favour of
28838  something called AudioWorklets which _forces_ you to load a _separate_ .js file at run time... nice... Hopefully ScriptProcessorNode will continue to
28839  work for years to come, but this may need to change to use AudioSourceBufferNode instead, which I think is what Emscripten uses for it's built-in SDL
28840  implementation. I'll be avoiding that insane AudioWorklet API like the plague...
28841 
28842  For capture it is a bit unintuitive. We use the ScriptProccessorNode _only_ to get the raw PCM data. It is connected to an AudioContext just like the
28843  playback case, however we just output silence to the AudioContext instead of passing any real data. It would make more sense to me to use the
28844  MediaRecorder API, but unfortunately you need to specify a MIME time (Opus, Vorbis, etc.) for the binary blob that's returned to the client, but I've
28845  been unable to figure out how to get this as raw PCM. The closest I can think is to use the MIME type for WAV files and just parse it, but I don't know
28846  how well this would work. Although ScriptProccessorNode is deprecated, in practice it seems to have pretty good browser support so I'm leaving it like
28847  this for now. If anyone knows how I could get raw PCM data using the MediaRecorder API please let me know!
28848  */
28849  device.scriptNode = device.webaudio.createScriptProcessor(bufferSize, channels, channels);
28850 
28851  if (isCapture) {
28852  device.scriptNode.onaudioprocess = function(e) {
28853  if (device.intermediaryBuffer === undefined) {
28854  return; /* This means the device has been uninitialized. */
28855  }
28856 
28857  /* Make sure silence it output to the AudioContext destination. Not doing this will cause sound to come out of the speakers! */
28858  for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) {
28859  e.outputBuffer.getChannelData(iChannel).fill(0.0);
28860  }
28861 
28862  /* There are some situations where we may want to send silence to the client. */
28863  var sendSilence = false;
28864  if (device.streamNode === undefined) {
28865  sendSilence = true;
28866  }
28867 
28868  /* Sanity check. This will never happen, right? */
28869  if (e.inputBuffer.numberOfChannels != channels) {
28870  console.log("Capture: Channel count mismatch. " + e.inputBufer.numberOfChannels + " != " + channels + ". Sending silence.");
28871  sendSilence = true;
28872  }
28873 
28874  /* This looped design guards against the situation where e.inputBuffer is a different size to the original buffer size. Should never happen in practice. */
28875  var totalFramesProcessed = 0;
28876  while (totalFramesProcessed < e.inputBuffer.length) {
28877  var framesRemaining = e.inputBuffer.length - totalFramesProcessed;
28878  var framesToProcess = framesRemaining;
28879  if (framesToProcess > (device.intermediaryBufferSizeInBytes/channels/4)) {
28880  framesToProcess = (device.intermediaryBufferSizeInBytes/channels/4);
28881  }
28882 
28883  /* We need to do the reverse of the playback case. We need to interleave the input data and copy it into the intermediary buffer. Then we send it to the client. */
28884  if (sendSilence) {
28885  device.intermediaryBufferView.fill(0.0);
28886  } else {
28887  for (var iFrame = 0; iFrame < framesToProcess; ++iFrame) {
28888  for (var iChannel = 0; iChannel < e.inputBuffer.numberOfChannels; ++iChannel) {
28889  device.intermediaryBufferView[iFrame*channels + iChannel] = e.inputBuffer.getChannelData(iChannel)[totalFramesProcessed + iFrame];
28890  }
28891  }
28892  }
28893 
28894  /* Send data to the client from our intermediary buffer. */
28895  ccall("ma_device_process_pcm_frames_capture__webaudio", "undefined", ["number", "number", "number"], [pDevice, framesToProcess, device.intermediaryBuffer]);
28896 
28897  totalFramesProcessed += framesToProcess;
28898  }
28899  };
28900 
28901  navigator.mediaDevices.getUserMedia({audio:true, video:false})
28902  .then(function(stream) {
28903  device.streamNode = device.webaudio.createMediaStreamSource(stream);
28904  device.streamNode.connect(device.scriptNode);
28905  device.scriptNode.connect(device.webaudio.destination);
28906  })
28907  .catch(function(error) {
28908  /* I think this should output silence... */
28909  device.scriptNode.connect(device.webaudio.destination);
28910  });
28911  } else {
28912  device.scriptNode.onaudioprocess = function(e) {
28913  if (device.intermediaryBuffer === undefined) {
28914  return; /* This means the device has been uninitialized. */
28915  }
28916 
28917  var outputSilence = false;
28918 
28919  /* Sanity check. This will never happen, right? */
28920  if (e.outputBuffer.numberOfChannels != channels) {
28921  console.log("Playback: Channel count mismatch. " + e.outputBufer.numberOfChannels + " != " + channels + ". Outputting silence.");
28922  outputSilence = true;
28923  return;
28924  }
28925 
28926  /* This looped design guards against the situation where e.outputBuffer is a different size to the original buffer size. Should never happen in practice. */
28927  var totalFramesProcessed = 0;
28928  while (totalFramesProcessed < e.outputBuffer.length) {
28929  var framesRemaining = e.outputBuffer.length - totalFramesProcessed;
28930  var framesToProcess = framesRemaining;
28931  if (framesToProcess > (device.intermediaryBufferSizeInBytes/channels/4)) {
28932  framesToProcess = (device.intermediaryBufferSizeInBytes/channels/4);
28933  }
28934 
28935  /* Read data from the client into our intermediary buffer. */
28936  ccall("ma_device_process_pcm_frames_playback__webaudio", "undefined", ["number", "number", "number"], [pDevice, framesToProcess, device.intermediaryBuffer]);
28937 
28938  /* At this point we'll have data in our intermediary buffer which we now need to deinterleave and copy over to the output buffers. */
28939  if (outputSilence) {
28940  for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) {
28941  e.outputBuffer.getChannelData(iChannel).fill(0.0);
28942  }
28943  } else {
28944  for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) {
28945  for (var iFrame = 0; iFrame < framesToProcess; ++iFrame) {
28946  e.outputBuffer.getChannelData(iChannel)[totalFramesProcessed + iFrame] = device.intermediaryBufferView[iFrame*channels + iChannel];
28947  }
28948  }
28949  }
28950 
28951  totalFramesProcessed += framesToProcess;
28952  }
28953  };
28954 
28955  device.scriptNode.connect(device.webaudio.destination);
28956  }
28957 
28958  return miniaudio.track_device(device);
28959  }, (deviceType == ma_device_type_capture) ? pConfig->capture.channels : pConfig->playback.channels, pConfig->sampleRate, internalPeriodSizeInFrames, deviceType == ma_device_type_capture, pDevice);
28960 
28961  if (deviceIndex < 0) {
28963  }
28964 
28965  if (deviceType == ma_device_type_capture) {
28966  pDevice->webaudio.indexCapture = deviceIndex;
28967  pDevice->capture.internalFormat = ma_format_f32;
28968  pDevice->capture.internalChannels = pConfig->capture.channels;
28969  ma_get_standard_channel_map(ma_standard_channel_map_webaudio, pDevice->capture.internalChannels, pDevice->capture.internalChannelMap);
28970  pDevice->capture.internalSampleRate = EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex);
28971  pDevice->capture.internalPeriodSizeInFrames = internalPeriodSizeInFrames;
28972  pDevice->capture.internalPeriods = 1;
28973  } else {
28974  pDevice->webaudio.indexPlayback = deviceIndex;
28975  pDevice->playback.internalFormat = ma_format_f32;
28976  pDevice->playback.internalChannels = pConfig->playback.channels;
28977  ma_get_standard_channel_map(ma_standard_channel_map_webaudio, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap);
28978  pDevice->playback.internalSampleRate = EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex);
28979  pDevice->playback.internalPeriodSizeInFrames = internalPeriodSizeInFrames;
28980  pDevice->playback.internalPeriods = 1;
28981  }
28982 
28983  return MA_SUCCESS;
28984 }
28985 
28986 static ma_result ma_device_init__webaudio(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
28987 {
28988  ma_result result;
28989 
28990  if (pConfig->deviceType == ma_device_type_loopback) {
28992  }
28993 
28994  /* No exclusive mode with Web Audio. */
28998  }
28999 
29000  if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
29001  result = ma_device_init_by_type__webaudio(pContext, pConfig, ma_device_type_capture, pDevice);
29002  if (result != MA_SUCCESS) {
29003  return result;
29004  }
29005  }
29006 
29007  if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
29008  result = ma_device_init_by_type__webaudio(pContext, pConfig, ma_device_type_playback, pDevice);
29009  if (result != MA_SUCCESS) {
29010  if (pConfig->deviceType == ma_device_type_duplex) {
29011  ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture);
29012  }
29013  return result;
29014  }
29015  }
29016 
29017  /*
29018  We need a ring buffer for moving data from the capture device to the playback device. The capture callback is the producer
29019  and the playback callback is the consumer. The buffer needs to be large enough to hold internalPeriodSizeInFrames based on
29020  the external sample rate.
29021  */
29022  if (pConfig->deviceType == ma_device_type_duplex) {
29024  result = ma_pcm_rb_init(pDevice->capture.format, pDevice->capture.channels, rbSizeInFrames, NULL, &pDevice->pContext->allocationCallbacks, &pDevice->webaudio.duplexRB);
29025  if (result != MA_SUCCESS) {
29026  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
29027  ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture);
29028  }
29029  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
29030  ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_playback, pDevice->webaudio.indexPlayback);
29031  }
29032  return result;
29033  }
29034 
29035  /* We need a period to act as a buffer for cases where the playback and capture device's end up desyncing. */
29036  {
29037  ma_uint32 marginSizeInFrames = rbSizeInFrames / 3; /* <-- Dividing by 3 because internalPeriods is always set to 1 for WebAudio. */
29038  void* pMarginData;
29039  ma_pcm_rb_acquire_write(&pDevice->webaudio.duplexRB, &marginSizeInFrames, &pMarginData);
29040  {
29041  MA_ZERO_MEMORY(pMarginData, marginSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
29042  }
29043  ma_pcm_rb_commit_write(&pDevice->webaudio.duplexRB, marginSizeInFrames, pMarginData);
29044  }
29045  }
29046 
29047  return MA_SUCCESS;
29048 }
29049 
29050 static ma_result ma_device_start__webaudio(ma_device* pDevice)
29051 {
29052  MA_ASSERT(pDevice != NULL);
29053 
29054  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
29055  EM_ASM({
29056  miniaudio.get_device_by_index($0).webaudio.resume();
29057  }, pDevice->webaudio.indexCapture);
29058  }
29059 
29060  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
29061  EM_ASM({
29062  miniaudio.get_device_by_index($0).webaudio.resume();
29063  }, pDevice->webaudio.indexPlayback);
29064  }
29065 
29066  return MA_SUCCESS;
29067 }
29068 
29069 static ma_result ma_device_stop__webaudio(ma_device* pDevice)
29070 {
29071  MA_ASSERT(pDevice != NULL);
29072 
29073  /*
29074  From the WebAudio API documentation for AudioContext.suspend():
29075 
29076  Suspends the progression of AudioContext's currentTime, allows any current context processing blocks that are already processed to be played to the
29077  destination, and then allows the system to release its claim on audio hardware.
29078 
29079  I read this to mean that "any current context processing blocks" are processed by suspend() - i.e. They they are drained. We therefore shouldn't need to
29080  do any kind of explicit draining.
29081  */
29082 
29083  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
29084  EM_ASM({
29085  miniaudio.get_device_by_index($0).webaudio.suspend();
29086  }, pDevice->webaudio.indexCapture);
29087  }
29088 
29089  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
29090  EM_ASM({
29091  miniaudio.get_device_by_index($0).webaudio.suspend();
29092  }, pDevice->webaudio.indexPlayback);
29093  }
29094 
29095  ma_stop_proc onStop = pDevice->onStop;
29096  if (onStop) {
29097  onStop(pDevice);
29098  }
29099 
29100  return MA_SUCCESS;
29101 }
29102 
29103 static ma_result ma_context_uninit__webaudio(ma_context* pContext)
29104 {
29105  MA_ASSERT(pContext != NULL);
29106  MA_ASSERT(pContext->backend == ma_backend_webaudio);
29107 
29108  /* Nothing needs to be done here. */
29109  (void)pContext;
29110 
29111  return MA_SUCCESS;
29112 }
29113 
29114 static ma_result ma_context_init__webaudio(const ma_context_config* pConfig, ma_context* pContext)
29115 {
29116  int resultFromJS;
29117 
29118  MA_ASSERT(pContext != NULL);
29119 
29120  /* Here is where our global JavaScript object is initialized. */
29121  resultFromJS = EM_ASM_INT({
29122  if ((window.AudioContext || window.webkitAudioContext) === undefined) {
29123  return 0; /* Web Audio not supported. */
29124  }
29125 
29126  if (typeof(miniaudio) === 'undefined') {
29127  miniaudio = {};
29128  miniaudio.devices = []; /* Device cache for mapping devices to indexes for JavaScript/C interop. */
29129 
29130  miniaudio.track_device = function(device) {
29131  /* Try inserting into a free slot first. */
29132  for (var iDevice = 0; iDevice < miniaudio.devices.length; ++iDevice) {
29133  if (miniaudio.devices[iDevice] == null) {
29134  miniaudio.devices[iDevice] = device;
29135  return iDevice;
29136  }
29137  }
29138 
29139  /* Getting here means there is no empty slots in the array so we just push to the end. */
29140  miniaudio.devices.push(device);
29141  return miniaudio.devices.length - 1;
29142  };
29143 
29144  miniaudio.untrack_device_by_index = function(deviceIndex) {
29145  /* We just set the device's slot to null. The slot will get reused in the next call to ma_track_device. */
29146  miniaudio.devices[deviceIndex] = null;
29147 
29148  /* Trim the array if possible. */
29149  while (miniaudio.devices.length > 0) {
29150  if (miniaudio.devices[miniaudio.devices.length-1] == null) {
29151  miniaudio.devices.pop();
29152  } else {
29153  break;
29154  }
29155  }
29156  };
29157 
29158  miniaudio.untrack_device = function(device) {
29159  for (var iDevice = 0; iDevice < miniaudio.devices.length; ++iDevice) {
29160  if (miniaudio.devices[iDevice] == device) {
29161  return miniaudio.untrack_device_by_index(iDevice);
29162  }
29163  }
29164  };
29165 
29166  miniaudio.get_device_by_index = function(deviceIndex) {
29167  return miniaudio.devices[deviceIndex];
29168  };
29169  }
29170 
29171  return 1;
29172  }, 0); /* Must pass in a dummy argument for C99 compatibility. */
29173 
29174  if (resultFromJS != 1) {
29176  }
29177 
29178 
29179  pContext->isBackendAsynchronous = MA_TRUE;
29180 
29181  pContext->onUninit = ma_context_uninit__webaudio;
29182  pContext->onDeviceIDEqual = ma_context_is_device_id_equal__webaudio;
29183  pContext->onEnumDevices = ma_context_enumerate_devices__webaudio;
29184  pContext->onGetDeviceInfo = ma_context_get_device_info__webaudio;
29185  pContext->onDeviceInit = ma_device_init__webaudio;
29186  pContext->onDeviceUninit = ma_device_uninit__webaudio;
29187  pContext->onDeviceStart = ma_device_start__webaudio;
29188  pContext->onDeviceStop = ma_device_stop__webaudio;
29189 
29190  (void)pConfig; /* Unused. */
29191  return MA_SUCCESS;
29192 }
29193 #endif /* Web Audio */
29194 
29195 
29196 
29197 static ma_bool32 ma__is_channel_map_valid(const ma_channel* channelMap, ma_uint32 channels)
29198 {
29199  /* A blank channel map should be allowed, in which case it should use an appropriate default which will depend on context. */
29200  if (channelMap[0] != MA_CHANNEL_NONE) {
29201  ma_uint32 iChannel;
29202 
29203  if (channels == 0) {
29204  return MA_FALSE; /* No channels. */
29205  }
29206 
29207  /* A channel cannot be present in the channel map more than once. */
29208  for (iChannel = 0; iChannel < channels; ++iChannel) {
29209  ma_uint32 jChannel;
29210  for (jChannel = iChannel + 1; jChannel < channels; ++jChannel) {
29211  if (channelMap[iChannel] == channelMap[jChannel]) {
29212  return MA_FALSE;
29213  }
29214  }
29215  }
29216  }
29217 
29218  return MA_TRUE;
29219 }
29220 
29221 
29222 static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType)
29223 {
29224  ma_result result;
29225 
29226  MA_ASSERT(pDevice != NULL);
29227 
29228  if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
29229  if (pDevice->capture.usingDefaultFormat) {
29230  pDevice->capture.format = pDevice->capture.internalFormat;
29231  }
29232  if (pDevice->capture.usingDefaultChannels) {
29233  pDevice->capture.channels = pDevice->capture.internalChannels;
29234  }
29235  if (pDevice->capture.usingDefaultChannelMap) {
29236  if (pDevice->capture.internalChannels == pDevice->capture.channels) {
29238  } else {
29240  }
29241  }
29242  }
29243 
29244  if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
29245  if (pDevice->playback.usingDefaultFormat) {
29246  pDevice->playback.format = pDevice->playback.internalFormat;
29247  }
29248  if (pDevice->playback.usingDefaultChannels) {
29249  pDevice->playback.channels = pDevice->playback.internalChannels;
29250  }
29251  if (pDevice->playback.usingDefaultChannelMap) {
29252  if (pDevice->playback.internalChannels == pDevice->playback.channels) {
29254  } else {
29256  }
29257  }
29258  }
29259 
29260  if (pDevice->usingDefaultSampleRate) {
29261  if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
29262  pDevice->sampleRate = pDevice->capture.internalSampleRate;
29263  } else {
29264  pDevice->sampleRate = pDevice->playback.internalSampleRate;
29265  }
29266  }
29267 
29268  /* PCM converters. */
29269  if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
29270  /* Converting from internal device format to client format. */
29272  converterConfig.formatIn = pDevice->capture.internalFormat;
29273  converterConfig.channelsIn = pDevice->capture.internalChannels;
29274  converterConfig.sampleRateIn = pDevice->capture.internalSampleRate;
29276  converterConfig.formatOut = pDevice->capture.format;
29277  converterConfig.channelsOut = pDevice->capture.channels;
29278  converterConfig.sampleRateOut = pDevice->sampleRate;
29279  ma_channel_map_copy(converterConfig.channelMapOut, pDevice->capture.channelMap, pDevice->capture.channels);
29280  converterConfig.resampling.allowDynamicSampleRate = MA_FALSE;
29281  converterConfig.resampling.algorithm = pDevice->resampling.algorithm;
29282  converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder;
29283  converterConfig.resampling.speex.quality = pDevice->resampling.speex.quality;
29284 
29285  result = ma_data_converter_init(&converterConfig, &pDevice->capture.converter);
29286  if (result != MA_SUCCESS) {
29287  return result;
29288  }
29289  }
29290 
29291  if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
29292  /* Converting from client format to device format. */
29294  converterConfig.formatIn = pDevice->playback.format;
29295  converterConfig.channelsIn = pDevice->playback.channels;
29296  converterConfig.sampleRateIn = pDevice->sampleRate;
29297  ma_channel_map_copy(converterConfig.channelMapIn, pDevice->playback.channelMap, pDevice->playback.channels);
29298  converterConfig.formatOut = pDevice->playback.internalFormat;
29299  converterConfig.channelsOut = pDevice->playback.internalChannels;
29300  converterConfig.sampleRateOut = pDevice->playback.internalSampleRate;
29302  converterConfig.resampling.allowDynamicSampleRate = MA_FALSE;
29303  converterConfig.resampling.algorithm = pDevice->resampling.algorithm;
29304  converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder;
29305  converterConfig.resampling.speex.quality = pDevice->resampling.speex.quality;
29306 
29307  result = ma_data_converter_init(&converterConfig, &pDevice->playback.converter);
29308  if (result != MA_SUCCESS) {
29309  return result;
29310  }
29311  }
29312 
29313  return MA_SUCCESS;
29314 }
29315 
29316 
29318 {
29319  ma_device* pDevice = (ma_device*)pData;
29320  MA_ASSERT(pDevice != NULL);
29321 
29322 #ifdef MA_WIN32
29323  ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE);
29324 #endif
29325 
29326  /*
29327  When the device is being initialized it's initial state is set to MA_STATE_UNINITIALIZED. Before returning from
29328  ma_device_init(), the state needs to be set to something valid. In miniaudio the device's default state immediately
29329  after initialization is stopped, so therefore we need to mark the device as such. miniaudio will wait on the worker
29330  thread to signal an event to know when the worker thread is ready for action.
29331  */
29333  ma_event_signal(&pDevice->stopEvent);
29334 
29335  for (;;) { /* <-- This loop just keeps the thread alive. The main audio loop is inside. */
29336  ma_stop_proc onStop;
29337 
29338  /* We wait on an event to know when something has requested that the device be started and the main loop entered. */
29339  ma_event_wait(&pDevice->wakeupEvent);
29340 
29341  /* Default result code. */
29342  pDevice->workResult = MA_SUCCESS;
29343 
29344  /* If the reason for the wake up is that we are terminating, just break from the loop. */
29345  if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED) {
29346  break;
29347  }
29348 
29349  /*
29350  Getting to this point means the device is wanting to get started. The function that has requested that the device
29351  be started will be waiting on an event (pDevice->startEvent) which means we need to make sure we signal the event
29352  in both the success and error case. It's important that the state of the device is set _before_ signaling the event.
29353  */
29354  MA_ASSERT(ma_device__get_state(pDevice) == MA_STATE_STARTING);
29355 
29356  /* Make sure the state is set appropriately. */
29358  ma_event_signal(&pDevice->startEvent);
29359 
29360  if (pDevice->pContext->onDeviceMainLoop != NULL) {
29361  pDevice->pContext->onDeviceMainLoop(pDevice);
29362  } else {
29363  ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "No main loop implementation.", MA_API_NOT_FOUND);
29364  }
29365 
29366  /*
29367  Getting here means we have broken from the main loop which happens the application has requested that device be stopped. Note that this
29368  may have actually already happened above if the device was lost and miniaudio has attempted to re-initialize the device. In this case we
29369  don't want to be doing this a second time.
29370  */
29371  if (ma_device__get_state(pDevice) != MA_STATE_UNINITIALIZED) {
29372  if (pDevice->pContext->onDeviceStop) {
29373  pDevice->pContext->onDeviceStop(pDevice);
29374  }
29375  }
29376 
29377  /* After the device has stopped, make sure an event is posted. */
29378  onStop = pDevice->onStop;
29379  if (onStop) {
29380  onStop(pDevice);
29381  }
29382 
29383  /*
29384  A function somewhere is waiting for the device to have stopped for real so we need to signal an event to allow it to continue. Note that
29385  it's possible that the device has been uninitialized which means we need to _not_ change the status to stopped. We cannot go from an
29386  uninitialized state to stopped state.
29387  */
29388  if (ma_device__get_state(pDevice) != MA_STATE_UNINITIALIZED) {
29390  ma_event_signal(&pDevice->stopEvent);
29391  }
29392  }
29393 
29394  /* Make sure we aren't continuously waiting on a stop event. */
29395  ma_event_signal(&pDevice->stopEvent); /* <-- Is this still needed? */
29396 
29397 #ifdef MA_WIN32
29398  ma_CoUninitialize(pDevice->pContext);
29399 #endif
29400 
29401  return (ma_thread_result)0;
29402 }
29403 
29404 
29405 /* Helper for determining whether or not the given device is initialized. */
29407 {
29408  if (pDevice == NULL) {
29409  return MA_FALSE;
29410  }
29411 
29412  return ma_device__get_state(pDevice) != MA_STATE_UNINITIALIZED;
29413 }
29414 
29415 
29416 #ifdef MA_WIN32
29417 static ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext)
29418 {
29419  ma_CoUninitialize(pContext);
29420  ma_dlclose(pContext, pContext->win32.hUser32DLL);
29421  ma_dlclose(pContext, pContext->win32.hOle32DLL);
29422  ma_dlclose(pContext, pContext->win32.hAdvapi32DLL);
29423 
29424  return MA_SUCCESS;
29425 }
29426 
29427 static ma_result ma_context_init_backend_apis__win32(ma_context* pContext)
29428 {
29429 #ifdef MA_WIN32_DESKTOP
29430  /* Ole32.dll */
29431  pContext->win32.hOle32DLL = ma_dlopen(pContext, "ole32.dll");
29432  if (pContext->win32.hOle32DLL == NULL) {
29434  }
29435 
29436  pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoInitializeEx");
29437  pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoUninitialize");
29438  pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoCreateInstance");
29439  pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoTaskMemFree");
29440  pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "PropVariantClear");
29441  pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "StringFromGUID2");
29442 
29443 
29444  /* User32.dll */
29445  pContext->win32.hUser32DLL = ma_dlopen(pContext, "user32.dll");
29446  if (pContext->win32.hUser32DLL == NULL) {
29448  }
29449 
29450  pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetForegroundWindow");
29451  pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetDesktopWindow");
29452 
29453 
29454  /* Advapi32.dll */
29455  pContext->win32.hAdvapi32DLL = ma_dlopen(pContext, "advapi32.dll");
29456  if (pContext->win32.hAdvapi32DLL == NULL) {
29458  }
29459 
29460  pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegOpenKeyExA");
29461  pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegCloseKey");
29462  pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegQueryValueExA");
29463 #endif
29464 
29465  ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE);
29466  return MA_SUCCESS;
29467 }
29468 #else
29470 {
29471 #if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
29472  ma_dlclose(pContext, pContext->posix.pthreadSO);
29473 #else
29474  (void)pContext;
29475 #endif
29476 
29477  return MA_SUCCESS;
29478 }
29479 
29481 {
29482  /* pthread */
29483 #if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
29484  const char* libpthreadFileNames[] = {
29485  "libpthread.so",
29486  "libpthread.so.0",
29487  "libpthread.dylib"
29488  };
29489  size_t i;
29490 
29491  for (i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) {
29492  pContext->posix.pthreadSO = ma_dlopen(pContext, libpthreadFileNames[i]);
29493  if (pContext->posix.pthreadSO != NULL) {
29494  break;
29495  }
29496  }
29497 
29498  if (pContext->posix.pthreadSO == NULL) {
29500  }
29501 
29502  pContext->posix.pthread_create = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_create");
29503  pContext->posix.pthread_join = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_join");
29504  pContext->posix.pthread_mutex_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_init");
29505  pContext->posix.pthread_mutex_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_destroy");
29506  pContext->posix.pthread_mutex_lock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_lock");
29507  pContext->posix.pthread_mutex_unlock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_unlock");
29508  pContext->posix.pthread_cond_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_init");
29509  pContext->posix.pthread_cond_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_destroy");
29510  pContext->posix.pthread_cond_wait = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_wait");
29511  pContext->posix.pthread_cond_signal = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_signal");
29512  pContext->posix.pthread_attr_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_init");
29513  pContext->posix.pthread_attr_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_destroy");
29514  pContext->posix.pthread_attr_setschedpolicy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedpolicy");
29515  pContext->posix.pthread_attr_getschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_getschedparam");
29516  pContext->posix.pthread_attr_setschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedparam");
29517 #else
29518  pContext->posix.pthread_create = (ma_proc)pthread_create;
29519  pContext->posix.pthread_join = (ma_proc)pthread_join;
29520  pContext->posix.pthread_mutex_init = (ma_proc)pthread_mutex_init;
29521  pContext->posix.pthread_mutex_destroy = (ma_proc)pthread_mutex_destroy;
29522  pContext->posix.pthread_mutex_lock = (ma_proc)pthread_mutex_lock;
29523  pContext->posix.pthread_mutex_unlock = (ma_proc)pthread_mutex_unlock;
29524  pContext->posix.pthread_cond_init = (ma_proc)pthread_cond_init;
29525  pContext->posix.pthread_cond_destroy = (ma_proc)pthread_cond_destroy;
29526  pContext->posix.pthread_cond_wait = (ma_proc)pthread_cond_wait;
29527  pContext->posix.pthread_cond_signal = (ma_proc)pthread_cond_signal;
29528  pContext->posix.pthread_attr_init = (ma_proc)pthread_attr_init;
29529  pContext->posix.pthread_attr_destroy = (ma_proc)pthread_attr_destroy;
29530 #if !defined(__EMSCRIPTEN__)
29531  pContext->posix.pthread_attr_setschedpolicy = (ma_proc)pthread_attr_setschedpolicy;
29532  pContext->posix.pthread_attr_getschedparam = (ma_proc)pthread_attr_getschedparam;
29533  pContext->posix.pthread_attr_setschedparam = (ma_proc)pthread_attr_setschedparam;
29534 #endif
29535 #endif
29536 
29537  return MA_SUCCESS;
29538 }
29539 #endif
29540 
29542 {
29543  ma_result result;
29544 #ifdef MA_WIN32
29545  result = ma_context_init_backend_apis__win32(pContext);
29546 #else
29547  result = ma_context_init_backend_apis__nix(pContext);
29548 #endif
29549 
29550  return result;
29551 }
29552 
29554 {
29555  ma_result result;
29556 #ifdef MA_WIN32
29557  result = ma_context_uninit_backend_apis__win32(pContext);
29558 #else
29559  result = ma_context_uninit_backend_apis__nix(pContext);
29560 #endif
29561 
29562  return result;
29563 }
29564 
29565 
29567 {
29568  return pContext->isBackendAsynchronous;
29569 }
29570 
29571 
29573 {
29576 
29577  return config;
29578 }
29579 
29580 ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext)
29581 {
29582  ma_result result;
29584  ma_backend defaultBackends[ma_backend_null+1];
29585  ma_uint32 iBackend;
29586  ma_backend* pBackendsToIterate;
29587  ma_uint32 backendsToIterateCount;
29588 
29589  if (pContext == NULL) {
29590  return MA_INVALID_ARGS;
29591  }
29592 
29593  MA_ZERO_OBJECT(pContext);
29594 
29595  /* Always make sure the config is set first to ensure properties are available as soon as possible. */
29596  if (pConfig != NULL) {
29597  config = *pConfig;
29598  } else {
29600  }
29601 
29602  pContext->logCallback = config.logCallback;
29603  pContext->threadPriority = config.threadPriority;
29604  pContext->pUserData = config.pUserData;
29605 
29606  result = ma_allocation_callbacks_init_copy(&pContext->allocationCallbacks, &config.allocationCallbacks);
29607  if (result != MA_SUCCESS) {
29608  return result;
29609  }
29610 
29611  /* Backend APIs need to be initialized first. This is where external libraries will be loaded and linked. */
29612  result = ma_context_init_backend_apis(pContext);
29613  if (result != MA_SUCCESS) {
29614  return result;
29615  }
29616 
29617  for (iBackend = 0; iBackend <= ma_backend_null; ++iBackend) {
29618  defaultBackends[iBackend] = (ma_backend)iBackend;
29619  }
29620 
29621  pBackendsToIterate = (ma_backend*)backends;
29622  backendsToIterateCount = backendCount;
29623  if (pBackendsToIterate == NULL) {
29624  pBackendsToIterate = (ma_backend*)defaultBackends;
29625  backendsToIterateCount = ma_countof(defaultBackends);
29626  }
29627 
29628  MA_ASSERT(pBackendsToIterate != NULL);
29629 
29630  for (iBackend = 0; iBackend < backendsToIterateCount; ++iBackend) {
29631  ma_backend backend = pBackendsToIterate[iBackend];
29632 
29633  result = MA_NO_BACKEND;
29634  switch (backend) {
29635  #ifdef MA_HAS_WASAPI
29636  case ma_backend_wasapi:
29637  {
29638  result = ma_context_init__wasapi(&config, pContext);
29639  } break;
29640  #endif
29641  #ifdef MA_HAS_DSOUND
29642  case ma_backend_dsound:
29643  {
29644  result = ma_context_init__dsound(&config, pContext);
29645  } break;
29646  #endif
29647  #ifdef MA_HAS_WINMM
29648  case ma_backend_winmm:
29649  {
29650  result = ma_context_init__winmm(&config, pContext);
29651  } break;
29652  #endif
29653  #ifdef MA_HAS_ALSA
29654  case ma_backend_alsa:
29655  {
29656  result = ma_context_init__alsa(&config, pContext);
29657  } break;
29658  #endif
29659  #ifdef MA_HAS_PULSEAUDIO
29660  case ma_backend_pulseaudio:
29661  {
29662  result = ma_context_init__pulse(&config, pContext);
29663  } break;
29664  #endif
29665  #ifdef MA_HAS_JACK
29666  case ma_backend_jack:
29667  {
29668  result = ma_context_init__jack(&config, pContext);
29669  } break;
29670  #endif
29671  #ifdef MA_HAS_COREAUDIO
29672  case ma_backend_coreaudio:
29673  {
29674  result = ma_context_init__coreaudio(&config, pContext);
29675  } break;
29676  #endif
29677  #ifdef MA_HAS_SNDIO
29678  case ma_backend_sndio:
29679  {
29680  result = ma_context_init__sndio(&config, pContext);
29681  } break;
29682  #endif
29683  #ifdef MA_HAS_AUDIO4
29684  case ma_backend_audio4:
29685  {
29686  result = ma_context_init__audio4(&config, pContext);
29687  } break;
29688  #endif
29689  #ifdef MA_HAS_OSS
29690  case ma_backend_oss:
29691  {
29692  result = ma_context_init__oss(&config, pContext);
29693  } break;
29694  #endif
29695  #ifdef MA_HAS_AAUDIO
29696  case ma_backend_aaudio:
29697  {
29698  result = ma_context_init__aaudio(&config, pContext);
29699  } break;
29700  #endif
29701  #ifdef MA_HAS_OPENSL
29702  case ma_backend_opensl:
29703  {
29704  result = ma_context_init__opensl(&config, pContext);
29705  } break;
29706  #endif
29707  #ifdef MA_HAS_WEBAUDIO
29708  case ma_backend_webaudio:
29709  {
29710  result = ma_context_init__webaudio(&config, pContext);
29711  } break;
29712  #endif
29713  #ifdef MA_HAS_NULL
29714  case ma_backend_null:
29715  {
29716  result = ma_context_init__null(&config, pContext);
29717  } break;
29718  #endif
29719 
29720  default: break;
29721  }
29722 
29723  /* If this iteration was successful, return. */
29724  if (result == MA_SUCCESS) {
29725  result = ma_mutex_init(pContext, &pContext->deviceEnumLock);
29726  if (result != MA_SUCCESS) {
29727  ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.", result);
29728  }
29729  result = ma_mutex_init(pContext, &pContext->deviceInfoLock);
29730  if (result != MA_SUCCESS) {
29731  ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.", result);
29732  }
29733 
29734 #ifdef MA_DEBUG_OUTPUT
29735  printf("[miniaudio] Endian: %s\n", ma_is_little_endian() ? "LE" : "BE");
29736  printf("[miniaudio] SSE2: %s\n", ma_has_sse2() ? "YES" : "NO");
29737  printf("[miniaudio] AVX2: %s\n", ma_has_avx2() ? "YES" : "NO");
29738  printf("[miniaudio] AVX512F: %s\n", ma_has_avx512f() ? "YES" : "NO");
29739  printf("[miniaudio] NEON: %s\n", ma_has_neon() ? "YES" : "NO");
29740 #endif
29741 
29742  pContext->backend = backend;
29743  return result;
29744  }
29745  }
29746 
29747  /* If we get here it means an error occurred. */
29748  MA_ZERO_OBJECT(pContext); /* Safety. */
29749  return MA_NO_BACKEND;
29750 }
29751 
29753 {
29754  if (pContext == NULL) {
29755  return MA_INVALID_ARGS;
29756  }
29757 
29758  pContext->onUninit(pContext);
29759 
29760  ma_mutex_uninit(&pContext->deviceEnumLock);
29761  ma_mutex_uninit(&pContext->deviceInfoLock);
29764 
29765  return MA_SUCCESS;
29766 }
29767 
29768 
29770 {
29771  ma_result result;
29772 
29773  if (pContext == NULL || pContext->onEnumDevices == NULL || callback == NULL) {
29774  return MA_INVALID_ARGS;
29775  }
29776 
29777  ma_mutex_lock(&pContext->deviceEnumLock);
29778  {
29779  result = pContext->onEnumDevices(pContext, callback, pUserData);
29780  }
29781  ma_mutex_unlock(&pContext->deviceEnumLock);
29782 
29783  return result;
29784 }
29785 
29786 
29787 static ma_bool32 ma_context_get_devices__enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData)
29788 {
29789  /*
29790  We need to insert the device info into our main internal buffer. Where it goes depends on the device type. If it's a capture device
29791  it's just appended to the end. If it's a playback device it's inserted just before the first capture device.
29792  */
29793 
29794  /*
29795  First make sure we have room. Since the number of devices we add to the list is usually relatively small I've decided to use a
29796  simple fixed size increment for buffer expansion.
29797  */
29798  const ma_uint32 bufferExpansionCount = 2;
29799  const ma_uint32 totalDeviceInfoCount = pContext->playbackDeviceInfoCount + pContext->captureDeviceInfoCount;
29800 
29801  if (pContext->deviceInfoCapacity >= totalDeviceInfoCount) {
29802  ma_uint32 oldCapacity = pContext->deviceInfoCapacity;
29803  ma_uint32 newCapacity = oldCapacity + bufferExpansionCount;
29804  ma_device_info* pNewInfos = (ma_device_info*)ma__realloc_from_callbacks(pContext->pDeviceInfos, sizeof(*pContext->pDeviceInfos)*newCapacity, sizeof(*pContext->pDeviceInfos)*oldCapacity, &pContext->allocationCallbacks);
29805  if (pNewInfos == NULL) {
29806  return MA_FALSE; /* Out of memory. */
29807  }
29808 
29809  pContext->pDeviceInfos = pNewInfos;
29810  pContext->deviceInfoCapacity = newCapacity;
29811  }
29812 
29813  if (deviceType == ma_device_type_playback) {
29814  /* Playback. Insert just before the first capture device. */
29815 
29816  /* The first thing to do is move all of the capture devices down a slot. */
29817  ma_uint32 iFirstCaptureDevice = pContext->playbackDeviceInfoCount;
29818  size_t iCaptureDevice;
29819  for (iCaptureDevice = totalDeviceInfoCount; iCaptureDevice > iFirstCaptureDevice; --iCaptureDevice) {
29820  pContext->pDeviceInfos[iCaptureDevice] = pContext->pDeviceInfos[iCaptureDevice-1];
29821  }
29822 
29823  /* Now just insert where the first capture device was before moving it down a slot. */
29824  pContext->pDeviceInfos[iFirstCaptureDevice] = *pInfo;
29825  pContext->playbackDeviceInfoCount += 1;
29826  } else {
29827  /* Capture. Insert at the end. */
29828  pContext->pDeviceInfos[totalDeviceInfoCount] = *pInfo;
29829  pContext->captureDeviceInfoCount += 1;
29830  }
29831 
29832  (void)pUserData;
29833  return MA_TRUE;
29834 }
29835 
29836 ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** ppPlaybackDeviceInfos, ma_uint32* pPlaybackDeviceCount, ma_device_info** ppCaptureDeviceInfos, ma_uint32* pCaptureDeviceCount)
29837 {
29838  ma_result result;
29839 
29840  /* Safety. */
29841  if (ppPlaybackDeviceInfos != NULL) *ppPlaybackDeviceInfos = NULL;
29842  if (pPlaybackDeviceCount != NULL) *pPlaybackDeviceCount = 0;
29843  if (ppCaptureDeviceInfos != NULL) *ppCaptureDeviceInfos = NULL;
29844  if (pCaptureDeviceCount != NULL) *pCaptureDeviceCount = 0;
29845 
29846  if (pContext == NULL || pContext->onEnumDevices == NULL) {
29847  return MA_INVALID_ARGS;
29848  }
29849 
29850  /* Note that we don't use ma_context_enumerate_devices() here because we want to do locking at a higher level. */
29851  ma_mutex_lock(&pContext->deviceEnumLock);
29852  {
29853  /* Reset everything first. */
29854  pContext->playbackDeviceInfoCount = 0;
29855  pContext->captureDeviceInfoCount = 0;
29856 
29857  /* Now enumerate over available devices. */
29858  result = pContext->onEnumDevices(pContext, ma_context_get_devices__enum_callback, NULL);
29859  if (result == MA_SUCCESS) {
29860  /* Playback devices. */
29861  if (ppPlaybackDeviceInfos != NULL) {
29862  *ppPlaybackDeviceInfos = pContext->pDeviceInfos;
29863  }
29864  if (pPlaybackDeviceCount != NULL) {
29865  *pPlaybackDeviceCount = pContext->playbackDeviceInfoCount;
29866  }
29867 
29868  /* Capture devices. */
29869  if (ppCaptureDeviceInfos != NULL) {
29870  *ppCaptureDeviceInfos = pContext->pDeviceInfos + pContext->playbackDeviceInfoCount; /* Capture devices come after playback devices. */
29871  }
29872  if (pCaptureDeviceCount != NULL) {
29873  *pCaptureDeviceCount = pContext->captureDeviceInfoCount;
29874  }
29875  }
29876  }
29877  ma_mutex_unlock(&pContext->deviceEnumLock);
29878 
29879  return result;
29880 }
29881 
29882 ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
29883 {
29884  ma_device_info deviceInfo;
29885 
29886  /* NOTE: Do not clear pDeviceInfo on entry. The reason is the pDeviceID may actually point to pDeviceInfo->id which will break things. */
29887  if (pContext == NULL || pDeviceInfo == NULL) {
29888  return MA_INVALID_ARGS;
29889  }
29890 
29891  MA_ZERO_OBJECT(&deviceInfo);
29892 
29893  /* Help the backend out by copying over the device ID if we have one. */
29894  if (pDeviceID != NULL) {
29895  MA_COPY_MEMORY(&deviceInfo.id, pDeviceID, sizeof(*pDeviceID));
29896  }
29897 
29898  /* The backend may have an optimized device info retrieval function. If so, try that first. */
29899  if (pContext->onGetDeviceInfo != NULL) {
29900  ma_result result;
29901  ma_mutex_lock(&pContext->deviceInfoLock);
29902  {
29903  result = pContext->onGetDeviceInfo(pContext, deviceType, pDeviceID, shareMode, &deviceInfo);
29904  }
29905  ma_mutex_unlock(&pContext->deviceInfoLock);
29906 
29907  /* Clamp ranges. */
29908  deviceInfo.minChannels = ma_max(deviceInfo.minChannels, MA_MIN_CHANNELS);
29909  deviceInfo.maxChannels = ma_min(deviceInfo.maxChannels, MA_MAX_CHANNELS);
29910  deviceInfo.minSampleRate = ma_max(deviceInfo.minSampleRate, MA_MIN_SAMPLE_RATE);
29911  deviceInfo.maxSampleRate = ma_min(deviceInfo.maxSampleRate, MA_MAX_SAMPLE_RATE);
29912 
29913  *pDeviceInfo = deviceInfo;
29914  return result;
29915  }
29916 
29917  /* Getting here means onGetDeviceInfo has not been set. */
29918  return MA_ERROR;
29919 }
29920 
29922 {
29923  if (pContext == NULL) {
29924  return MA_FALSE;
29925  }
29926 
29927  return ma_is_loopback_supported(pContext->backend);
29928 }
29929 
29930 
29932 {
29935  config.deviceType = deviceType;
29936 
29937  /* Resampling defaults. We must never use the Speex backend by default because it uses licensed third party code. */
29938  config.resampling.algorithm = ma_resample_algorithm_linear;
29939  config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
29940  config.resampling.speex.quality = 3;
29941 
29942  return config;
29943 }
29944 
29945 ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
29946 {
29947  ma_result result;
29949 
29950  if (pContext == NULL) {
29951  return ma_device_init_ex(NULL, 0, NULL, pConfig, pDevice);
29952  }
29953  if (pDevice == NULL) {
29954  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS);
29955  }
29956  if (pConfig == NULL) {
29957  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid arguments (pConfig == NULL).", MA_INVALID_ARGS);
29958  }
29959 
29960  /* We need to make a copy of the config so we can set default values if they were left unset in the input config. */
29961  config = *pConfig;
29962 
29963  /* Basic config validation. */
29964  if (config.deviceType != ma_device_type_playback && config.deviceType != ma_device_type_capture && config.deviceType != ma_device_type_duplex && config.deviceType != ma_device_type_loopback) {
29965  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Device type is invalid. Make sure the device type has been set in the config.", MA_INVALID_DEVICE_CONFIG);
29966  }
29967 
29968  if (config.deviceType == ma_device_type_capture || config.deviceType == ma_device_type_duplex) {
29969  if (config.capture.channels > MA_MAX_CHANNELS) {
29970  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Capture channel count cannot exceed 32.", MA_INVALID_DEVICE_CONFIG);
29971  }
29972  if (!ma__is_channel_map_valid(config.capture.channelMap, config.capture.channels)) {
29973  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid config. Capture channel map is invalid.", MA_INVALID_DEVICE_CONFIG);
29974  }
29975  }
29976 
29977  if (config.deviceType == ma_device_type_playback || config.deviceType == ma_device_type_duplex || config.deviceType == ma_device_type_loopback) {
29978  if (config.playback.channels > MA_MAX_CHANNELS) {
29979  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Playback channel count cannot exceed 32.", MA_INVALID_DEVICE_CONFIG);
29980  }
29981  if (!ma__is_channel_map_valid(config.playback.channelMap, config.playback.channels)) {
29982  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid config. Playback channel map is invalid.", MA_INVALID_DEVICE_CONFIG);
29983  }
29984  }
29985 
29986 
29987  MA_ZERO_OBJECT(pDevice);
29988  pDevice->pContext = pContext;
29989 
29990  /* Set the user data and log callback ASAP to ensure it is available for the entire initialization process. */
29991  pDevice->pUserData = config.pUserData;
29992  pDevice->onData = config.dataCallback;
29993  pDevice->onStop = config.stopCallback;
29994 
29995  if (((ma_uintptr)pDevice % sizeof(pDevice)) != 0) {
29996  if (pContext->logCallback) {
29997  pContext->logCallback(pContext, pDevice, MA_LOG_LEVEL_WARNING, "WARNING: ma_device_init() called for a device that is not properly aligned. Thread safety is not supported.");
29998  }
29999  }
30000 
30001  pDevice->noPreZeroedOutputBuffer = config.noPreZeroedOutputBuffer;
30002  pDevice->noClip = config.noClip;
30003  pDevice->masterVolumeFactor = 1;
30004 
30005  /*
30006  When passing in 0 for the format/channels/rate/chmap it means the device will be using whatever is chosen by the backend. If everything is set
30007  to defaults it means the format conversion pipeline will run on a fast path where data transfer is just passed straight through to the backend.
30008  */
30009  if (config.sampleRate == 0) {
30010  config.sampleRate = MA_DEFAULT_SAMPLE_RATE;
30011  pDevice->usingDefaultSampleRate = MA_TRUE;
30012  }
30013 
30014  if (config.capture.format == ma_format_unknown) {
30015  config.capture.format = MA_DEFAULT_FORMAT;
30016  pDevice->capture.usingDefaultFormat = MA_TRUE;
30017  }
30018  if (config.capture.channels == 0) {
30019  config.capture.channels = MA_DEFAULT_CHANNELS;
30021  }
30022  if (config.capture.channelMap[0] == MA_CHANNEL_NONE) {
30024  }
30025 
30026  if (config.playback.format == ma_format_unknown) {
30027  config.playback.format = MA_DEFAULT_FORMAT;
30028  pDevice->playback.usingDefaultFormat = MA_TRUE;
30029  }
30030  if (config.playback.channels == 0) {
30031  config.playback.channels = MA_DEFAULT_CHANNELS;
30033  }
30034  if (config.playback.channelMap[0] == MA_CHANNEL_NONE) {
30036  }
30037 
30038 
30039  /* Default periods. */
30040  if (config.periods == 0) {
30041  config.periods = MA_DEFAULT_PERIODS;
30042  pDevice->usingDefaultPeriods = MA_TRUE;
30043  }
30044 
30045  /*
30046  Must have at least 3 periods for full-duplex mode. The idea is that the playback and capture positions hang out in the middle period, with the surrounding
30047  periods acting as a buffer in case the capture and playback devices get's slightly out of sync.
30048  */
30049  if (config.deviceType == ma_device_type_duplex && config.periods < 3) {
30050  config.periods = 3;
30051  }
30052 
30053  /* Default buffer size. */
30054  if (config.periodSizeInMilliseconds == 0 && config.periodSizeInFrames == 0) {
30056  pDevice->usingDefaultBufferSize = MA_TRUE;
30057  }
30058 
30059 
30060 
30061  pDevice->type = config.deviceType;
30062  pDevice->sampleRate = config.sampleRate;
30063  pDevice->resampling.algorithm = config.resampling.algorithm;
30064  pDevice->resampling.linear.lpfOrder = config.resampling.linear.lpfOrder;
30065  pDevice->resampling.speex.quality = config.resampling.speex.quality;
30066 
30067  pDevice->capture.shareMode = config.capture.shareMode;
30068  pDevice->capture.format = config.capture.format;
30069  pDevice->capture.channels = config.capture.channels;
30070  ma_channel_map_copy(pDevice->capture.channelMap, config.capture.channelMap, config.capture.channels);
30071 
30072  pDevice->playback.shareMode = config.playback.shareMode;
30073  pDevice->playback.format = config.playback.format;
30074  pDevice->playback.channels = config.playback.channels;
30075  ma_channel_map_copy(pDevice->playback.channelMap, config.playback.channelMap, config.playback.channels);
30076 
30077 
30078  /* The internal format, channel count and sample rate can be modified by the backend. */
30079  pDevice->capture.internalFormat = pDevice->capture.format;
30080  pDevice->capture.internalChannels = pDevice->capture.channels;
30081  pDevice->capture.internalSampleRate = pDevice->sampleRate;
30083 
30084  pDevice->playback.internalFormat = pDevice->playback.format;
30085  pDevice->playback.internalChannels = pDevice->playback.channels;
30086  pDevice->playback.internalSampleRate = pDevice->sampleRate;
30088 
30089  result = ma_mutex_init(pContext, &pDevice->lock);
30090  if (result != MA_SUCCESS) {
30091  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create mutex.", result);
30092  }
30093 
30094  /*
30095  When the device is started, the worker thread is the one that does the actual startup of the backend device. We
30096  use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device.
30097 
30098  Each of these semaphores is released internally by the worker thread when the work is completed. The start
30099  semaphore is also used to wake up the worker thread.
30100  */
30101  result = ma_event_init(pContext, &pDevice->wakeupEvent);
30102  if (result != MA_SUCCESS) {
30103  ma_mutex_uninit(&pDevice->lock);
30104  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread wakeup event.", result);
30105  }
30106 
30107  result = ma_event_init(pContext, &pDevice->startEvent);
30108  if (result != MA_SUCCESS) {
30109  ma_event_uninit(&pDevice->wakeupEvent);
30110  ma_mutex_uninit(&pDevice->lock);
30111  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread start event.", result);
30112  }
30113 
30114  result = ma_event_init(pContext, &pDevice->stopEvent);
30115  if (result != MA_SUCCESS) {
30116  ma_event_uninit(&pDevice->startEvent);
30117  ma_event_uninit(&pDevice->wakeupEvent);
30118  ma_mutex_uninit(&pDevice->lock);
30119  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread stop event.", result);
30120  }
30121 
30122 
30123  result = pContext->onDeviceInit(pContext, &config, pDevice);
30124  if (result != MA_SUCCESS) {
30125  return result;
30126  }
30127 
30128  ma_device__post_init_setup(pDevice, pConfig->deviceType);
30129 
30130 
30131  /* If the backend did not fill out a name for the device, try a generic method. */
30132  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
30133  if (pDevice->capture.name[0] == '\0') {
30134  if (ma_context__try_get_device_name_by_id(pContext, ma_device_type_capture, config.capture.pDeviceID, pDevice->capture.name, sizeof(pDevice->capture.name)) != MA_SUCCESS) {
30135  ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), (config.capture.pDeviceID == NULL) ? MA_DEFAULT_CAPTURE_DEVICE_NAME : "Capture Device", (size_t)-1);
30136  }
30137  }
30138  }
30139  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
30140  if (pDevice->playback.name[0] == '\0') {
30141  if (ma_context__try_get_device_name_by_id(pContext, ma_device_type_playback, config.playback.pDeviceID, pDevice->playback.name, sizeof(pDevice->playback.name)) != MA_SUCCESS) {
30142  ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), (config.playback.pDeviceID == NULL) ? MA_DEFAULT_PLAYBACK_DEVICE_NAME : "Playback Device", (size_t)-1);
30143  }
30144  }
30145  }
30146 
30147 
30148  /* Some backends don't require the worker thread. */
30149  if (!ma_context_is_backend_asynchronous(pContext)) {
30150  /* The worker thread. */
30151  result = ma_thread_create(pContext, &pDevice->thread, ma_worker_thread, pDevice);
30152  if (result != MA_SUCCESS) {
30153  ma_device_uninit(pDevice);
30154  return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread.", result);
30155  }
30156 
30157  /* Wait for the worker thread to put the device into it's stopped state for real. */
30158  ma_event_wait(&pDevice->stopEvent);
30159  } else {
30161  }
30162 
30163 
30164 #ifdef MA_DEBUG_OUTPUT
30165  printf("[%s]\n", ma_get_backend_name(pDevice->pContext->backend));
30166  if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
30167  printf(" %s (%s)\n", pDevice->capture.name, "Capture");
30168  printf(" Format: %s -> %s\n", ma_get_format_name(pDevice->capture.format), ma_get_format_name(pDevice->capture.internalFormat));
30169  printf(" Channels: %d -> %d\n", pDevice->capture.channels, pDevice->capture.internalChannels);
30170  printf(" Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->capture.internalSampleRate);
30171  printf(" Buffer Size: %d*%d (%d)\n", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods));
30172  printf(" Conversion:\n");
30173  printf(" Pre Format Conversion: %s\n", pDevice->capture.converter.hasPreFormatConversion ? "YES" : "NO");
30174  printf(" Post Format Conversion: %s\n", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO");
30175  printf(" Channel Routing: %s\n", pDevice->capture.converter.hasChannelConverter ? "YES" : "NO");
30176  printf(" Resampling: %s\n", pDevice->capture.converter.hasResampler ? "YES" : "NO");
30177  printf(" Passthrough: %s\n", pDevice->capture.converter.isPassthrough ? "YES" : "NO");
30178  }
30179  if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
30180  printf(" %s (%s)\n", pDevice->playback.name, "Playback");
30181  printf(" Format: %s -> %s\n", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat));
30182  printf(" Channels: %d -> %d\n", pDevice->playback.channels, pDevice->playback.internalChannels);
30183  printf(" Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->playback.internalSampleRate);
30184  printf(" Buffer Size: %d*%d (%d)\n", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods));
30185  printf(" Conversion:\n");
30186  printf(" Pre Format Conversion: %s\n", pDevice->playback.converter.hasPreFormatConversion ? "YES" : "NO");
30187  printf(" Post Format Conversion: %s\n", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO");
30188  printf(" Channel Routing: %s\n", pDevice->playback.converter.hasChannelConverter ? "YES" : "NO");
30189  printf(" Resampling: %s\n", pDevice->playback.converter.hasResampler ? "YES" : "NO");
30190  printf(" Passthrough: %s\n", pDevice->playback.converter.isPassthrough ? "YES" : "NO");
30191  }
30192 #endif
30193 
30194 
30195  MA_ASSERT(ma_device__get_state(pDevice) == MA_STATE_STOPPED);
30196  return MA_SUCCESS;
30197 }
30198 
30199 ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pContextConfig, const ma_device_config* pConfig, ma_device* pDevice)
30200 {
30201  ma_result result;
30202  ma_context* pContext;
30203  ma_backend defaultBackends[ma_backend_null+1];
30204  ma_uint32 iBackend;
30205  ma_backend* pBackendsToIterate;
30206  ma_uint32 backendsToIterateCount;
30207  ma_allocation_callbacks allocationCallbacks;
30208 
30209  if (pConfig == NULL) {
30210  return MA_INVALID_ARGS;
30211  }
30212 
30213  if (pContextConfig != NULL) {
30214  result = ma_allocation_callbacks_init_copy(&allocationCallbacks, &pContextConfig->allocationCallbacks);
30215  if (result != MA_SUCCESS) {
30216  return result;
30217  }
30218  } else {
30219  allocationCallbacks = ma_allocation_callbacks_init_default();
30220  }
30221 
30222 
30223  pContext = (ma_context*)ma__malloc_from_callbacks(sizeof(*pContext), &allocationCallbacks);
30224  if (pContext == NULL) {
30225  return MA_OUT_OF_MEMORY;
30226  }
30227 
30228  for (iBackend = 0; iBackend <= ma_backend_null; ++iBackend) {
30229  defaultBackends[iBackend] = (ma_backend)iBackend;
30230  }
30231 
30232  pBackendsToIterate = (ma_backend*)backends;
30233  backendsToIterateCount = backendCount;
30234  if (pBackendsToIterate == NULL) {
30235  pBackendsToIterate = (ma_backend*)defaultBackends;
30236  backendsToIterateCount = ma_countof(defaultBackends);
30237  }
30238 
30239  result = MA_NO_BACKEND;
30240 
30241  for (iBackend = 0; iBackend < backendsToIterateCount; ++iBackend) {
30242  result = ma_context_init(&pBackendsToIterate[iBackend], 1, pContextConfig, pContext);
30243  if (result == MA_SUCCESS) {
30244  result = ma_device_init(pContext, pConfig, pDevice);
30245  if (result == MA_SUCCESS) {
30246  break; /* Success. */
30247  } else {
30248  ma_context_uninit(pContext); /* Failure. */
30249  }
30250  }
30251  }
30252 
30253  if (result != MA_SUCCESS) {
30254  ma__free_from_callbacks(pContext, &allocationCallbacks);
30255  return result;
30256  }
30257 
30258  pDevice->isOwnerOfContext = MA_TRUE;
30259  return result;
30260 }
30261 
30262 void ma_device_uninit(ma_device* pDevice)
30263 {
30264  if (!ma_device__is_initialized(pDevice)) {
30265  return;
30266  }
30267 
30268  /* Make sure the device is stopped first. The backends will probably handle this naturally, but I like to do it explicitly for my own sanity. */
30269  if (ma_device_is_started(pDevice)) {
30270  ma_device_stop(pDevice);
30271  }
30272 
30273  /* Putting the device into an uninitialized state will make the worker thread return. */
30275 
30276  /* Wake up the worker thread and wait for it to properly terminate. */
30278  ma_event_signal(&pDevice->wakeupEvent);
30279  ma_thread_wait(&pDevice->thread);
30280  }
30281 
30282  pDevice->pContext->onDeviceUninit(pDevice);
30283 
30284  ma_event_uninit(&pDevice->stopEvent);
30285  ma_event_uninit(&pDevice->startEvent);
30286  ma_event_uninit(&pDevice->wakeupEvent);
30287  ma_mutex_uninit(&pDevice->lock);
30288 
30289  if (pDevice->isOwnerOfContext) {
30290  ma_allocation_callbacks allocationCallbacks = pDevice->pContext->allocationCallbacks;
30291 
30292  ma_context_uninit(pDevice->pContext);
30293  ma__free_from_callbacks(pDevice->pContext, &allocationCallbacks);
30294  }
30295 
30296  MA_ZERO_OBJECT(pDevice);
30297 }
30298 
30300 {
30301  ma_result result;
30302 
30303  if (pDevice == NULL) {
30304  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS);
30305  }
30306 
30307  if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED) {
30308  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED);
30309  }
30310 
30311  if (ma_device__get_state(pDevice) == MA_STATE_STARTED) {
30312  return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_start() called when the device is already started.", MA_INVALID_OPERATION); /* Already started. Returning an error to let the application know because it probably means they're doing something wrong. */
30313  }
30314 
30315  result = MA_ERROR;
30316  ma_mutex_lock(&pDevice->lock);
30317  {
30318  /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a stopped or paused state. */
30319  MA_ASSERT(ma_device__get_state(pDevice) == MA_STATE_STOPPED);
30320 
30322 
30323  /* Asynchronous backends need to be handled differently. */
30325  result = pDevice->pContext->onDeviceStart(pDevice);
30326  if (result == MA_SUCCESS) {
30328  }
30329  } else {
30330  /*
30331  Synchronous backends are started by signaling an event that's being waited on in the worker thread. We first wake up the
30332  thread and then wait for the start event.
30333  */
30334  ma_event_signal(&pDevice->wakeupEvent);
30335 
30336  /*
30337  Wait for the worker thread to finish starting the device. Note that the worker thread will be the one who puts the device
30338  into the started state. Don't call ma_device__set_state() here.
30339  */
30340  ma_event_wait(&pDevice->startEvent);
30341  result = pDevice->workResult;
30342  }
30343  }
30344  ma_mutex_unlock(&pDevice->lock);
30345 
30346  return result;
30347 }
30348 
30350 {
30351  ma_result result;
30352 
30353  if (pDevice == NULL) {
30354  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS);
30355  }
30356 
30357  if (ma_device__get_state(pDevice) == MA_STATE_UNINITIALIZED) {
30358  return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED);
30359  }
30360 
30361  if (ma_device__get_state(pDevice) == MA_STATE_STOPPED) {
30362  return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_stop() called when the device is already stopped.", MA_INVALID_OPERATION); /* Already stopped. Returning an error to let the application know because it probably means they're doing something wrong. */
30363  }
30364 
30365  result = MA_ERROR;
30366  ma_mutex_lock(&pDevice->lock);
30367  {
30368  /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a started or paused state. */
30369  MA_ASSERT(ma_device__get_state(pDevice) == MA_STATE_STARTED);
30370 
30372 
30373  /* There's no need to wake up the thread like we do when starting. */
30374 
30375  if (pDevice->pContext->onDeviceStop) {
30376  result = pDevice->pContext->onDeviceStop(pDevice);
30377  } else {
30378  result = MA_SUCCESS;
30379  }
30380 
30381  /* Asynchronous backends need to be handled differently. */
30384  } else {
30385  /* Synchronous backends. */
30386 
30387  /*
30388  We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be
30389  the one who puts the device into the stopped state. Don't call ma_device__set_state() here.
30390  */
30391  ma_event_wait(&pDevice->stopEvent);
30392  result = MA_SUCCESS;
30393  }
30394  }
30395  ma_mutex_unlock(&pDevice->lock);
30396 
30397  return result;
30398 }
30399 
30401 {
30402  if (pDevice == NULL) {
30403  return MA_FALSE;
30404  }
30405 
30406  return ma_device__get_state(pDevice) == MA_STATE_STARTED;
30407 }
30408 
30409 ma_result ma_device_set_master_volume(ma_device* pDevice, float volume)
30410 {
30411  if (pDevice == NULL) {
30412  return MA_INVALID_ARGS;
30413  }
30414 
30415  if (volume < 0.0f || volume > 1.0f) {
30416  return MA_INVALID_ARGS;
30417  }
30418 
30419  pDevice->masterVolumeFactor = volume;
30420 
30421  return MA_SUCCESS;
30422 }
30423 
30424 ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume)
30425 {
30426  if (pVolume == NULL) {
30427  return MA_INVALID_ARGS;
30428  }
30429 
30430  if (pDevice == NULL) {
30431  *pVolume = 0;
30432  return MA_INVALID_ARGS;
30433  }
30434 
30435  *pVolume = pDevice->masterVolumeFactor;
30436 
30437  return MA_SUCCESS;
30438 }
30439 
30440 ma_result ma_device_set_master_gain_db(ma_device* pDevice, float gainDB)
30441 {
30442  if (gainDB > 0) {
30443  return MA_INVALID_ARGS;
30444  }
30445 
30446  return ma_device_set_master_volume(pDevice, ma_gain_db_to_factor(gainDB));
30447 }
30448 
30449 ma_result ma_device_get_master_gain_db(ma_device* pDevice, float* pGainDB)
30450 {
30451  float factor;
30452  ma_result result;
30453 
30454  if (pGainDB == NULL) {
30455  return MA_INVALID_ARGS;
30456  }
30457 
30458  result = ma_device_get_master_volume(pDevice, &factor);
30459  if (result != MA_SUCCESS) {
30460  *pGainDB = 0;
30461  return result;
30462  }
30463 
30464  *pGainDB = ma_factor_to_gain_db(factor);
30465 
30466  return MA_SUCCESS;
30467 }
30468 #endif /* MA_NO_DEVICE_IO */
30469 
30470 
30471 /**************************************************************************************************************************************************************
30472 
30473 Biquad Filter
30474 
30475 **************************************************************************************************************************************************************/
30476 #ifndef MA_BIQUAD_FIXED_POINT_SHIFT
30477 #define MA_BIQUAD_FIXED_POINT_SHIFT 14
30478 #endif
30479 
30480 static ma_int32 ma_biquad_float_to_fp(double x)
30481 {
30482  return (ma_int32)(x * (1 << MA_BIQUAD_FIXED_POINT_SHIFT));
30483 }
30484 
30485 ma_biquad_config ma_biquad_config_init(ma_format format, ma_uint32 channels, double b0, double b1, double b2, double a0, double a1, double a2)
30486 {
30488 
30490  config.format = format;
30491  config.channels = channels;
30492  config.b0 = b0;
30493  config.b1 = b1;
30494  config.b2 = b2;
30495  config.a0 = a0;
30496  config.a1 = a1;
30497  config.a2 = a2;
30498 
30499  return config;
30500 }
30501 
30502 ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ)
30503 {
30504  if (pBQ == NULL) {
30505  return MA_INVALID_ARGS;
30506  }
30507 
30508  MA_ZERO_OBJECT(pBQ);
30509 
30510  if (pConfig == NULL) {
30511  return MA_INVALID_ARGS;
30512  }
30513 
30514  return ma_biquad_reinit(pConfig, pBQ);
30515 }
30516 
30518 {
30519  if (pBQ == NULL || pConfig == NULL) {
30520  return MA_INVALID_ARGS;
30521  }
30522 
30523  if (pConfig->a0 == 0) {
30524  return MA_INVALID_ARGS; /* Division by zero. */
30525  }
30526 
30527  /* Only supporting f32 and s16. */
30528  if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
30529  return MA_INVALID_ARGS;
30530  }
30531 
30532  /* The format cannot be changed after initialization. */
30533  if (pBQ->format != ma_format_unknown && pBQ->format != pConfig->format) {
30534  return MA_INVALID_OPERATION;
30535  }
30536 
30537  /* The channel count cannot be changed after initialization. */
30538  if (pBQ->channels != 0 && pBQ->channels != pConfig->channels) {
30539  return MA_INVALID_OPERATION;
30540  }
30541 
30542 
30543  pBQ->format = pConfig->format;
30544  pBQ->channels = pConfig->channels;
30545 
30546  /* Normalize. */
30547  if (pConfig->format == ma_format_f32) {
30548  pBQ->b0.f32 = (float)(pConfig->b0 / pConfig->a0);
30549  pBQ->b1.f32 = (float)(pConfig->b1 / pConfig->a0);
30550  pBQ->b2.f32 = (float)(pConfig->b2 / pConfig->a0);
30551  pBQ->a1.f32 = (float)(pConfig->a1 / pConfig->a0);
30552  pBQ->a2.f32 = (float)(pConfig->a2 / pConfig->a0);
30553  } else {
30554  pBQ->b0.s32 = ma_biquad_float_to_fp(pConfig->b0 / pConfig->a0);
30555  pBQ->b1.s32 = ma_biquad_float_to_fp(pConfig->b1 / pConfig->a0);
30556  pBQ->b2.s32 = ma_biquad_float_to_fp(pConfig->b2 / pConfig->a0);
30557  pBQ->a1.s32 = ma_biquad_float_to_fp(pConfig->a1 / pConfig->a0);
30558  pBQ->a2.s32 = ma_biquad_float_to_fp(pConfig->a2 / pConfig->a0);
30559  }
30560 
30561  return MA_SUCCESS;
30562 }
30563 
30564 static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(ma_biquad* pBQ, float* pY, const float* pX)
30565 {
30566  ma_uint32 c;
30567  const float b0 = pBQ->b0.f32;
30568  const float b1 = pBQ->b1.f32;
30569  const float b2 = pBQ->b2.f32;
30570  const float a1 = pBQ->a1.f32;
30571  const float a2 = pBQ->a2.f32;
30572 
30573  for (c = 0; c < pBQ->channels; c += 1) {
30574  float r1 = pBQ->r1[c].f32;
30575  float r2 = pBQ->r2[c].f32;
30576  float x = pX[c];
30577  float y;
30578 
30579  y = b0*x + r1;
30580  r1 = b1*x - a1*y + r2;
30581  r2 = b2*x - a2*y;
30582 
30583  pY[c] = y;
30584  pBQ->r1[c].f32 = r1;
30585  pBQ->r2[c].f32 = r2;
30586  }
30587 }
30588 
30589 static MA_INLINE void ma_biquad_process_pcm_frame_f32(ma_biquad* pBQ, float* pY, const float* pX)
30590 {
30592 }
30593 
30595 {
30596  ma_uint32 c;
30597  const ma_int32 b0 = pBQ->b0.s32;
30598  const ma_int32 b1 = pBQ->b1.s32;
30599  const ma_int32 b2 = pBQ->b2.s32;
30600  const ma_int32 a1 = pBQ->a1.s32;
30601  const ma_int32 a2 = pBQ->a2.s32;
30602 
30603  for (c = 0; c < pBQ->channels; c += 1) {
30604  ma_int32 r1 = pBQ->r1[c].s32;
30605  ma_int32 r2 = pBQ->r2[c].s32;
30606  ma_int32 x = pX[c];
30607  ma_int32 y;
30608 
30609  y = (b0*x + r1) >> MA_BIQUAD_FIXED_POINT_SHIFT;
30610  r1 = (b1*x - a1*y + r2);
30611  r2 = (b2*x - a2*y);
30612 
30613  pY[c] = (ma_int16)ma_clamp(y, -32768, 32767);
30614  pBQ->r1[c].s32 = r1;
30615  pBQ->r2[c].s32 = r2;
30616  }
30617 }
30618 
30619 static MA_INLINE void ma_biquad_process_pcm_frame_s16(ma_biquad* pBQ, ma_int16* pY, const ma_int16* pX)
30620 {
30622 }
30623 
30624 ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
30625 {
30626  ma_uint32 n;
30627 
30628  if (pBQ == NULL || pFramesOut == NULL || pFramesIn == NULL) {
30629  return MA_INVALID_ARGS;
30630  }
30631 
30632  /* Note that the logic below needs to support in-place filtering. That is, it must support the case where pFramesOut and pFramesIn are the same. */
30633 
30634  if (pBQ->format == ma_format_f32) {
30635  /* */ float* pY = ( float*)pFramesOut;
30636  const float* pX = (const float*)pFramesIn;
30637 
30638  for (n = 0; n < frameCount; n += 1) {
30640  pY += pBQ->channels;
30641  pX += pBQ->channels;
30642  }
30643  } else if (pBQ->format == ma_format_s16) {
30644  /* */ ma_int16* pY = ( ma_int16*)pFramesOut;
30645  const ma_int16* pX = (const ma_int16*)pFramesIn;
30646 
30647  for (n = 0; n < frameCount; n += 1) {
30649  pY += pBQ->channels;
30650  pX += pBQ->channels;
30651  }
30652  } else {
30654  return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */
30655  }
30656 
30657  return MA_SUCCESS;
30658 }
30659 
30661 {
30662  if (pBQ == NULL) {
30663  return 0;
30664  }
30665 
30666  return 2;
30667 }
30668 
30669 
30670 /**************************************************************************************************************************************************************
30671 
30672 Low-Pass Filter
30673 
30674 **************************************************************************************************************************************************************/
30675 ma_lpf1_config ma_lpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency)
30676 {
30678 
30680  config.format = format;
30681  config.channels = channels;
30682  config.sampleRate = sampleRate;
30683  config.cutoffFrequency = cutoffFrequency;
30684  config.q = 0.5;
30685 
30686  return config;
30687 }
30688 
30689 ma_lpf2_config ma_lpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
30690 {
30692 
30694  config.format = format;
30695  config.channels = channels;
30696  config.sampleRate = sampleRate;
30697  config.cutoffFrequency = cutoffFrequency;
30698  config.q = q;
30699 
30700  /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */
30701  if (config.q == 0) {
30702  config.q = 0.707107;
30703  }
30704 
30705  return config;
30706 }
30707 
30708 
30709 ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, ma_lpf1* pLPF)
30710 {
30711  if (pLPF == NULL) {
30712  return MA_INVALID_ARGS;
30713  }
30714 
30715  MA_ZERO_OBJECT(pLPF);
30716 
30717  if (pConfig == NULL) {
30718  return MA_INVALID_ARGS;
30719  }
30720 
30721  return ma_lpf1_reinit(pConfig, pLPF);
30722 }
30723 
30724 ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF)
30725 {
30726  double a;
30727 
30728  if (pLPF == NULL || pConfig == NULL) {
30729  return MA_INVALID_ARGS;
30730  }
30731 
30732  /* Only supporting f32 and s16. */
30733  if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
30734  return MA_INVALID_ARGS;
30735  }
30736 
30737  /* The format cannot be changed after initialization. */
30738  if (pLPF->format != ma_format_unknown && pLPF->format != pConfig->format) {
30739  return MA_INVALID_OPERATION;
30740  }
30741 
30742  /* The channel count cannot be changed after initialization. */
30743  if (pLPF->channels != 0 && pLPF->channels != pConfig->channels) {
30744  return MA_INVALID_OPERATION;
30745  }
30746 
30747  pLPF->format = pConfig->format;
30748  pLPF->channels = pConfig->channels;
30749 
30750  a = ma_exp(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate);
30751  if (pConfig->format == ma_format_f32) {
30752  pLPF->a.f32 = (float)a;
30753  } else {
30754  pLPF->a.s32 = ma_biquad_float_to_fp(a);
30755  }
30756 
30757  return MA_SUCCESS;
30758 }
30759 
30760 static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, const float* pX)
30761 {
30762  ma_uint32 c;
30763  const float a = pLPF->a.f32;
30764  const float b = 1 - a;
30765 
30766  for (c = 0; c < pLPF->channels; c += 1) {
30767  float r1 = pLPF->r1[c].f32;
30768  float x = pX[c];
30769  float y;
30770 
30771  y = b*x + a*r1;
30772 
30773  pY[c] = y;
30774  pLPF->r1[c].f32 = y;
30775  }
30776 }
30777 
30778 static MA_INLINE void ma_lpf1_process_pcm_frame_s16(ma_lpf1* pLPF, ma_int16* pY, const ma_int16* pX)
30779 {
30780  ma_uint32 c;
30781  const ma_int32 a = pLPF->a.s32;
30782  const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a);
30783 
30784  for (c = 0; c < pLPF->channels; c += 1) {
30785  ma_int32 r1 = pLPF->r1[c].s32;
30786  ma_int32 x = pX[c];
30787  ma_int32 y;
30788 
30789  y = (b*x + a*r1) >> MA_BIQUAD_FIXED_POINT_SHIFT;
30790 
30791  pY[c] = (ma_int16)y;
30792  pLPF->r1[c].s32 = (ma_int32)y;
30793  }
30794 }
30795 
30796 ma_result ma_lpf1_process_pcm_frames(ma_lpf1* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
30797 {
30798  ma_uint32 n;
30799 
30800  if (pLPF == NULL || pFramesOut == NULL || pFramesIn == NULL) {
30801  return MA_INVALID_ARGS;
30802  }
30803 
30804  /* Note that the logic below needs to support in-place filtering. That is, it must support the case where pFramesOut and pFramesIn are the same. */
30805 
30806  if (pLPF->format == ma_format_f32) {
30807  /* */ float* pY = ( float*)pFramesOut;
30808  const float* pX = (const float*)pFramesIn;
30809 
30810  for (n = 0; n < frameCount; n += 1) {
30811  ma_lpf1_process_pcm_frame_f32(pLPF, pY, pX);
30812  pY += pLPF->channels;
30813  pX += pLPF->channels;
30814  }
30815  } else if (pLPF->format == ma_format_s16) {
30816  /* */ ma_int16* pY = ( ma_int16*)pFramesOut;
30817  const ma_int16* pX = (const ma_int16*)pFramesIn;
30818 
30819  for (n = 0; n < frameCount; n += 1) {
30820  ma_lpf1_process_pcm_frame_s16(pLPF, pY, pX);
30821  pY += pLPF->channels;
30822  pX += pLPF->channels;
30823  }
30824  } else {
30826  return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */
30827  }
30828 
30829  return MA_SUCCESS;
30830 }
30831 
30833 {
30834  if (pLPF == NULL) {
30835  return 0;
30836  }
30837 
30838  return 1;
30839 }
30840 
30841 
30843 {
30844  ma_biquad_config bqConfig;
30845  double q;
30846  double w;
30847  double s;
30848  double c;
30849  double a;
30850 
30851  MA_ASSERT(pConfig != NULL);
30852 
30853  q = pConfig->q;
30854  w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
30855  s = ma_sin(w);
30856  c = ma_cos(w);
30857  a = s / (2*q);
30858 
30859  bqConfig.b0 = (1 - c) / 2;
30860  bqConfig.b1 = 1 - c;
30861  bqConfig.b2 = (1 - c) / 2;
30862  bqConfig.a0 = 1 + a;
30863  bqConfig.a1 = -2 * c;
30864  bqConfig.a2 = 1 - a;
30865 
30866  bqConfig.format = pConfig->format;
30867  bqConfig.channels = pConfig->channels;
30868 
30869  return bqConfig;
30870 }
30871 
30872 ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, ma_lpf2* pLPF)
30873 {
30874  ma_result result;
30875  ma_biquad_config bqConfig;
30876 
30877  if (pLPF == NULL) {
30878  return MA_INVALID_ARGS;
30879  }
30880 
30881  MA_ZERO_OBJECT(pLPF);
30882 
30883  if (pConfig == NULL) {
30884  return MA_INVALID_ARGS;
30885  }
30886 
30887  bqConfig = ma_lpf2__get_biquad_config(pConfig);
30888  result = ma_biquad_init(&bqConfig, &pLPF->bq);
30889  if (result != MA_SUCCESS) {
30890  return result;
30891  }
30892 
30893  return MA_SUCCESS;
30894 }
30895 
30896 ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF)
30897 {
30898  ma_result result;
30899  ma_biquad_config bqConfig;
30900 
30901  if (pLPF == NULL || pConfig == NULL) {
30902  return MA_INVALID_ARGS;
30903  }
30904 
30905  bqConfig = ma_lpf2__get_biquad_config(pConfig);
30906  result = ma_biquad_reinit(&bqConfig, &pLPF->bq);
30907  if (result != MA_SUCCESS) {
30908  return result;
30909  }
30910 
30911  return MA_SUCCESS;
30912 }
30913 
30914 static MA_INLINE void ma_lpf2_process_pcm_frame_s16(ma_lpf2* pLPF, ma_int16* pFrameOut, const ma_int16* pFrameIn)
30915 {
30916  ma_biquad_process_pcm_frame_s16(&pLPF->bq, pFrameOut, pFrameIn);
30917 }
30918 
30919 static MA_INLINE void ma_lpf2_process_pcm_frame_f32(ma_lpf2* pLPF, float* pFrameOut, const float* pFrameIn)
30920 {
30921  ma_biquad_process_pcm_frame_f32(&pLPF->bq, pFrameOut, pFrameIn);
30922 }
30923 
30924 ma_result ma_lpf2_process_pcm_frames(ma_lpf2* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
30925 {
30926  if (pLPF == NULL) {
30927  return MA_INVALID_ARGS;
30928  }
30929 
30930  return ma_biquad_process_pcm_frames(&pLPF->bq, pFramesOut, pFramesIn, frameCount);
30931 }
30932 
30934 {
30935  if (pLPF == NULL) {
30936  return 0;
30937  }
30938 
30939  return ma_biquad_get_latency(&pLPF->bq);
30940 }
30941 
30942 
30943 ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
30944 {
30946 
30948  config.format = format;
30949  config.channels = channels;
30950  config.sampleRate = sampleRate;
30951  config.cutoffFrequency = cutoffFrequency;
30952  config.order = ma_min(order, MA_MAX_FILTER_ORDER);
30953 
30954  return config;
30955 }
30956 
30957 static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, ma_lpf* pLPF, ma_bool32 isNew)
30958 {
30959  ma_result result;
30960  ma_uint32 lpf1Count;
30961  ma_uint32 lpf2Count;
30962  ma_uint32 ilpf1;
30963  ma_uint32 ilpf2;
30964 
30965  if (pLPF == NULL || pConfig == NULL) {
30966  return MA_INVALID_ARGS;
30967  }
30968 
30969  /* Only supporting f32 and s16. */
30970  if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
30971  return MA_INVALID_ARGS;
30972  }
30973 
30974  /* The format cannot be changed after initialization. */
30975  if (pLPF->format != ma_format_unknown && pLPF->format != pConfig->format) {
30976  return MA_INVALID_OPERATION;
30977  }
30978 
30979  /* The channel count cannot be changed after initialization. */
30980  if (pLPF->channels != 0 && pLPF->channels != pConfig->channels) {
30981  return MA_INVALID_OPERATION;
30982  }
30983 
30984  if (pConfig->order > MA_MAX_FILTER_ORDER) {
30985  return MA_INVALID_ARGS;
30986  }
30987 
30988  lpf1Count = pConfig->order % 2;
30989  lpf2Count = pConfig->order / 2;
30990 
30991  MA_ASSERT(lpf1Count <= ma_countof(pLPF->lpf1));
30992  MA_ASSERT(lpf2Count <= ma_countof(pLPF->lpf2));
30993 
30994  /* The filter order can't change between reinits. */
30995  if (!isNew) {
30996  if (pLPF->lpf1Count != lpf1Count || pLPF->lpf2Count != lpf2Count) {
30997  return MA_INVALID_OPERATION;
30998  }
30999  }
31000 
31001  for (ilpf1 = 0; ilpf1 < lpf1Count; ilpf1 += 1) {
31002  ma_lpf1_config lpf1Config = ma_lpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency);
31003 
31004  if (isNew) {
31005  result = ma_lpf1_init(&lpf1Config, &pLPF->lpf1[ilpf1]);
31006  } else {
31007  result = ma_lpf1_reinit(&lpf1Config, &pLPF->lpf1[ilpf1]);
31008  }
31009 
31010  if (result != MA_SUCCESS) {
31011  return result;
31012  }
31013  }
31014 
31015  for (ilpf2 = 0; ilpf2 < lpf2Count; ilpf2 += 1) {
31016  ma_lpf2_config lpf2Config;
31017  double q;
31018  double a;
31019 
31020  /* Tempting to use 0.707107, but won't result in a Butterworth filter if the order is > 2. */
31021  if (lpf1Count == 1) {
31022  a = (1 + ilpf2*1) * (MA_PI_D/(pConfig->order*1)); /* Odd order. */
31023  } else {
31024  a = (1 + ilpf2*2) * (MA_PI_D/(pConfig->order*2)); /* Even order. */
31025  }
31026  q = 1 / (2*ma_cos(a));
31027 
31028  lpf2Config = ma_lpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q);
31029 
31030  if (isNew) {
31031  result = ma_lpf2_init(&lpf2Config, &pLPF->lpf2[ilpf2]);
31032  } else {
31033  result = ma_lpf2_reinit(&lpf2Config, &pLPF->lpf2[ilpf2]);
31034  }
31035 
31036  if (result != MA_SUCCESS) {
31037  return result;
31038  }
31039  }
31040 
31041  pLPF->lpf1Count = lpf1Count;
31042  pLPF->lpf2Count = lpf2Count;
31043  pLPF->format = pConfig->format;
31044  pLPF->channels = pConfig->channels;
31045 
31046  return MA_SUCCESS;
31047 }
31048 
31049 ma_result ma_lpf_init(const ma_lpf_config* pConfig, ma_lpf* pLPF)
31050 {
31051  if (pLPF == NULL) {
31052  return MA_INVALID_ARGS;
31053  }
31054 
31055  MA_ZERO_OBJECT(pLPF);
31056 
31057  if (pConfig == NULL) {
31058  return MA_INVALID_ARGS;
31059  }
31060 
31061  return ma_lpf_reinit__internal(pConfig, pLPF, /*isNew*/MA_TRUE);
31062 }
31063 
31064 ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF)
31065 {
31066  return ma_lpf_reinit__internal(pConfig, pLPF, /*isNew*/MA_FALSE);
31067 }
31068 
31069 static MA_INLINE void ma_lpf_process_pcm_frame_f32(ma_lpf* pLPF, float* pY, const void* pX)
31070 {
31071  ma_uint32 ilpf1;
31072  ma_uint32 ilpf2;
31073 
31074  MA_ASSERT(pLPF->format == ma_format_f32);
31075 
31076  MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels));
31077 
31078  for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) {
31079  ma_lpf1_process_pcm_frame_f32(&pLPF->lpf1[ilpf1], pY, pY);
31080  }
31081 
31082  for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) {
31083  ma_lpf2_process_pcm_frame_f32(&pLPF->lpf2[ilpf2], pY, pY);
31084  }
31085 }
31086 
31087 static MA_INLINE void ma_lpf_process_pcm_frame_s16(ma_lpf* pLPF, ma_int16* pY, const ma_int16* pX)
31088 {
31089  ma_uint32 ilpf1;
31090  ma_uint32 ilpf2;
31091 
31092  MA_ASSERT(pLPF->format == ma_format_s16);
31093 
31094  MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels));
31095 
31096  for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) {
31097  ma_lpf1_process_pcm_frame_s16(&pLPF->lpf1[ilpf1], pY, pY);
31098  }
31099 
31100  for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) {
31101  ma_lpf2_process_pcm_frame_s16(&pLPF->lpf2[ilpf2], pY, pY);
31102  }
31103 }
31104 
31105 ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
31106 {
31107  ma_result result;
31108  ma_uint32 ilpf1;
31109  ma_uint32 ilpf2;
31110 
31111  if (pLPF == NULL) {
31112  return MA_INVALID_ARGS;
31113  }
31114 
31115  /* Faster path for in-place. */
31116  if (pFramesOut == pFramesIn) {
31117  for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) {
31118  result = ma_lpf1_process_pcm_frames(&pLPF->lpf1[ilpf1], pFramesOut, pFramesOut, frameCount);
31119  if (result != MA_SUCCESS) {
31120  return result;
31121  }
31122  }
31123 
31124  for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) {
31125  result = ma_lpf2_process_pcm_frames(&pLPF->lpf2[ilpf2], pFramesOut, pFramesOut, frameCount);
31126  if (result != MA_SUCCESS) {
31127  return result;
31128  }
31129  }
31130  }
31131 
31132  /* Slightly slower path for copying. */
31133  if (pFramesOut != pFramesIn) {
31134  ma_uint32 iFrame;
31135 
31136  /* */ if (pLPF->format == ma_format_f32) {
31137  /* */ float* pFramesOutF32 = ( float*)pFramesOut;
31138  const float* pFramesInF32 = (const float*)pFramesIn;
31139 
31140  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
31141  ma_lpf_process_pcm_frame_f32(pLPF, pFramesOutF32, pFramesInF32);
31142  pFramesOutF32 += pLPF->channels;
31143  pFramesInF32 += pLPF->channels;
31144  }
31145  } else if (pLPF->format == ma_format_s16) {
31146  /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut;
31147  const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn;
31148 
31149  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
31150  ma_lpf_process_pcm_frame_s16(pLPF, pFramesOutS16, pFramesInS16);
31151  pFramesOutS16 += pLPF->channels;
31152  pFramesInS16 += pLPF->channels;
31153  }
31154  } else {
31156  return MA_INVALID_OPERATION; /* Should never hit this. */
31157  }
31158  }
31159 
31160  return MA_SUCCESS;
31161 }
31162 
31164 {
31165  if (pLPF == NULL) {
31166  return 0;
31167  }
31168 
31169  return pLPF->lpf2Count*2 + pLPF->lpf1Count;
31170 }
31171 
31172 
31173 /**************************************************************************************************************************************************************
31174 
31175 High-Pass Filtering
31176 
31177 **************************************************************************************************************************************************************/
31178 ma_hpf1_config ma_hpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency)
31179 {
31181 
31183  config.format = format;
31184  config.channels = channels;
31185  config.sampleRate = sampleRate;
31186  config.cutoffFrequency = cutoffFrequency;
31187 
31188  return config;
31189 }
31190 
31191 ma_hpf2_config ma_hpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
31192 {
31194 
31196  config.format = format;
31197  config.channels = channels;
31198  config.sampleRate = sampleRate;
31199  config.cutoffFrequency = cutoffFrequency;
31200  config.q = q;
31201 
31202  /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */
31203  if (config.q == 0) {
31204  config.q = 0.707107;
31205  }
31206 
31207  return config;
31208 }
31209 
31210 
31211 ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, ma_hpf1* pHPF)
31212 {
31213  if (pHPF == NULL) {
31214  return MA_INVALID_ARGS;
31215  }
31216 
31217  MA_ZERO_OBJECT(pHPF);
31218 
31219  if (pConfig == NULL) {
31220  return MA_INVALID_ARGS;
31221  }
31222 
31223  return ma_hpf1_reinit(pConfig, pHPF);
31224 }
31225 
31226 ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF)
31227 {
31228  double a;
31229 
31230  if (pHPF == NULL || pConfig == NULL) {
31231  return MA_INVALID_ARGS;
31232  }
31233 
31234  /* Only supporting f32 and s16. */
31235  if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
31236  return MA_INVALID_ARGS;
31237  }
31238 
31239  /* The format cannot be changed after initialization. */
31240  if (pHPF->format != ma_format_unknown && pHPF->format != pConfig->format) {
31241  return MA_INVALID_OPERATION;
31242  }
31243 
31244  /* The channel count cannot be changed after initialization. */
31245  if (pHPF->channels != 0 && pHPF->channels != pConfig->channels) {
31246  return MA_INVALID_OPERATION;
31247  }
31248 
31249  pHPF->format = pConfig->format;
31250  pHPF->channels = pConfig->channels;
31251 
31252  a = ma_exp(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate);
31253  if (pConfig->format == ma_format_f32) {
31254  pHPF->a.f32 = (float)a;
31255  } else {
31256  pHPF->a.s32 = ma_biquad_float_to_fp(a);
31257  }
31258 
31259  return MA_SUCCESS;
31260 }
31261 
31262 static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1* pHPF, float* pY, const float* pX)
31263 {
31264  ma_uint32 c;
31265  const float a = 1 - pHPF->a.f32;
31266  const float b = 1 - a;
31267 
31268  for (c = 0; c < pHPF->channels; c += 1) {
31269  float r1 = pHPF->r1[c].f32;
31270  float x = pX[c];
31271  float y;
31272 
31273  y = b*x - a*r1;
31274 
31275  pY[c] = y;
31276  pHPF->r1[c].f32 = y;
31277  }
31278 }
31279 
31280 static MA_INLINE void ma_hpf1_process_pcm_frame_s16(ma_hpf1* pHPF, ma_int16* pY, const ma_int16* pX)
31281 {
31282  ma_uint32 c;
31283  const ma_int32 a = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - pHPF->a.s32);
31284  const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a);
31285 
31286  for (c = 0; c < pHPF->channels; c += 1) {
31287  ma_int32 r1 = pHPF->r1[c].s32;
31288  ma_int32 x = pX[c];
31289  ma_int32 y;
31290 
31291  y = (b*x - a*r1) >> MA_BIQUAD_FIXED_POINT_SHIFT;
31292 
31293  pY[c] = (ma_int16)y;
31294  pHPF->r1[c].s32 = (ma_int32)y;
31295  }
31296 }
31297 
31298 ma_result ma_hpf1_process_pcm_frames(ma_hpf1* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
31299 {
31300  ma_uint32 n;
31301 
31302  if (pHPF == NULL || pFramesOut == NULL || pFramesIn == NULL) {
31303  return MA_INVALID_ARGS;
31304  }
31305 
31306  /* Note that the logic below needs to support in-place filtering. That is, it must support the case where pFramesOut and pFramesIn are the same. */
31307 
31308  if (pHPF->format == ma_format_f32) {
31309  /* */ float* pY = ( float*)pFramesOut;
31310  const float* pX = (const float*)pFramesIn;
31311 
31312  for (n = 0; n < frameCount; n += 1) {
31313  ma_hpf1_process_pcm_frame_f32(pHPF, pY, pX);
31314  pY += pHPF->channels;
31315  pX += pHPF->channels;
31316  }
31317  } else if (pHPF->format == ma_format_s16) {
31318  /* */ ma_int16* pY = ( ma_int16*)pFramesOut;
31319  const ma_int16* pX = (const ma_int16*)pFramesIn;
31320 
31321  for (n = 0; n < frameCount; n += 1) {
31322  ma_hpf1_process_pcm_frame_s16(pHPF, pY, pX);
31323  pY += pHPF->channels;
31324  pX += pHPF->channels;
31325  }
31326  } else {
31328  return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */
31329  }
31330 
31331  return MA_SUCCESS;
31332 }
31333 
31335 {
31336  if (pHPF == NULL) {
31337  return 0;
31338  }
31339 
31340  return 1;
31341 }
31342 
31343 
31345 {
31346  ma_biquad_config bqConfig;
31347  double q;
31348  double w;
31349  double s;
31350  double c;
31351  double a;
31352 
31353  MA_ASSERT(pConfig != NULL);
31354 
31355  q = pConfig->q;
31356  w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
31357  s = ma_sin(w);
31358  c = ma_cos(w);
31359  a = s / (2*q);
31360 
31361  bqConfig.b0 = (1 + c) / 2;
31362  bqConfig.b1 = -(1 + c);
31363  bqConfig.b2 = (1 + c) / 2;
31364  bqConfig.a0 = 1 + a;
31365  bqConfig.a1 = -2 * c;
31366  bqConfig.a2 = 1 - a;
31367 
31368  bqConfig.format = pConfig->format;
31369  bqConfig.channels = pConfig->channels;
31370 
31371  return bqConfig;
31372 }
31373 
31374 ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, ma_hpf2* pHPF)
31375 {
31376  ma_result result;
31377  ma_biquad_config bqConfig;
31378 
31379  if (pHPF == NULL) {
31380  return MA_INVALID_ARGS;
31381  }
31382 
31383  MA_ZERO_OBJECT(pHPF);
31384 
31385  if (pConfig == NULL) {
31386  return MA_INVALID_ARGS;
31387  }
31388 
31389  bqConfig = ma_hpf2__get_biquad_config(pConfig);
31390  result = ma_biquad_init(&bqConfig, &pHPF->bq);
31391  if (result != MA_SUCCESS) {
31392  return result;
31393  }
31394 
31395  return MA_SUCCESS;
31396 }
31397 
31398 ma_result ma_hpf2_reinit(const ma_hpf2_config* pConfig, ma_hpf2* pHPF)
31399 {
31400  ma_result result;
31401  ma_biquad_config bqConfig;
31402 
31403  if (pHPF == NULL || pConfig == NULL) {
31404  return MA_INVALID_ARGS;
31405  }
31406 
31407  bqConfig = ma_hpf2__get_biquad_config(pConfig);
31408  result = ma_biquad_reinit(&bqConfig, &pHPF->bq);
31409  if (result != MA_SUCCESS) {
31410  return result;
31411  }
31412 
31413  return MA_SUCCESS;
31414 }
31415 
31416 static MA_INLINE void ma_hpf2_process_pcm_frame_s16(ma_hpf2* pHPF, ma_int16* pFrameOut, const ma_int16* pFrameIn)
31417 {
31418  ma_biquad_process_pcm_frame_s16(&pHPF->bq, pFrameOut, pFrameIn);
31419 }
31420 
31421 static MA_INLINE void ma_hpf2_process_pcm_frame_f32(ma_hpf2* pHPF, float* pFrameOut, const float* pFrameIn)
31422 {
31423  ma_biquad_process_pcm_frame_f32(&pHPF->bq, pFrameOut, pFrameIn);
31424 }
31425 
31426 ma_result ma_hpf2_process_pcm_frames(ma_hpf2* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
31427 {
31428  if (pHPF == NULL) {
31429  return MA_INVALID_ARGS;
31430  }
31431 
31432  return ma_biquad_process_pcm_frames(&pHPF->bq, pFramesOut, pFramesIn, frameCount);
31433 }
31434 
31436 {
31437  if (pHPF == NULL) {
31438  return 0;
31439  }
31440 
31441  return ma_biquad_get_latency(&pHPF->bq);
31442 }
31443 
31444 
31445 ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
31446 {
31448 
31450  config.format = format;
31451  config.channels = channels;
31452  config.sampleRate = sampleRate;
31453  config.cutoffFrequency = cutoffFrequency;
31454  config.order = ma_min(order, MA_MAX_FILTER_ORDER);
31455 
31456  return config;
31457 }
31458 
31459 static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, ma_hpf* pHPF, ma_bool32 isNew)
31460 {
31461  ma_result result;
31462  ma_uint32 hpf1Count;
31463  ma_uint32 hpf2Count;
31464  ma_uint32 ihpf1;
31465  ma_uint32 ihpf2;
31466 
31467  if (pHPF == NULL || pConfig == NULL) {
31468  return MA_INVALID_ARGS;
31469  }
31470 
31471  /* Only supporting f32 and s16. */
31472  if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
31473  return MA_INVALID_ARGS;
31474  }
31475 
31476  /* The format cannot be changed after initialization. */
31477  if (pHPF->format != ma_format_unknown && pHPF->format != pConfig->format) {
31478  return MA_INVALID_OPERATION;
31479  }
31480 
31481  /* The channel count cannot be changed after initialization. */
31482  if (pHPF->channels != 0 && pHPF->channels != pConfig->channels) {
31483  return MA_INVALID_OPERATION;
31484  }
31485 
31486  if (pConfig->order > MA_MAX_FILTER_ORDER) {
31487  return MA_INVALID_ARGS;
31488  }
31489 
31490  hpf1Count = pConfig->order % 2;
31491  hpf2Count = pConfig->order / 2;
31492 
31493  MA_ASSERT(hpf1Count <= ma_countof(pHPF->hpf1));
31494  MA_ASSERT(hpf2Count <= ma_countof(pHPF->hpf2));
31495 
31496  /* The filter order can't change between reinits. */
31497  if (!isNew) {
31498  if (pHPF->hpf1Count != hpf1Count || pHPF->hpf2Count != hpf2Count) {
31499  return MA_INVALID_OPERATION;
31500  }
31501  }
31502 
31503  for (ihpf1 = 0; ihpf1 < hpf1Count; ihpf1 += 1) {
31504  ma_hpf1_config hpf1Config = ma_hpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency);
31505 
31506  if (isNew) {
31507  result = ma_hpf1_init(&hpf1Config, &pHPF->hpf1[ihpf1]);
31508  } else {
31509  result = ma_hpf1_reinit(&hpf1Config, &pHPF->hpf1[ihpf1]);
31510  }
31511 
31512  if (result != MA_SUCCESS) {
31513  return result;
31514  }
31515  }
31516 
31517  for (ihpf2 = 0; ihpf2 < hpf2Count; ihpf2 += 1) {
31518  ma_hpf2_config hpf2Config;
31519  double q;
31520  double a;
31521 
31522  /* Tempting to use 0.707107, but won't result in a Butterworth filter if the order is > 2. */
31523  if (hpf1Count == 1) {
31524  a = (1 + ihpf2*1) * (MA_PI_D/(pConfig->order*1)); /* Odd order. */
31525  } else {
31526  a = (1 + ihpf2*2) * (MA_PI_D/(pConfig->order*2)); /* Even order. */
31527  }
31528  q = 1 / (2*ma_cos(a));
31529 
31530  hpf2Config = ma_hpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q);
31531 
31532  if (isNew) {
31533  result = ma_hpf2_init(&hpf2Config, &pHPF->hpf2[ihpf2]);
31534  } else {
31535  result = ma_hpf2_reinit(&hpf2Config, &pHPF->hpf2[ihpf2]);
31536  }
31537 
31538  if (result != MA_SUCCESS) {
31539  return result;
31540  }
31541  }
31542 
31543  pHPF->hpf1Count = hpf1Count;
31544  pHPF->hpf2Count = hpf2Count;
31545  pHPF->format = pConfig->format;
31546  pHPF->channels = pConfig->channels;
31547 
31548  return MA_SUCCESS;
31549 }
31550 
31551 ma_result ma_hpf_init(const ma_hpf_config* pConfig, ma_hpf* pHPF)
31552 {
31553  if (pHPF == NULL) {
31554  return MA_INVALID_ARGS;
31555  }
31556 
31557  MA_ZERO_OBJECT(pHPF);
31558 
31559  if (pConfig == NULL) {
31560  return MA_INVALID_ARGS;
31561  }
31562 
31563  return ma_hpf_reinit__internal(pConfig, pHPF, /*isNew*/MA_TRUE);
31564 }
31565 
31566 ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF)
31567 {
31568  return ma_hpf_reinit__internal(pConfig, pHPF, /*isNew*/MA_FALSE);
31569 }
31570 
31571 ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
31572 {
31573  ma_result result;
31574  ma_uint32 ihpf1;
31575  ma_uint32 ihpf2;
31576 
31577  if (pHPF == NULL) {
31578  return MA_INVALID_ARGS;
31579  }
31580 
31581  /* Faster path for in-place. */
31582  if (pFramesOut == pFramesIn) {
31583  for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) {
31584  result = ma_hpf1_process_pcm_frames(&pHPF->hpf1[ihpf1], pFramesOut, pFramesOut, frameCount);
31585  if (result != MA_SUCCESS) {
31586  return result;
31587  }
31588  }
31589 
31590  for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) {
31591  result = ma_hpf2_process_pcm_frames(&pHPF->hpf2[ihpf2], pFramesOut, pFramesOut, frameCount);
31592  if (result != MA_SUCCESS) {
31593  return result;
31594  }
31595  }
31596  }
31597 
31598  /* Slightly slower path for copying. */
31599  if (pFramesOut != pFramesIn) {
31600  ma_uint32 iFrame;
31601 
31602  /* */ if (pHPF->format == ma_format_f32) {
31603  /* */ float* pFramesOutF32 = ( float*)pFramesOut;
31604  const float* pFramesInF32 = (const float*)pFramesIn;
31605 
31606  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
31607  MA_COPY_MEMORY(pFramesOutF32, pFramesInF32, ma_get_bytes_per_frame(pHPF->format, pHPF->channels));
31608 
31609  for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) {
31610  ma_hpf1_process_pcm_frame_f32(&pHPF->hpf1[ihpf1], pFramesOutF32, pFramesOutF32);
31611  }
31612 
31613  for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) {
31614  ma_hpf2_process_pcm_frame_f32(&pHPF->hpf2[ihpf2], pFramesOutF32, pFramesOutF32);
31615  }
31616 
31617  pFramesOutF32 += pHPF->channels;
31618  pFramesInF32 += pHPF->channels;
31619  }
31620  } else if (pHPF->format == ma_format_s16) {
31621  /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut;
31622  const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn;
31623 
31624  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
31625  MA_COPY_MEMORY(pFramesOutS16, pFramesInS16, ma_get_bytes_per_frame(pHPF->format, pHPF->channels));
31626 
31627  for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) {
31628  ma_hpf1_process_pcm_frame_s16(&pHPF->hpf1[ihpf1], pFramesOutS16, pFramesOutS16);
31629  }
31630 
31631  for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) {
31632  ma_hpf2_process_pcm_frame_s16(&pHPF->hpf2[ihpf2], pFramesOutS16, pFramesOutS16);
31633  }
31634 
31635  pFramesOutS16 += pHPF->channels;
31636  pFramesInS16 += pHPF->channels;
31637  }
31638  } else {
31640  return MA_INVALID_OPERATION; /* Should never hit this. */
31641  }
31642  }
31643 
31644  return MA_SUCCESS;
31645 }
31646 
31648 {
31649  if (pHPF == NULL) {
31650  return 0;
31651  }
31652 
31653  return pHPF->hpf2Count*2 + pHPF->hpf1Count;
31654 }
31655 
31656 
31657 /**************************************************************************************************************************************************************
31658 
31659 Band-Pass Filtering
31660 
31661 **************************************************************************************************************************************************************/
31662 ma_bpf2_config ma_bpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
31663 {
31665 
31667  config.format = format;
31668  config.channels = channels;
31669  config.sampleRate = sampleRate;
31670  config.cutoffFrequency = cutoffFrequency;
31671  config.q = q;
31672 
31673  /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */
31674  if (config.q == 0) {
31675  config.q = 0.707107;
31676  }
31677 
31678  return config;
31679 }
31680 
31681 
31683 {
31684  ma_biquad_config bqConfig;
31685  double q;
31686  double w;
31687  double s;
31688  double c;
31689  double a;
31690 
31691  MA_ASSERT(pConfig != NULL);
31692 
31693  q = pConfig->q;
31694  w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
31695  s = ma_sin(w);
31696  c = ma_cos(w);
31697  a = s / (2*q);
31698 
31699  bqConfig.b0 = q * a;
31700  bqConfig.b1 = 0;
31701  bqConfig.b2 = -q * a;
31702  bqConfig.a0 = 1 + a;
31703  bqConfig.a1 = -2 * c;
31704  bqConfig.a2 = 1 - a;
31705 
31706  bqConfig.format = pConfig->format;
31707  bqConfig.channels = pConfig->channels;
31708 
31709  return bqConfig;
31710 }
31711 
31712 ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, ma_bpf2* pBPF)
31713 {
31714  ma_result result;
31715  ma_biquad_config bqConfig;
31716 
31717  if (pBPF == NULL) {
31718  return MA_INVALID_ARGS;
31719  }
31720 
31721  MA_ZERO_OBJECT(pBPF);
31722 
31723  if (pConfig == NULL) {
31724  return MA_INVALID_ARGS;
31725  }
31726 
31727  bqConfig = ma_bpf2__get_biquad_config(pConfig);
31728  result = ma_biquad_init(&bqConfig, &pBPF->bq);
31729  if (result != MA_SUCCESS) {
31730  return result;
31731  }
31732 
31733  return MA_SUCCESS;
31734 }
31735 
31736 ma_result ma_bpf2_reinit(const ma_bpf2_config* pConfig, ma_bpf2* pBPF)
31737 {
31738  ma_result result;
31739  ma_biquad_config bqConfig;
31740 
31741  if (pBPF == NULL || pConfig == NULL) {
31742  return MA_INVALID_ARGS;
31743  }
31744 
31745  bqConfig = ma_bpf2__get_biquad_config(pConfig);
31746  result = ma_biquad_reinit(&bqConfig, &pBPF->bq);
31747  if (result != MA_SUCCESS) {
31748  return result;
31749  }
31750 
31751  return MA_SUCCESS;
31752 }
31753 
31754 static MA_INLINE void ma_bpf2_process_pcm_frame_s16(ma_bpf2* pBPF, ma_int16* pFrameOut, const ma_int16* pFrameIn)
31755 {
31756  ma_biquad_process_pcm_frame_s16(&pBPF->bq, pFrameOut, pFrameIn);
31757 }
31758 
31759 static MA_INLINE void ma_bpf2_process_pcm_frame_f32(ma_bpf2* pBPF, float* pFrameOut, const float* pFrameIn)
31760 {
31761  ma_biquad_process_pcm_frame_f32(&pBPF->bq, pFrameOut, pFrameIn);
31762 }
31763 
31764 ma_result ma_bpf2_process_pcm_frames(ma_bpf2* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
31765 {
31766  if (pBPF == NULL) {
31767  return MA_INVALID_ARGS;
31768  }
31769 
31770  return ma_biquad_process_pcm_frames(&pBPF->bq, pFramesOut, pFramesIn, frameCount);
31771 }
31772 
31774 {
31775  if (pBPF == NULL) {
31776  return 0;
31777  }
31778 
31779  return ma_biquad_get_latency(&pBPF->bq);
31780 }
31781 
31782 
31783 ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
31784 {
31786 
31788  config.format = format;
31789  config.channels = channels;
31790  config.sampleRate = sampleRate;
31791  config.cutoffFrequency = cutoffFrequency;
31792  config.order = ma_min(order, MA_MAX_FILTER_ORDER);
31793 
31794  return config;
31795 }
31796 
31797 static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, ma_bpf* pBPF, ma_bool32 isNew)
31798 {
31799  ma_result result;
31800  ma_uint32 bpf2Count;
31801  ma_uint32 ibpf2;
31802 
31803  if (pBPF == NULL || pConfig == NULL) {
31804  return MA_INVALID_ARGS;
31805  }
31806 
31807  /* Only supporting f32 and s16. */
31808  if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
31809  return MA_INVALID_ARGS;
31810  }
31811 
31812  /* The format cannot be changed after initialization. */
31813  if (pBPF->format != ma_format_unknown && pBPF->format != pConfig->format) {
31814  return MA_INVALID_OPERATION;
31815  }
31816 
31817  /* The channel count cannot be changed after initialization. */
31818  if (pBPF->channels != 0 && pBPF->channels != pConfig->channels) {
31819  return MA_INVALID_OPERATION;
31820  }
31821 
31822  if (pConfig->order > MA_MAX_FILTER_ORDER) {
31823  return MA_INVALID_ARGS;
31824  }
31825 
31826  /* We must have an even number of order. */
31827  if ((pConfig->order & 0x1) != 0) {
31828  return MA_INVALID_ARGS;
31829  }
31830 
31831  bpf2Count = pConfig->order / 2;
31832 
31833  MA_ASSERT(bpf2Count <= ma_countof(pBPF->bpf2));
31834 
31835  /* The filter order can't change between reinits. */
31836  if (!isNew) {
31837  if (pBPF->bpf2Count != bpf2Count) {
31838  return MA_INVALID_OPERATION;
31839  }
31840  }
31841 
31842  for (ibpf2 = 0; ibpf2 < bpf2Count; ibpf2 += 1) {
31843  ma_bpf2_config bpf2Config;
31844  double q;
31845 
31846  /* TODO: Calculate Q to make this a proper Butterworth filter. */
31847  q = 0.707107;
31848 
31849  bpf2Config = ma_bpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q);
31850 
31851  if (isNew) {
31852  result = ma_bpf2_init(&bpf2Config, &pBPF->bpf2[ibpf2]);
31853  } else {
31854  result = ma_bpf2_reinit(&bpf2Config, &pBPF->bpf2[ibpf2]);
31855  }
31856 
31857  if (result != MA_SUCCESS) {
31858  return result;
31859  }
31860  }
31861 
31862  pBPF->bpf2Count = bpf2Count;
31863  pBPF->format = pConfig->format;
31864  pBPF->channels = pConfig->channels;
31865 
31866  return MA_SUCCESS;
31867 }
31868 
31869 ma_result ma_bpf_init(const ma_bpf_config* pConfig, ma_bpf* pBPF)
31870 {
31871  if (pBPF == NULL) {
31872  return MA_INVALID_ARGS;
31873  }
31874 
31875  MA_ZERO_OBJECT(pBPF);
31876 
31877  if (pConfig == NULL) {
31878  return MA_INVALID_ARGS;
31879  }
31880 
31881  return ma_bpf_reinit__internal(pConfig, pBPF, /*isNew*/MA_TRUE);
31882 }
31883 
31884 ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF)
31885 {
31886  return ma_bpf_reinit__internal(pConfig, pBPF, /*isNew*/MA_FALSE);
31887 }
31888 
31889 ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
31890 {
31891  ma_result result;
31892  ma_uint32 ibpf2;
31893 
31894  if (pBPF == NULL) {
31895  return MA_INVALID_ARGS;
31896  }
31897 
31898  /* Faster path for in-place. */
31899  if (pFramesOut == pFramesIn) {
31900  for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) {
31901  result = ma_bpf2_process_pcm_frames(&pBPF->bpf2[ibpf2], pFramesOut, pFramesOut, frameCount);
31902  if (result != MA_SUCCESS) {
31903  return result;
31904  }
31905  }
31906  }
31907 
31908  /* Slightly slower path for copying. */
31909  if (pFramesOut != pFramesIn) {
31910  ma_uint32 iFrame;
31911 
31912  /* */ if (pBPF->format == ma_format_f32) {
31913  /* */ float* pFramesOutF32 = ( float*)pFramesOut;
31914  const float* pFramesInF32 = (const float*)pFramesIn;
31915 
31916  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
31917  MA_COPY_MEMORY(pFramesOutF32, pFramesInF32, ma_get_bytes_per_frame(pBPF->format, pBPF->channels));
31918 
31919  for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) {
31920  ma_bpf2_process_pcm_frame_f32(&pBPF->bpf2[ibpf2], pFramesOutF32, pFramesOutF32);
31921  }
31922 
31923  pFramesOutF32 += pBPF->channels;
31924  pFramesInF32 += pBPF->channels;
31925  }
31926  } else if (pBPF->format == ma_format_s16) {
31927  /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut;
31928  const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn;
31929 
31930  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
31931  MA_COPY_MEMORY(pFramesOutS16, pFramesInS16, ma_get_bytes_per_frame(pBPF->format, pBPF->channels));
31932 
31933  for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) {
31934  ma_bpf2_process_pcm_frame_s16(&pBPF->bpf2[ibpf2], pFramesOutS16, pFramesOutS16);
31935  }
31936 
31937  pFramesOutS16 += pBPF->channels;
31938  pFramesInS16 += pBPF->channels;
31939  }
31940  } else {
31942  return MA_INVALID_OPERATION; /* Should never hit this. */
31943  }
31944  }
31945 
31946  return MA_SUCCESS;
31947 }
31948 
31950 {
31951  if (pBPF == NULL) {
31952  return 0;
31953  }
31954 
31955  return pBPF->bpf2Count*2;
31956 }
31957 
31958 
31959 /**************************************************************************************************************************************************************
31960 
31961 Notching Filter
31962 
31963 **************************************************************************************************************************************************************/
31964 ma_notch2_config ma_notch2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency)
31965 {
31967 
31969  config.format = format;
31970  config.channels = channels;
31971  config.sampleRate = sampleRate;
31972  config.q = q;
31973  config.frequency = frequency;
31974 
31975  if (config.q == 0) {
31976  config.q = 0.707107;
31977  }
31978 
31979  return config;
31980 }
31981 
31982 
31984 {
31985  ma_biquad_config bqConfig;
31986  double q;
31987  double w;
31988  double s;
31989  double c;
31990  double a;
31991 
31992  MA_ASSERT(pConfig != NULL);
31993 
31994  q = pConfig->q;
31995  w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
31996  s = ma_sin(w);
31997  c = ma_cos(w);
31998  a = s / (2*q);
31999 
32000  bqConfig.b0 = 1;
32001  bqConfig.b1 = -2 * c;
32002  bqConfig.b2 = 1;
32003  bqConfig.a0 = 1 + a;
32004  bqConfig.a1 = -2 * c;
32005  bqConfig.a2 = 1 - a;
32006 
32007  bqConfig.format = pConfig->format;
32008  bqConfig.channels = pConfig->channels;
32009 
32010  return bqConfig;
32011 }
32012 
32013 ma_result ma_notch2_init(const ma_notch2_config* pConfig, ma_notch2* pFilter)
32014 {
32015  ma_result result;
32016  ma_biquad_config bqConfig;
32017 
32018  if (pFilter == NULL) {
32019  return MA_INVALID_ARGS;
32020  }
32021 
32022  MA_ZERO_OBJECT(pFilter);
32023 
32024  if (pConfig == NULL) {
32025  return MA_INVALID_ARGS;
32026  }
32027 
32028  bqConfig = ma_notch2__get_biquad_config(pConfig);
32029  result = ma_biquad_init(&bqConfig, &pFilter->bq);
32030  if (result != MA_SUCCESS) {
32031  return result;
32032  }
32033 
32034  return MA_SUCCESS;
32035 }
32036 
32037 ma_result ma_notch2_reinit(const ma_notch2_config* pConfig, ma_notch2* pFilter)
32038 {
32039  ma_result result;
32040  ma_biquad_config bqConfig;
32041 
32042  if (pFilter == NULL || pConfig == NULL) {
32043  return MA_INVALID_ARGS;
32044  }
32045 
32046  bqConfig = ma_notch2__get_biquad_config(pConfig);
32047  result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
32048  if (result != MA_SUCCESS) {
32049  return result;
32050  }
32051 
32052  return MA_SUCCESS;
32053 }
32054 
32055 static MA_INLINE void ma_notch2_process_pcm_frame_s16(ma_notch2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
32056 {
32057  ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
32058 }
32059 
32060 static MA_INLINE void ma_notch2_process_pcm_frame_f32(ma_notch2* pFilter, float* pFrameOut, const float* pFrameIn)
32061 {
32062  ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
32063 }
32064 
32065 ma_result ma_notch2_process_pcm_frames(ma_notch2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
32066 {
32067  if (pFilter == NULL) {
32068  return MA_INVALID_ARGS;
32069  }
32070 
32071  return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
32072 }
32073 
32075 {
32076  if (pFilter == NULL) {
32077  return 0;
32078  }
32079 
32080  return ma_biquad_get_latency(&pFilter->bq);
32081 }
32082 
32083 
32084 
32085 /**************************************************************************************************************************************************************
32086 
32087 Peaking EQ Filter
32088 
32089 **************************************************************************************************************************************************************/
32090 ma_peak2_config ma_peak2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency)
32091 {
32093 
32095  config.format = format;
32096  config.channels = channels;
32097  config.sampleRate = sampleRate;
32098  config.gainDB = gainDB;
32099  config.q = q;
32100  config.frequency = frequency;
32101 
32102  if (config.q == 0) {
32103  config.q = 0.707107;
32104  }
32105 
32106  return config;
32107 }
32108 
32109 
32111 {
32112  ma_biquad_config bqConfig;
32113  double q;
32114  double w;
32115  double s;
32116  double c;
32117  double a;
32118  double A;
32119 
32120  MA_ASSERT(pConfig != NULL);
32121 
32122  q = pConfig->q;
32123  w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
32124  s = ma_sin(w);
32125  c = ma_cos(w);
32126  a = s / (2*q);
32127  A = ma_pow(10, (pConfig->gainDB / 40));
32128 
32129  bqConfig.b0 = 1 + (a * A);
32130  bqConfig.b1 = -2 * c;
32131  bqConfig.b2 = 1 - (a * A);
32132  bqConfig.a0 = 1 + (a / A);
32133  bqConfig.a1 = -2 * c;
32134  bqConfig.a2 = 1 - (a / A);
32135 
32136  bqConfig.format = pConfig->format;
32137  bqConfig.channels = pConfig->channels;
32138 
32139  return bqConfig;
32140 }
32141 
32142 ma_result ma_peak2_init(const ma_peak2_config* pConfig, ma_peak2* pFilter)
32143 {
32144  ma_result result;
32145  ma_biquad_config bqConfig;
32146 
32147  if (pFilter == NULL) {
32148  return MA_INVALID_ARGS;
32149  }
32150 
32151  MA_ZERO_OBJECT(pFilter);
32152 
32153  if (pConfig == NULL) {
32154  return MA_INVALID_ARGS;
32155  }
32156 
32157  bqConfig = ma_peak2__get_biquad_config(pConfig);
32158  result = ma_biquad_init(&bqConfig, &pFilter->bq);
32159  if (result != MA_SUCCESS) {
32160  return result;
32161  }
32162 
32163  return MA_SUCCESS;
32164 }
32165 
32166 ma_result ma_peak2_reinit(const ma_peak2_config* pConfig, ma_peak2* pFilter)
32167 {
32168  ma_result result;
32169  ma_biquad_config bqConfig;
32170 
32171  if (pFilter == NULL || pConfig == NULL) {
32172  return MA_INVALID_ARGS;
32173  }
32174 
32175  bqConfig = ma_peak2__get_biquad_config(pConfig);
32176  result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
32177  if (result != MA_SUCCESS) {
32178  return result;
32179  }
32180 
32181  return MA_SUCCESS;
32182 }
32183 
32184 static MA_INLINE void ma_peak2_process_pcm_frame_s16(ma_peak2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
32185 {
32186  ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
32187 }
32188 
32189 static MA_INLINE void ma_peak2_process_pcm_frame_f32(ma_peak2* pFilter, float* pFrameOut, const float* pFrameIn)
32190 {
32191  ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
32192 }
32193 
32194 ma_result ma_peak2_process_pcm_frames(ma_peak2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
32195 {
32196  if (pFilter == NULL) {
32197  return MA_INVALID_ARGS;
32198  }
32199 
32200  return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
32201 }
32202 
32204 {
32205  if (pFilter == NULL) {
32206  return 0;
32207  }
32208 
32209  return ma_biquad_get_latency(&pFilter->bq);
32210 }
32211 
32212 
32213 /**************************************************************************************************************************************************************
32214 
32215 Low Shelf Filter
32216 
32217 **************************************************************************************************************************************************************/
32218 ma_loshelf2_config ma_loshelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency)
32219 {
32221 
32223  config.format = format;
32224  config.channels = channels;
32225  config.sampleRate = sampleRate;
32226  config.gainDB = gainDB;
32227  config.shelfSlope = shelfSlope;
32228  config.frequency = frequency;
32229 
32230  return config;
32231 }
32232 
32233 
32235 {
32236  ma_biquad_config bqConfig;
32237  double w;
32238  double s;
32239  double c;
32240  double A;
32241  double S;
32242  double a;
32243  double sqrtA;
32244 
32245  MA_ASSERT(pConfig != NULL);
32246 
32247  w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
32248  s = ma_sin(w);
32249  c = ma_cos(w);
32250  A = ma_pow(10, (pConfig->gainDB / 40));
32251  S = pConfig->shelfSlope;
32252  a = s/2 * ma_sqrt((A + 1/A) * (1/S - 1) + 2);
32253  sqrtA = 2*ma_sqrt(A)*a;
32254 
32255  bqConfig.b0 = A * ((A + 1) - (A - 1)*c + sqrtA);
32256  bqConfig.b1 = 2 * A * ((A - 1) - (A + 1)*c);
32257  bqConfig.b2 = A * ((A + 1) - (A - 1)*c - sqrtA);
32258  bqConfig.a0 = (A + 1) + (A - 1)*c + sqrtA;
32259  bqConfig.a1 = -2 * ((A - 1) + (A + 1)*c);
32260  bqConfig.a2 = (A + 1) + (A - 1)*c - sqrtA;
32261 
32262  bqConfig.format = pConfig->format;
32263  bqConfig.channels = pConfig->channels;
32264 
32265  return bqConfig;
32266 }
32267 
32268 ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter)
32269 {
32270  ma_result result;
32271  ma_biquad_config bqConfig;
32272 
32273  if (pFilter == NULL) {
32274  return MA_INVALID_ARGS;
32275  }
32276 
32277  MA_ZERO_OBJECT(pFilter);
32278 
32279  if (pConfig == NULL) {
32280  return MA_INVALID_ARGS;
32281  }
32282 
32283  bqConfig = ma_loshelf2__get_biquad_config(pConfig);
32284  result = ma_biquad_init(&bqConfig, &pFilter->bq);
32285  if (result != MA_SUCCESS) {
32286  return result;
32287  }
32288 
32289  return MA_SUCCESS;
32290 }
32291 
32293 {
32294  ma_result result;
32295  ma_biquad_config bqConfig;
32296 
32297  if (pFilter == NULL || pConfig == NULL) {
32298  return MA_INVALID_ARGS;
32299  }
32300 
32301  bqConfig = ma_loshelf2__get_biquad_config(pConfig);
32302  result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
32303  if (result != MA_SUCCESS) {
32304  return result;
32305  }
32306 
32307  return MA_SUCCESS;
32308 }
32309 
32310 static MA_INLINE void ma_loshelf2_process_pcm_frame_s16(ma_loshelf2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
32311 {
32312  ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
32313 }
32314 
32315 static MA_INLINE void ma_loshelf2_process_pcm_frame_f32(ma_loshelf2* pFilter, float* pFrameOut, const float* pFrameIn)
32316 {
32317  ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
32318 }
32319 
32320 ma_result ma_loshelf2_process_pcm_frames(ma_loshelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
32321 {
32322  if (pFilter == NULL) {
32323  return MA_INVALID_ARGS;
32324  }
32325 
32326  return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
32327 }
32328 
32330 {
32331  if (pFilter == NULL) {
32332  return 0;
32333  }
32334 
32335  return ma_biquad_get_latency(&pFilter->bq);
32336 }
32337 
32338 
32339 /**************************************************************************************************************************************************************
32340 
32341 High Shelf Filter
32342 
32343 **************************************************************************************************************************************************************/
32344 ma_hishelf2_config ma_hishelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency)
32345 {
32347 
32349  config.format = format;
32350  config.channels = channels;
32351  config.sampleRate = sampleRate;
32352  config.gainDB = gainDB;
32353  config.shelfSlope = shelfSlope;
32354  config.frequency = frequency;
32355 
32356  return config;
32357 }
32358 
32359 
32361 {
32362  ma_biquad_config bqConfig;
32363  double w;
32364  double s;
32365  double c;
32366  double A;
32367  double S;
32368  double a;
32369  double sqrtA;
32370 
32371  MA_ASSERT(pConfig != NULL);
32372 
32373  w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
32374  s = ma_sin(w);
32375  c = ma_cos(w);
32376  A = ma_pow(10, (pConfig->gainDB / 40));
32377  S = pConfig->shelfSlope;
32378  a = s/2 * ma_sqrt((A + 1/A) * (1/S - 1) + 2);
32379  sqrtA = 2*ma_sqrt(A)*a;
32380 
32381  bqConfig.b0 = A * ((A + 1) + (A - 1)*c + sqrtA);
32382  bqConfig.b1 = -2 * A * ((A - 1) + (A + 1)*c);
32383  bqConfig.b2 = A * ((A + 1) + (A - 1)*c - sqrtA);
32384  bqConfig.a0 = (A + 1) - (A - 1)*c + sqrtA;
32385  bqConfig.a1 = 2 * ((A - 1) - (A + 1)*c);
32386  bqConfig.a2 = (A + 1) - (A - 1)*c - sqrtA;
32387 
32388  bqConfig.format = pConfig->format;
32389  bqConfig.channels = pConfig->channels;
32390 
32391  return bqConfig;
32392 }
32393 
32394 ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter)
32395 {
32396  ma_result result;
32397  ma_biquad_config bqConfig;
32398 
32399  if (pFilter == NULL) {
32400  return MA_INVALID_ARGS;
32401  }
32402 
32403  MA_ZERO_OBJECT(pFilter);
32404 
32405  if (pConfig == NULL) {
32406  return MA_INVALID_ARGS;
32407  }
32408 
32409  bqConfig = ma_hishelf2__get_biquad_config(pConfig);
32410  result = ma_biquad_init(&bqConfig, &pFilter->bq);
32411  if (result != MA_SUCCESS) {
32412  return result;
32413  }
32414 
32415  return MA_SUCCESS;
32416 }
32417 
32419 {
32420  ma_result result;
32421  ma_biquad_config bqConfig;
32422 
32423  if (pFilter == NULL || pConfig == NULL) {
32424  return MA_INVALID_ARGS;
32425  }
32426 
32427  bqConfig = ma_hishelf2__get_biquad_config(pConfig);
32428  result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
32429  if (result != MA_SUCCESS) {
32430  return result;
32431  }
32432 
32433  return MA_SUCCESS;
32434 }
32435 
32436 static MA_INLINE void ma_hishelf2_process_pcm_frame_s16(ma_hishelf2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
32437 {
32438  ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
32439 }
32440 
32441 static MA_INLINE void ma_hishelf2_process_pcm_frame_f32(ma_hishelf2* pFilter, float* pFrameOut, const float* pFrameIn)
32442 {
32443  ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
32444 }
32445 
32446 ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
32447 {
32448  if (pFilter == NULL) {
32449  return MA_INVALID_ARGS;
32450  }
32451 
32452  return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
32453 }
32454 
32456 {
32457  if (pFilter == NULL) {
32458  return 0;
32459  }
32460 
32461  return ma_biquad_get_latency(&pFilter->bq);
32462 }
32463 
32464 
32465 
32466 /**************************************************************************************************************************************************************
32467 
32468 Resampling
32469 
32470 **************************************************************************************************************************************************************/
32472 {
32475  config.format = format;
32476  config.channels = channels;
32477  config.sampleRateIn = sampleRateIn;
32478  config.sampleRateOut = sampleRateOut;
32480  config.lpfNyquistFactor = 1;
32481 
32482  return config;
32483 }
32484 
32485 static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_bool32 isResamplerAlreadyInitialized)
32486 {
32487  ma_uint32 gcf;
32488 
32489  if (pResampler == NULL) {
32490  return MA_INVALID_ARGS;
32491  }
32492 
32493  if (sampleRateIn == 0 || sampleRateOut == 0) {
32494  return MA_INVALID_ARGS;
32495  }
32496 
32497  /* Simplify the sample rate. */
32498  gcf = ma_gcf_u32(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut);
32499  pResampler->config.sampleRateIn /= gcf;
32500  pResampler->config.sampleRateOut /= gcf;
32501 
32502  if (pResampler->config.lpfOrder > 0) {
32503  ma_result result;
32504  ma_uint32 lpfSampleRate;
32505  double lpfCutoffFrequency;
32506  ma_lpf_config lpfConfig;
32507 
32508  if (pResampler->config.lpfOrder > MA_MAX_FILTER_ORDER) {
32509  return MA_INVALID_ARGS;
32510  }
32511 
32512  lpfSampleRate = (ma_uint32)(ma_max(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut));
32513  lpfCutoffFrequency = ( double)(ma_min(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut) * 0.5 * pResampler->config.lpfNyquistFactor);
32514 
32515  lpfConfig = ma_lpf_config_init(pResampler->config.format, pResampler->config.channels, lpfSampleRate, lpfCutoffFrequency, pResampler->config.lpfOrder);
32516 
32517  /*
32518  If the resampler is alreay initialized we don't want to do a fresh initialization of the low-pass filter because it will result in the cached frames
32519  getting cleared. Instead we re-initialize the filter which will maintain any cached frames.
32520  */
32521  if (isResamplerAlreadyInitialized) {
32522  result = ma_lpf_reinit(&lpfConfig, &pResampler->lpf);
32523  } else {
32524  result = ma_lpf_init(&lpfConfig, &pResampler->lpf);
32525  }
32526 
32527  if (result != MA_SUCCESS) {
32528  return result;
32529  }
32530  }
32531 
32532  pResampler->inAdvanceInt = pResampler->config.sampleRateIn / pResampler->config.sampleRateOut;
32533  pResampler->inAdvanceFrac = pResampler->config.sampleRateIn % pResampler->config.sampleRateOut;
32534 
32535  /* Make sure the fractional part is less than the output sample rate. */
32536  pResampler->inTimeInt += pResampler->inTimeFrac / pResampler->config.sampleRateOut;
32537  pResampler->inTimeFrac = pResampler->inTimeFrac % pResampler->config.sampleRateOut;
32538 
32539  return MA_SUCCESS;
32540 }
32541 
32543 {
32544  ma_result result;
32545 
32546  if (pResampler == NULL) {
32547  return MA_INVALID_ARGS;
32548  }
32549 
32550  MA_ZERO_OBJECT(pResampler);
32551 
32552  if (pConfig == NULL) {
32553  return MA_INVALID_ARGS;
32554  }
32555 
32556  pResampler->config = *pConfig;
32557 
32558  /* Setting the rate will set up the filter and time advances for us. */
32559  result = ma_linear_resampler_set_rate_internal(pResampler, pConfig->sampleRateIn, pConfig->sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_FALSE);
32560  if (result != MA_SUCCESS) {
32561  return result;
32562  }
32563 
32564  pResampler->inTimeInt = 1; /* Set this to one to force an input sample to always be loaded for the first output frame. */
32565  pResampler->inTimeFrac = 0;
32566 
32567  return MA_SUCCESS;
32568 }
32569 
32571 {
32572  if (pResampler == NULL) {
32573  return;
32574  }
32575 }
32576 
32578 {
32579  ma_int32 b;
32580  ma_int32 c;
32581  ma_int32 r;
32582 
32583  MA_ASSERT(a <= (1<<shift));
32584 
32585  b = x * ((1<<shift) - a);
32586  c = y * a;
32587  r = b + c;
32588 
32589  return (ma_int16)(r >> shift);
32590 }
32591 
32592 static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResampler, ma_int16* pFrameOut)
32593 {
32594  ma_uint32 c;
32595  ma_uint32 a;
32596  const ma_uint32 shift = 12;
32597 
32598  MA_ASSERT(pResampler != NULL);
32599  MA_ASSERT(pFrameOut != NULL);
32600 
32601  a = (pResampler->inTimeFrac << shift) / pResampler->config.sampleRateOut;
32602 
32603  for (c = 0; c < pResampler->config.channels; c += 1) {
32604  ma_int16 s = ma_linear_resampler_mix_s16(pResampler->x0.s16[c], pResampler->x1.s16[c], a, shift);
32605  pFrameOut[c] = s;
32606  }
32607 }
32608 
32609 
32610 static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResampler, float* pFrameOut)
32611 {
32612  ma_uint32 c;
32613  float a;
32614 
32615  MA_ASSERT(pResampler != NULL);
32616  MA_ASSERT(pFrameOut != NULL);
32617 
32618  a = (float)pResampler->inTimeFrac / pResampler->config.sampleRateOut;
32619 
32620  for (c = 0; c < pResampler->config.channels; c += 1) {
32621  float s = ma_mix_f32_fast(pResampler->x0.f32[c], pResampler->x1.f32[c], a);
32622  pFrameOut[c] = s;
32623  }
32624 }
32625 
32626 static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
32627 {
32628  const ma_int16* pFramesInS16;
32629  /* */ ma_int16* pFramesOutS16;
32630  ma_uint64 frameCountIn;
32631  ma_uint64 frameCountOut;
32632  ma_uint64 framesProcessedIn;
32633  ma_uint64 framesProcessedOut;
32634 
32635  MA_ASSERT(pResampler != NULL);
32636  MA_ASSERT(pFrameCountIn != NULL);
32637  MA_ASSERT(pFrameCountOut != NULL);
32638 
32639  pFramesInS16 = (const ma_int16*)pFramesIn;
32640  pFramesOutS16 = ( ma_int16*)pFramesOut;
32641  frameCountIn = *pFrameCountIn;
32642  frameCountOut = *pFrameCountOut;
32643  framesProcessedIn = 0;
32644  framesProcessedOut = 0;
32645 
32646  for (;;) {
32647  if (framesProcessedOut >= frameCountOut) {
32648  break;
32649  }
32650 
32651  /* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */
32652  while (pResampler->inTimeInt > 0 && frameCountIn > 0) {
32653  ma_uint32 iChannel;
32654 
32655  if (pFramesInS16 != NULL) {
32656  for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
32657  pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
32658  pResampler->x1.s16[iChannel] = pFramesInS16[iChannel];
32659  }
32660  pFramesInS16 += pResampler->config.channels;
32661  } else {
32662  for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
32663  pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
32664  pResampler->x1.s16[iChannel] = 0;
32665  }
32666  }
32667 
32668  /* Filter. */
32669  ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pResampler->x1.s16, pResampler->x1.s16);
32670 
32671  frameCountIn -= 1;
32672  framesProcessedIn += 1;
32673  pResampler->inTimeInt -= 1;
32674  }
32675 
32676  if (pResampler->inTimeInt > 0) {
32677  break; /* Ran out of input data. */
32678  }
32679 
32680  /* Getting here means the frames have been loaded and filtered and we can generate the next output frame. */
32681  if (pFramesOutS16 != NULL) {
32682  MA_ASSERT(pResampler->inTimeInt == 0);
32683  ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16);
32684 
32685  pFramesOutS16 += pResampler->config.channels;
32686  }
32687 
32688  framesProcessedOut += 1;
32689 
32690  /* Advance time forward. */
32691  pResampler->inTimeInt += pResampler->inAdvanceInt;
32692  pResampler->inTimeFrac += pResampler->inAdvanceFrac;
32693  if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
32694  pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
32695  pResampler->inTimeInt += 1;
32696  }
32697  }
32698 
32699  *pFrameCountIn = framesProcessedIn;
32700  *pFrameCountOut = framesProcessedOut;
32701 
32702  return MA_SUCCESS;
32703 }
32704 
32705 static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
32706 {
32707  const ma_int16* pFramesInS16;
32708  /* */ ma_int16* pFramesOutS16;
32709  ma_uint64 frameCountIn;
32710  ma_uint64 frameCountOut;
32711  ma_uint64 framesProcessedIn;
32712  ma_uint64 framesProcessedOut;
32713 
32714  MA_ASSERT(pResampler != NULL);
32715  MA_ASSERT(pFrameCountIn != NULL);
32716  MA_ASSERT(pFrameCountOut != NULL);
32717 
32718  pFramesInS16 = (const ma_int16*)pFramesIn;
32719  pFramesOutS16 = ( ma_int16*)pFramesOut;
32720  frameCountIn = *pFrameCountIn;
32721  frameCountOut = *pFrameCountOut;
32722  framesProcessedIn = 0;
32723  framesProcessedOut = 0;
32724 
32725  for (;;) {
32726  if (framesProcessedOut >= frameCountOut) {
32727  break;
32728  }
32729 
32730  /* Before interpolating we need to load the buffers. */
32731  while (pResampler->inTimeInt > 0 && frameCountIn > 0) {
32732  ma_uint32 iChannel;
32733 
32734  if (pFramesInS16 != NULL) {
32735  for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
32736  pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
32737  pResampler->x1.s16[iChannel] = pFramesInS16[iChannel];
32738  }
32739  pFramesInS16 += pResampler->config.channels;
32740  } else {
32741  for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
32742  pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
32743  pResampler->x1.s16[iChannel] = 0;
32744  }
32745  }
32746 
32747  frameCountIn -= 1;
32748  framesProcessedIn += 1;
32749  pResampler->inTimeInt -= 1;
32750  }
32751 
32752  if (pResampler->inTimeInt > 0) {
32753  break; /* Ran out of input data. */
32754  }
32755 
32756  /* Getting here means the frames have been loaded and we can generate the next output frame. */
32757  if (pFramesOutS16 != NULL) {
32758  MA_ASSERT(pResampler->inTimeInt == 0);
32759  ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16);
32760 
32761  /* Filter. */
32762  ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pFramesOutS16, pFramesOutS16);
32763 
32764  pFramesOutS16 += pResampler->config.channels;
32765  }
32766 
32767  framesProcessedOut += 1;
32768 
32769  /* Advance time forward. */
32770  pResampler->inTimeInt += pResampler->inAdvanceInt;
32771  pResampler->inTimeFrac += pResampler->inAdvanceFrac;
32772  if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
32773  pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
32774  pResampler->inTimeInt += 1;
32775  }
32776  }
32777 
32778  *pFrameCountIn = framesProcessedIn;
32779  *pFrameCountOut = framesProcessedOut;
32780 
32781  return MA_SUCCESS;
32782 }
32783 
32784 static ma_result ma_linear_resampler_process_pcm_frames_s16(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
32785 {
32786  MA_ASSERT(pResampler != NULL);
32787 
32788  if (pResampler->config.sampleRateIn > pResampler->config.sampleRateOut) {
32789  return ma_linear_resampler_process_pcm_frames_s16_downsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
32790  } else {
32791  return ma_linear_resampler_process_pcm_frames_s16_upsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
32792  }
32793 }
32794 
32795 
32796 static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
32797 {
32798  const float* pFramesInF32;
32799  /* */ float* pFramesOutF32;
32800  ma_uint64 frameCountIn;
32801  ma_uint64 frameCountOut;
32802  ma_uint64 framesProcessedIn;
32803  ma_uint64 framesProcessedOut;
32804 
32805  MA_ASSERT(pResampler != NULL);
32806  MA_ASSERT(pFrameCountIn != NULL);
32807  MA_ASSERT(pFrameCountOut != NULL);
32808 
32809  pFramesInF32 = (const float*)pFramesIn;
32810  pFramesOutF32 = ( float*)pFramesOut;
32811  frameCountIn = *pFrameCountIn;
32812  frameCountOut = *pFrameCountOut;
32813  framesProcessedIn = 0;
32814  framesProcessedOut = 0;
32815 
32816  for (;;) {
32817  if (framesProcessedOut >= frameCountOut) {
32818  break;
32819  }
32820 
32821  /* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */
32822  while (pResampler->inTimeInt > 0 && frameCountIn > 0) {
32823  ma_uint32 iChannel;
32824 
32825  if (pFramesInF32 != NULL) {
32826  for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
32827  pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
32828  pResampler->x1.f32[iChannel] = pFramesInF32[iChannel];
32829  }
32830  pFramesInF32 += pResampler->config.channels;
32831  } else {
32832  for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
32833  pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
32834  pResampler->x1.f32[iChannel] = 0;
32835  }
32836  }
32837 
32838  /* Filter. */
32839  ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pResampler->x1.f32, pResampler->x1.f32);
32840 
32841  frameCountIn -= 1;
32842  framesProcessedIn += 1;
32843  pResampler->inTimeInt -= 1;
32844  }
32845 
32846  if (pResampler->inTimeInt > 0) {
32847  break; /* Ran out of input data. */
32848  }
32849 
32850  /* Getting here means the frames have been loaded and filtered and we can generate the next output frame. */
32851  if (pFramesOutF32 != NULL) {
32852  MA_ASSERT(pResampler->inTimeInt == 0);
32853  ma_linear_resampler_interpolate_frame_f32(pResampler, pFramesOutF32);
32854 
32855  pFramesOutF32 += pResampler->config.channels;
32856  }
32857 
32858  framesProcessedOut += 1;
32859 
32860  /* Advance time forward. */
32861  pResampler->inTimeInt += pResampler->inAdvanceInt;
32862  pResampler->inTimeFrac += pResampler->inAdvanceFrac;
32863  if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
32864  pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
32865  pResampler->inTimeInt += 1;
32866  }
32867  }
32868 
32869  *pFrameCountIn = framesProcessedIn;
32870  *pFrameCountOut = framesProcessedOut;
32871 
32872  return MA_SUCCESS;
32873 }
32874 
32875 static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
32876 {
32877  const float* pFramesInF32;
32878  /* */ float* pFramesOutF32;
32879  ma_uint64 frameCountIn;
32880  ma_uint64 frameCountOut;
32881  ma_uint64 framesProcessedIn;
32882  ma_uint64 framesProcessedOut;
32883 
32884  MA_ASSERT(pResampler != NULL);
32885  MA_ASSERT(pFrameCountIn != NULL);
32886  MA_ASSERT(pFrameCountOut != NULL);
32887 
32888  pFramesInF32 = (const float*)pFramesIn;
32889  pFramesOutF32 = ( float*)pFramesOut;
32890  frameCountIn = *pFrameCountIn;
32891  frameCountOut = *pFrameCountOut;
32892  framesProcessedIn = 0;
32893  framesProcessedOut = 0;
32894 
32895  for (;;) {
32896  if (framesProcessedOut >= frameCountOut) {
32897  break;
32898  }
32899 
32900  /* Before interpolating we need to load the buffers. */
32901  while (pResampler->inTimeInt > 0 && frameCountIn > 0) {
32902  ma_uint32 iChannel;
32903 
32904  if (pFramesInF32 != NULL) {
32905  for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
32906  pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
32907  pResampler->x1.f32[iChannel] = pFramesInF32[iChannel];
32908  }
32909  pFramesInF32 += pResampler->config.channels;
32910  } else {
32911  for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
32912  pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
32913  pResampler->x1.f32[iChannel] = 0;
32914  }
32915  }
32916 
32917  frameCountIn -= 1;
32918  framesProcessedIn += 1;
32919  pResampler->inTimeInt -= 1;
32920  }
32921 
32922  if (pResampler->inTimeInt > 0) {
32923  break; /* Ran out of input data. */
32924  }
32925 
32926  /* Getting here means the frames have been loaded and we can generate the next output frame. */
32927  if (pFramesOutF32 != NULL) {
32928  MA_ASSERT(pResampler->inTimeInt == 0);
32929  ma_linear_resampler_interpolate_frame_f32(pResampler, pFramesOutF32);
32930 
32931  /* Filter. */
32932  ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pFramesOutF32, pFramesOutF32);
32933 
32934  pFramesOutF32 += pResampler->config.channels;
32935  }
32936 
32937  framesProcessedOut += 1;
32938 
32939  /* Advance time forward. */
32940  pResampler->inTimeInt += pResampler->inAdvanceInt;
32941  pResampler->inTimeFrac += pResampler->inAdvanceFrac;
32942  if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
32943  pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
32944  pResampler->inTimeInt += 1;
32945  }
32946  }
32947 
32948  *pFrameCountIn = framesProcessedIn;
32949  *pFrameCountOut = framesProcessedOut;
32950 
32951  return MA_SUCCESS;
32952 }
32953 
32954 static ma_result ma_linear_resampler_process_pcm_frames_f32(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
32955 {
32956  MA_ASSERT(pResampler != NULL);
32957 
32958  if (pResampler->config.sampleRateIn > pResampler->config.sampleRateOut) {
32959  return ma_linear_resampler_process_pcm_frames_f32_downsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
32960  } else {
32961  return ma_linear_resampler_process_pcm_frames_f32_upsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
32962  }
32963 }
32964 
32965 
32966 ma_result ma_linear_resampler_process_pcm_frames(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
32967 {
32968  if (pResampler == NULL) {
32969  return MA_INVALID_ARGS;
32970  }
32971 
32972  /* */ if (pResampler->config.format == ma_format_s16) {
32973  return ma_linear_resampler_process_pcm_frames_s16(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
32974  } else if (pResampler->config.format == ma_format_f32) {
32975  return ma_linear_resampler_process_pcm_frames_f32(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
32976  } else {
32977  /* Should never get here. Getting here means the format is not supported and you didn't check the return value of ma_linear_resampler_init(). */
32979  return MA_INVALID_ARGS;
32980  }
32981 }
32982 
32983 
32984 ma_result ma_linear_resampler_set_rate(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
32985 {
32986  return ma_linear_resampler_set_rate_internal(pResampler, sampleRateIn, sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_TRUE);
32987 }
32988 
32990 {
32991  ma_uint32 n;
32992  ma_uint32 d;
32993 
32994  d = 1000000; /* We use up to 6 decimal places. */
32995  n = (ma_uint32)(ratioInOut * d);
32996 
32997  if (n == 0) {
32998  return MA_INVALID_ARGS; /* Ratio too small. */
32999  }
33000 
33001  MA_ASSERT(n != 0);
33002 
33003  return ma_linear_resampler_set_rate(pResampler, n, d);
33004 }
33005 
33006 
33008 {
33009  ma_uint64 count;
33010 
33011  if (pResampler == NULL) {
33012  return 0;
33013  }
33014 
33015  if (outputFrameCount == 0) {
33016  return 0;
33017  }
33018 
33019  /* Any whole input frames are consumed before the first output frame is generated. */
33020  count = pResampler->inTimeInt;
33021  outputFrameCount -= 1;
33022 
33023  /* The rest of the output frames can be calculated in constant time. */
33024  count += outputFrameCount * pResampler->inAdvanceInt;
33025  count += (pResampler->inTimeFrac + (outputFrameCount * pResampler->inAdvanceFrac)) / pResampler->config.sampleRateOut;
33026 
33027  return count;
33028 }
33029 
33031 {
33032  ma_uint64 outputFrameCount;
33033  ma_uint64 inTimeInt;
33034  ma_uint64 inTimeFrac;
33035 
33036  if (pResampler == NULL) {
33037  return 0;
33038  }
33039 
33040  /* TODO: Try making this run in constant time. */
33041 
33042  outputFrameCount = 0;
33043  inTimeInt = pResampler->inTimeInt;
33044  inTimeFrac = pResampler->inTimeFrac;
33045 
33046  for (;;) {
33047  while (inTimeInt > 0 && inputFrameCount > 0) {
33048  inputFrameCount -= 1;
33049  inTimeInt -= 1;
33050  }
33051 
33052  if (inTimeInt > 0) {
33053  break;
33054  }
33055 
33056  outputFrameCount += 1;
33057 
33058  /* Advance time forward. */
33059  inTimeInt += pResampler->inAdvanceInt;
33060  inTimeFrac += pResampler->inAdvanceFrac;
33061  if (inTimeFrac >= pResampler->config.sampleRateOut) {
33062  inTimeFrac -= pResampler->config.sampleRateOut;
33063  inTimeInt += 1;
33064  }
33065  }
33066 
33067  return outputFrameCount;
33068 }
33069 
33071 {
33072  if (pResampler == NULL) {
33073  return 0;
33074  }
33075 
33076  return 1 + ma_lpf_get_latency(&pResampler->lpf);
33077 }
33078 
33080 {
33081  if (pResampler == NULL) {
33082  return 0;
33083  }
33084 
33085  return ma_linear_resampler_get_input_latency(pResampler) * pResampler->config.sampleRateOut / pResampler->config.sampleRateIn;
33086 }
33087 
33088 
33089 #if defined(ma_speex_resampler_h)
33090 #define MA_HAS_SPEEX_RESAMPLER
33091 
33092 static ma_result ma_result_from_speex_err(int err)
33093 {
33094  switch (err)
33095  {
33096  case RESAMPLER_ERR_SUCCESS: return MA_SUCCESS;
33098  case RESAMPLER_ERR_BAD_STATE: return MA_ERROR;
33101  case RESAMPLER_ERR_OVERFLOW: return MA_ERROR;
33102  default: return MA_ERROR;
33103  }
33104 }
33105 #endif /* ma_speex_resampler_h */
33106 
33107 ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_resample_algorithm algorithm)
33108 {
33110 
33112  config.format = format;
33113  config.channels = channels;
33114  config.sampleRateIn = sampleRateIn;
33115  config.sampleRateOut = sampleRateOut;
33116  config.algorithm = algorithm;
33117 
33118  /* Linear. */
33120  config.linear.lpfNyquistFactor = 1;
33121 
33122  /* Speex. */
33123  config.speex.quality = 3; /* Cannot leave this as 0 as that is actually a valid value for Speex resampling quality. */
33124 
33125  return config;
33126 }
33127 
33128 ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resampler* pResampler)
33129 {
33130  ma_result result;
33131 
33132  if (pResampler == NULL) {
33133  return MA_INVALID_ARGS;
33134  }
33135 
33136  MA_ZERO_OBJECT(pResampler);
33137 
33138  if (pConfig == NULL) {
33139  return MA_INVALID_ARGS;
33140  }
33141 
33142  if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
33143  return MA_INVALID_ARGS;
33144  }
33145 
33146  pResampler->config = *pConfig;
33147 
33148  switch (pConfig->algorithm)
33149  {
33151  {
33152  ma_linear_resampler_config linearConfig;
33153  linearConfig = ma_linear_resampler_config_init(pConfig->format, pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut);
33154  linearConfig.lpfOrder = pConfig->linear.lpfOrder;
33155  linearConfig.lpfNyquistFactor = pConfig->linear.lpfNyquistFactor;
33156 
33157  result = ma_linear_resampler_init(&linearConfig, &pResampler->state.linear);
33158  if (result != MA_SUCCESS) {
33159  return result;
33160  }
33161  } break;
33162 
33164  {
33165  #if defined(MA_HAS_SPEEX_RESAMPLER)
33166  int speexErr;
33167  pResampler->state.speex.pSpeexResamplerState = speex_resampler_init(pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut, pConfig->speex.quality, &speexErr);
33168  if (pResampler->state.speex.pSpeexResamplerState == NULL) {
33169  return ma_result_from_speex_err(speexErr);
33170  }
33171  #else
33172  /* Speex resampler not available. */
33173  return MA_NO_BACKEND;
33174  #endif
33175  } break;
33176 
33177  default: return MA_INVALID_ARGS;
33178  }
33179 
33180  return MA_SUCCESS;
33181 }
33182 
33183 void ma_resampler_uninit(ma_resampler* pResampler)
33184 {
33185  if (pResampler == NULL) {
33186  return;
33187  }
33188 
33189  if (pResampler->config.algorithm == ma_resample_algorithm_linear) {
33190  ma_linear_resampler_uninit(&pResampler->state.linear);
33191  }
33192 
33193 #if defined(MA_HAS_SPEEX_RESAMPLER)
33194  if (pResampler->config.algorithm == ma_resample_algorithm_speex) {
33195  speex_resampler_destroy((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState);
33196  }
33197 #endif
33198 }
33199 
33200 static ma_result ma_resampler_process_pcm_frames__read__linear(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
33201 {
33202  return ma_linear_resampler_process_pcm_frames(&pResampler->state.linear, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
33203 }
33204 
33205 #if defined(MA_HAS_SPEEX_RESAMPLER)
33206 static ma_result ma_resampler_process_pcm_frames__read__speex(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
33207 {
33208  int speexErr;
33209  ma_uint64 frameCountOut;
33210  ma_uint64 frameCountIn;
33211  ma_uint64 framesProcessedOut;
33212  ma_uint64 framesProcessedIn;
33213  unsigned int framesPerIteration = UINT_MAX;
33214 
33215  MA_ASSERT(pResampler != NULL);
33216  MA_ASSERT(pFramesOut != NULL);
33217  MA_ASSERT(pFrameCountOut != NULL);
33218  MA_ASSERT(pFrameCountIn != NULL);
33219 
33220  /*
33221  Reading from the Speex resampler requires a bit of dancing around for a few reasons. The first thing is that it's frame counts
33222  are in unsigned int's whereas ours is in ma_uint64. We therefore need to run the conversion in a loop. The other, more complicated
33223  problem, is that we need to keep track of the input time, similar to what we do with the linear resampler. The reason we need to
33224  do this is for ma_resampler_get_required_input_frame_count() and ma_resampler_get_expected_output_frame_count().
33225  */
33226  frameCountOut = *pFrameCountOut;
33227  frameCountIn = *pFrameCountIn;
33228  framesProcessedOut = 0;
33229  framesProcessedIn = 0;
33230 
33231  while (framesProcessedOut < frameCountOut && framesProcessedIn < frameCountIn) {
33232  unsigned int frameCountInThisIteration;
33233  unsigned int frameCountOutThisIteration;
33234  const void* pFramesInThisIteration;
33235  void* pFramesOutThisIteration;
33236 
33237  frameCountInThisIteration = framesPerIteration;
33238  if ((ma_uint64)frameCountInThisIteration > (frameCountIn - framesProcessedIn)) {
33239  frameCountInThisIteration = (unsigned int)(frameCountIn - framesProcessedIn);
33240  }
33241 
33242  frameCountOutThisIteration = framesPerIteration;
33243  if ((ma_uint64)frameCountOutThisIteration > (frameCountOut - framesProcessedOut)) {
33244  frameCountOutThisIteration = (unsigned int)(frameCountOut - framesProcessedOut);
33245  }
33246 
33247  pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels));
33248  pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels));
33249 
33250  if (pResampler->config.format == ma_format_f32) {
33251  speexErr = speex_resampler_process_interleaved_float((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, (const float*)pFramesInThisIteration, &frameCountInThisIteration, (float*)pFramesOutThisIteration, &frameCountOutThisIteration);
33252  } else if (pResampler->config.format == ma_format_s16) {
33253  speexErr = speex_resampler_process_interleaved_int((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, (const spx_int16_t*)pFramesInThisIteration, &frameCountInThisIteration, (spx_int16_t*)pFramesOutThisIteration, &frameCountOutThisIteration);
33254  } else {
33255  /* Format not supported. Should never get here. */
33257  return MA_INVALID_OPERATION;
33258  }
33259 
33260  if (speexErr != RESAMPLER_ERR_SUCCESS) {
33261  return ma_result_from_speex_err(speexErr);
33262  }
33263 
33264  framesProcessedIn += frameCountInThisIteration;
33265  framesProcessedOut += frameCountOutThisIteration;
33266  }
33267 
33268  *pFrameCountOut = framesProcessedOut;
33269  *pFrameCountIn = framesProcessedIn;
33270 
33271  return MA_SUCCESS;
33272 }
33273 #endif
33274 
33275 static ma_result ma_resampler_process_pcm_frames__read(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
33276 {
33277  MA_ASSERT(pResampler != NULL);
33278  MA_ASSERT(pFramesOut != NULL);
33279 
33280  /* pFramesOut is not NULL, which means we must have a capacity. */
33281  if (pFrameCountOut == NULL) {
33282  return MA_INVALID_ARGS;
33283  }
33284 
33285  /* It doesn't make sense to not have any input frames to process. */
33286  if (pFrameCountIn == NULL || pFramesIn == NULL) {
33287  return MA_INVALID_ARGS;
33288  }
33289 
33290  switch (pResampler->config.algorithm)
33291  {
33293  {
33294  return ma_resampler_process_pcm_frames__read__linear(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
33295  }
33296 
33298  {
33299  #if defined(MA_HAS_SPEEX_RESAMPLER)
33300  return ma_resampler_process_pcm_frames__read__speex(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
33301  #else
33302  break;
33303  #endif
33304  }
33305 
33306  default: break;
33307  }
33308 
33309  /* Should never get here. */
33311  return MA_INVALID_ARGS;
33312 }
33313 
33314 
33315 static ma_result ma_resampler_process_pcm_frames__seek__linear(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut)
33316 {
33317  MA_ASSERT(pResampler != NULL);
33318 
33319  /* Seeking is supported natively by the linear resampler. */
33320  return ma_linear_resampler_process_pcm_frames(&pResampler->state.linear, pFramesIn, pFrameCountIn, NULL, pFrameCountOut);
33321 }
33322 
33323 #if defined(MA_HAS_SPEEX_RESAMPLER)
33324 static ma_result ma_resampler_process_pcm_frames__seek__speex(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut)
33325 {
33326  /* The generic seek method is implemented in on top of ma_resampler_process_pcm_frames__read() by just processing into a dummy buffer. */
33327  float devnull[8192];
33328  ma_uint64 totalOutputFramesToProcess;
33329  ma_uint64 totalOutputFramesProcessed;
33330  ma_uint64 totalInputFramesProcessed;
33331  ma_uint32 bpf;
33332  ma_result result;
33333 
33334  MA_ASSERT(pResampler != NULL);
33335 
33336  totalOutputFramesProcessed = 0;
33337  totalInputFramesProcessed = 0;
33338  bpf = ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels);
33339 
33340  if (pFrameCountOut != NULL) {
33341  /* Seek by output frames. */
33342  totalOutputFramesToProcess = *pFrameCountOut;
33343  } else {
33344  /* Seek by input frames. */
33345  MA_ASSERT(pFrameCountIn != NULL);
33346  totalOutputFramesToProcess = ma_resampler_get_expected_output_frame_count(pResampler, *pFrameCountIn);
33347  }
33348 
33349  if (pFramesIn != NULL) {
33350  /* Process input data. */
33351  MA_ASSERT(pFrameCountIn != NULL);
33352  while (totalOutputFramesProcessed < totalOutputFramesToProcess && totalInputFramesProcessed < *pFrameCountIn) {
33353  ma_uint64 inputFramesToProcessThisIteration = (*pFrameCountIn - totalInputFramesProcessed);
33354  ma_uint64 outputFramesToProcessThisIteration = (totalOutputFramesToProcess - totalOutputFramesProcessed);
33355  if (outputFramesToProcessThisIteration > sizeof(devnull) / bpf) {
33356  outputFramesToProcessThisIteration = sizeof(devnull) / bpf;
33357  }
33358 
33359  result = ma_resampler_process_pcm_frames__read(pResampler, ma_offset_ptr(pFramesIn, totalInputFramesProcessed*bpf), &inputFramesToProcessThisIteration, ma_offset_ptr(devnull, totalOutputFramesProcessed*bpf), &outputFramesToProcessThisIteration);
33360  if (result != MA_SUCCESS) {
33361  return result;
33362  }
33363 
33364  totalOutputFramesProcessed += outputFramesToProcessThisIteration;
33365  totalInputFramesProcessed += inputFramesToProcessThisIteration;
33366  }
33367  } else {
33368  /* Don't process input data - just update timing and filter state as if zeroes were passed in. */
33369  while (totalOutputFramesProcessed < totalOutputFramesToProcess) {
33370  ma_uint64 inputFramesToProcessThisIteration = 16384;
33371  ma_uint64 outputFramesToProcessThisIteration = (totalOutputFramesToProcess - totalOutputFramesProcessed);
33372  if (outputFramesToProcessThisIteration > sizeof(devnull) / bpf) {
33373  outputFramesToProcessThisIteration = sizeof(devnull) / bpf;
33374  }
33375 
33376  result = ma_resampler_process_pcm_frames__read(pResampler, NULL, &inputFramesToProcessThisIteration, ma_offset_ptr(devnull, totalOutputFramesProcessed*bpf), &outputFramesToProcessThisIteration);
33377  if (result != MA_SUCCESS) {
33378  return result;
33379  }
33380 
33381  totalOutputFramesProcessed += outputFramesToProcessThisIteration;
33382  totalInputFramesProcessed += inputFramesToProcessThisIteration;
33383  }
33384  }
33385 
33386 
33387  if (pFrameCountIn != NULL) {
33388  *pFrameCountIn = totalInputFramesProcessed;
33389  }
33390  if (pFrameCountOut != NULL) {
33391  *pFrameCountOut = totalOutputFramesProcessed;
33392  }
33393 
33394  return MA_SUCCESS;
33395 }
33396 #endif
33397 
33398 static ma_result ma_resampler_process_pcm_frames__seek(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut)
33399 {
33400  MA_ASSERT(pResampler != NULL);
33401 
33402  switch (pResampler->config.algorithm)
33403  {
33405  {
33406  return ma_resampler_process_pcm_frames__seek__linear(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut);
33407  } break;
33408 
33410  {
33411  #if defined(MA_HAS_SPEEX_RESAMPLER)
33412  return ma_resampler_process_pcm_frames__seek__speex(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut);
33413  #else
33414  break;
33415  #endif
33416  };
33417 
33418  default: break;
33419  }
33420 
33421  /* Should never hit this. */
33423  return MA_INVALID_ARGS;
33424 }
33425 
33426 
33427 ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
33428 {
33429  if (pResampler == NULL) {
33430  return MA_INVALID_ARGS;
33431  }
33432 
33433  if (pFrameCountOut == NULL && pFrameCountIn == NULL) {
33434  return MA_INVALID_ARGS;
33435  }
33436 
33437  if (pFramesOut != NULL) {
33438  /* Reading. */
33439  return ma_resampler_process_pcm_frames__read(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
33440  } else {
33441  /* Seeking. */
33442  return ma_resampler_process_pcm_frames__seek(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut);
33443  }
33444 }
33445 
33446 ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
33447 {
33448  if (pResampler == NULL) {
33449  return MA_INVALID_ARGS;
33450  }
33451 
33452  if (sampleRateIn == 0 || sampleRateOut == 0) {
33453  return MA_INVALID_ARGS;
33454  }
33455 
33456  pResampler->config.sampleRateIn = sampleRateIn;
33457  pResampler->config.sampleRateOut = sampleRateOut;
33458 
33459  switch (pResampler->config.algorithm)
33460  {
33462  {
33463  return ma_linear_resampler_set_rate(&pResampler->state.linear, sampleRateIn, sampleRateOut);
33464  } break;
33465 
33467  {
33468  #if defined(MA_HAS_SPEEX_RESAMPLER)
33469  return ma_result_from_speex_err(speex_resampler_set_rate((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, sampleRateIn, sampleRateOut));
33470  #else
33471  break;
33472  #endif
33473  };
33474 
33475  default: break;
33476  }
33477 
33478  /* Should never get here. */
33480  return MA_INVALID_OPERATION;
33481 }
33482 
33483 ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio)
33484 {
33485  if (pResampler == NULL) {
33486  return MA_INVALID_ARGS;
33487  }
33488 
33489  if (pResampler->config.algorithm == ma_resample_algorithm_linear) {
33490  return ma_linear_resampler_set_rate_ratio(&pResampler->state.linear, ratio);
33491  } else {
33492  /* Getting here means the backend does not have native support for setting the rate as a ratio so we just do it generically. */
33493  ma_uint32 n;
33494  ma_uint32 d;
33495 
33496  d = 1000000; /* We use up to 6 decimal places. */
33497  n = (ma_uint32)(ratio * d);
33498 
33499  if (n == 0) {
33500  return MA_INVALID_ARGS; /* Ratio too small. */
33501  }
33502 
33503  MA_ASSERT(n != 0);
33504 
33505  return ma_resampler_set_rate(pResampler, n, d);
33506  }
33507 }
33508 
33510 {
33511  if (pResampler == NULL) {
33512  return 0;
33513  }
33514 
33515  if (outputFrameCount == 0) {
33516  return 0;
33517  }
33518 
33519  switch (pResampler->config.algorithm)
33520  {
33522  {
33523  return ma_linear_resampler_get_required_input_frame_count(&pResampler->state.linear, outputFrameCount);
33524  }
33525 
33527  {
33528  #if defined(MA_HAS_SPEEX_RESAMPLER)
33529  ma_uint64 count;
33530  int speexErr = ma_speex_resampler_get_required_input_frame_count((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, outputFrameCount, &count);
33531  if (speexErr != RESAMPLER_ERR_SUCCESS) {
33532  return 0;
33533  }
33534 
33535  return count;
33536  #else
33537  break;
33538  #endif
33539  }
33540 
33541  default: break;
33542  }
33543 
33544  /* Should never get here. */
33546  return 0;
33547 }
33548 
33550 {
33551  if (pResampler == NULL) {
33552  return 0; /* Invalid args. */
33553  }
33554 
33555  if (inputFrameCount == 0) {
33556  return 0;
33557  }
33558 
33559  switch (pResampler->config.algorithm)
33560  {
33562  {
33563  return ma_linear_resampler_get_expected_output_frame_count(&pResampler->state.linear, inputFrameCount);
33564  }
33565 
33567  {
33568  #if defined(MA_HAS_SPEEX_RESAMPLER)
33569  ma_uint64 count;
33570  int speexErr = ma_speex_resampler_get_expected_output_frame_count((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, inputFrameCount, &count);
33571  if (speexErr != RESAMPLER_ERR_SUCCESS) {
33572  return 0;
33573  }
33574 
33575  return count;
33576  #else
33577  break;
33578  #endif
33579  }
33580 
33581  default: break;
33582  }
33583 
33584  /* Should never get here. */
33586  return 0;
33587 }
33588 
33590 {
33591  if (pResampler == NULL) {
33592  return 0;
33593  }
33594 
33595  switch (pResampler->config.algorithm)
33596  {
33598  {
33599  return ma_linear_resampler_get_input_latency(&pResampler->state.linear);
33600  }
33601 
33603  {
33604  #if defined(MA_HAS_SPEEX_RESAMPLER)
33605  return (ma_uint64)ma_speex_resampler_get_input_latency((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState);
33606  #else
33607  break;
33608  #endif
33609  }
33610 
33611  default: break;
33612  }
33613 
33614  /* Should never get here. */
33616  return 0;
33617 }
33618 
33620 {
33621  if (pResampler == NULL) {
33622  return 0;
33623  }
33624 
33625  switch (pResampler->config.algorithm)
33626  {
33628  {
33630  }
33631 
33633  {
33634  #if defined(MA_HAS_SPEEX_RESAMPLER)
33635  return (ma_uint64)ma_speex_resampler_get_output_latency((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState);
33636  #else
33637  break;
33638  #endif
33639  }
33640 
33641  default: break;
33642  }
33643 
33644  /* Should never get here. */
33646  return 0;
33647 }
33648 
33649 /**************************************************************************************************************************************************************
33650 
33651 Channel Conversion
33652 
33653 **************************************************************************************************************************************************************/
33654 #ifndef MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT
33655 #define MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT 12
33656 #endif
33657 
33658 #define MA_PLANE_LEFT 0
33659 #define MA_PLANE_RIGHT 1
33660 #define MA_PLANE_FRONT 2
33661 #define MA_PLANE_BACK 3
33662 #define MA_PLANE_BOTTOM 4
33663 #define MA_PLANE_TOP 5
33664 
33665 float g_maChannelPlaneRatios[MA_CHANNEL_POSITION_COUNT][6] = {
33666  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_NONE */
33667  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_MONO */
33668  { 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_LEFT */
33669  { 0.0f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_RIGHT */
33670  { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_CENTER */
33671  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_LFE */
33672  { 0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f}, /* MA_CHANNEL_BACK_LEFT */
33673  { 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f}, /* MA_CHANNEL_BACK_RIGHT */
33674  { 0.25f, 0.0f, 0.75f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_LEFT_CENTER */
33675  { 0.0f, 0.25f, 0.75f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_FRONT_RIGHT_CENTER */
33676  { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f}, /* MA_CHANNEL_BACK_CENTER */
33677  { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_SIDE_LEFT */
33678  { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_SIDE_RIGHT */
33679  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, /* MA_CHANNEL_TOP_CENTER */
33680  { 0.33f, 0.0f, 0.33f, 0.0f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_FRONT_LEFT */
33681  { 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f}, /* MA_CHANNEL_TOP_FRONT_CENTER */
33682  { 0.0f, 0.33f, 0.33f, 0.0f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_FRONT_RIGHT */
33683  { 0.33f, 0.0f, 0.0f, 0.33f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_BACK_LEFT */
33684  { 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f}, /* MA_CHANNEL_TOP_BACK_CENTER */
33685  { 0.0f, 0.33f, 0.0f, 0.33f, 0.0f, 0.34f}, /* MA_CHANNEL_TOP_BACK_RIGHT */
33686  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_0 */
33687  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_1 */
33688  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_2 */
33689  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_3 */
33690  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_4 */
33691  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_5 */
33692  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_6 */
33693  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_7 */
33694  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_8 */
33695  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_9 */
33696  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_10 */
33697  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_11 */
33698  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_12 */
33699  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_13 */
33700  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_14 */
33701  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_15 */
33702  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_16 */
33703  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_17 */
33704  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_18 */
33705  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_19 */
33706  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_20 */
33707  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_21 */
33708  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_22 */
33709  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_23 */
33710  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_24 */
33711  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_25 */
33712  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_26 */
33713  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_27 */
33714  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_28 */
33715  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_29 */
33716  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_30 */
33717  { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, /* MA_CHANNEL_AUX_31 */
33718 };
33719 
33720 float ma_calculate_channel_position_rectangular_weight(ma_channel channelPositionA, ma_channel channelPositionB)
33721 {
33722  /*
33723  Imagine the following simplified example: You have a single input speaker which is the front/left speaker which you want to convert to
33724  the following output configuration:
33725 
33726  - front/left
33727  - side/left
33728  - back/left
33729 
33730  The front/left output is easy - it the same speaker position so it receives the full contribution of the front/left input. The amount
33731  of contribution to apply to the side/left and back/left speakers, however, is a bit more complicated.
33732 
33733  Imagine the front/left speaker as emitting audio from two planes - the front plane and the left plane. You can think of the front/left
33734  speaker emitting half of it's total volume from the front, and the other half from the left. Since part of it's volume is being emitted
33735  from the left side, and the side/left and back/left channels also emit audio from the left plane, one would expect that they would
33736  receive some amount of contribution from front/left speaker. The amount of contribution depends on how many planes are shared between
33737  the two speakers. Note that in the examples below I've added a top/front/left speaker as an example just to show how the math works
33738  across 3 spatial dimensions.
33739 
33740  The first thing to do is figure out how each speaker's volume is spread over each of plane:
33741  - front/left: 2 planes (front and left) = 1/2 = half it's total volume on each plane
33742  - side/left: 1 plane (left only) = 1/1 = entire volume from left plane
33743  - back/left: 2 planes (back and left) = 1/2 = half it's total volume on each plane
33744  - top/front/left: 3 planes (top, front and left) = 1/3 = one third it's total volume on each plane
33745 
33746  The amount of volume each channel contributes to each of it's planes is what controls how much it is willing to given and take to other
33747  channels on the same plane. The volume that is willing to the given by one channel is multiplied by the volume that is willing to be
33748  taken by the other to produce the final contribution.
33749  */
33750 
33751  /* Contribution = Sum(Volume to Give * Volume to Take) */
33752  float contribution =
33753  g_maChannelPlaneRatios[channelPositionA][0] * g_maChannelPlaneRatios[channelPositionB][0] +
33754  g_maChannelPlaneRatios[channelPositionA][1] * g_maChannelPlaneRatios[channelPositionB][1] +
33755  g_maChannelPlaneRatios[channelPositionA][2] * g_maChannelPlaneRatios[channelPositionB][2] +
33756  g_maChannelPlaneRatios[channelPositionA][3] * g_maChannelPlaneRatios[channelPositionB][3] +
33757  g_maChannelPlaneRatios[channelPositionA][4] * g_maChannelPlaneRatios[channelPositionB][4] +
33758  g_maChannelPlaneRatios[channelPositionA][5] * g_maChannelPlaneRatios[channelPositionB][5];
33759 
33760  return contribution;
33761 }
33762 
33763 ma_channel_converter_config ma_channel_converter_config_init(ma_format format, ma_uint32 channelsIn, const ma_channel channelMapIn[MA_MAX_CHANNELS], ma_uint32 channelsOut, const ma_channel channelMapOut[MA_MAX_CHANNELS], ma_channel_mix_mode mixingMode)
33764 {
33767  config.format = format;
33768  config.channelsIn = channelsIn;
33769  config.channelsOut = channelsOut;
33770  ma_channel_map_copy(config.channelMapIn, channelMapIn, channelsIn);
33771  ma_channel_map_copy(config.channelMapOut, channelMapOut, channelsOut);
33772  config.mixingMode = mixingMode;
33773 
33774  return config;
33775 }
33776 
33777 static ma_int32 ma_channel_converter_float_to_fp(float x)
33778 {
33780 }
33781 
33782 static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition)
33783 {
33784  int i;
33785 
33786  if (channelPosition == MA_CHANNEL_NONE || channelPosition == MA_CHANNEL_MONO || channelPosition == MA_CHANNEL_LFE) {
33787  return MA_FALSE;
33788  }
33789 
33790  for (i = 0; i < 6; ++i) { /* Each side of a cube. */
33791  if (g_maChannelPlaneRatios[channelPosition][i] != 0) {
33792  return MA_TRUE;
33793  }
33794  }
33795 
33796  return MA_FALSE;
33797 }
33798 
33800 {
33801  ma_uint32 iChannelIn;
33802  ma_uint32 iChannelOut;
33803 
33804  if (pConverter == NULL) {
33805  return MA_INVALID_ARGS;
33806  }
33807 
33808  MA_ZERO_OBJECT(pConverter);
33809 
33810  if (pConfig == NULL) {
33811  return MA_INVALID_ARGS;
33812  }
33813 
33814  if (!ma_channel_map_valid(pConfig->channelsIn, pConfig->channelMapIn)) {
33815  return MA_INVALID_ARGS; /* Invalid input channel map. */
33816  }
33817  if (!ma_channel_map_valid(pConfig->channelsOut, pConfig->channelMapOut)) {
33818  return MA_INVALID_ARGS; /* Invalid output channel map. */
33819  }
33820 
33821  if (pConfig->format != ma_format_s16 && pConfig->format != ma_format_f32) {
33822  return MA_INVALID_ARGS; /* Invalid format. */
33823  }
33824 
33825  pConverter->format = pConfig->format;
33826  pConverter->channelsIn = pConfig->channelsIn;
33827  pConverter->channelsOut = pConfig->channelsOut;
33828  ma_channel_map_copy(pConverter->channelMapIn, pConfig->channelMapIn, pConfig->channelsIn);
33829  ma_channel_map_copy(pConverter->channelMapOut, pConfig->channelMapOut, pConfig->channelsOut);
33830  pConverter->mixingMode = pConfig->mixingMode;
33831 
33832  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) {
33833  for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
33834  if (pConverter->format == ma_format_s16) {
33835  pConverter->weights.f32[iChannelIn][iChannelOut] = pConfig->weights[iChannelIn][iChannelOut];
33836  } else {
33837  pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fp(pConfig->weights[iChannelIn][iChannelOut]);
33838  }
33839  }
33840  }
33841 
33842 
33843 
33844  /* If the input and output channels and channel maps are the same we should use a passthrough. */
33845  if (pConverter->channelsIn == pConverter->channelsOut) {
33846  if (ma_channel_map_equal(pConverter->channelsIn, pConverter->channelMapIn, pConverter->channelMapOut)) {
33847  pConverter->isPassthrough = MA_TRUE;
33848  }
33849  if (ma_channel_map_blank(pConverter->channelsIn, pConverter->channelMapIn) || ma_channel_map_blank(pConverter->channelsOut, pConverter->channelMapOut)) {
33850  pConverter->isPassthrough = MA_TRUE;
33851  }
33852  }
33853 
33854 
33855  /*
33856  We can use a simple case for expanding the mono channel. This will used when expanding a mono input into any output so long
33857  as no LFE is present in the output.
33858  */
33859  if (!pConverter->isPassthrough) {
33860  if (pConverter->channelsIn == 1 && pConverter->channelMapIn[0] == MA_CHANNEL_MONO) {
33861  /* Optimal case if no LFE is in the output channel map. */
33862  pConverter->isSimpleMonoExpansion = MA_TRUE;
33863  if (ma_channel_map_contains_channel_position(pConverter->channelsOut, pConverter->channelMapOut, MA_CHANNEL_LFE)) {
33864  pConverter->isSimpleMonoExpansion = MA_FALSE;
33865  }
33866  }
33867  }
33868 
33869  /* Another optimized case is stereo to mono. */
33870  if (!pConverter->isPassthrough) {
33871  if (pConverter->channelsOut == 1 && pConverter->channelMapOut[0] == MA_CHANNEL_MONO && pConverter->channelsIn == 2) {
33872  /* Optimal case if no LFE is in the input channel map. */
33873  pConverter->isStereoToMono = MA_TRUE;
33874  if (ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->channelMapIn, MA_CHANNEL_LFE)) {
33875  pConverter->isStereoToMono = MA_FALSE;
33876  }
33877  }
33878  }
33879 
33880 
33881  /*
33882  Here is where we do a bit of pre-processing to know how each channel should be combined to make up the output. Rules:
33883 
33884  1) If it's a passthrough, do nothing - it's just a simple memcpy().
33885  2) If the channel counts are the same and every channel position in the input map is present in the output map, use a
33886  simple shuffle. An example might be different 5.1 channel layouts.
33887  3) Otherwise channels are blended based on spatial locality.
33888  */
33889  if (!pConverter->isPassthrough) {
33890  if (pConverter->channelsIn == pConverter->channelsOut) {
33891  ma_bool32 areAllChannelPositionsPresent = MA_TRUE;
33892  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
33893  ma_bool32 isInputChannelPositionInOutput = MA_FALSE;
33894  for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
33895  if (pConverter->channelMapIn[iChannelIn] == pConverter->channelMapOut[iChannelOut]) {
33896  isInputChannelPositionInOutput = MA_TRUE;
33897  break;
33898  }
33899  }
33900 
33901  if (!isInputChannelPositionInOutput) {
33902  areAllChannelPositionsPresent = MA_FALSE;
33903  break;
33904  }
33905  }
33906 
33907  if (areAllChannelPositionsPresent) {
33908  pConverter->isSimpleShuffle = MA_TRUE;
33909 
33910  /*
33911  All the router will be doing is rearranging channels which means all we need to do is use a shuffling table which is just
33912  a mapping between the index of the input channel to the index of the output channel.
33913  */
33914  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
33915  for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
33916  if (pConverter->channelMapIn[iChannelIn] == pConverter->channelMapOut[iChannelOut]) {
33917  pConverter->shuffleTable[iChannelIn] = (ma_uint8)iChannelOut;
33918  break;
33919  }
33920  }
33921  }
33922  }
33923  }
33924  }
33925 
33926 
33927  /*
33928  Here is where weights are calculated. Note that we calculate the weights at all times, even when using a passthrough and simple
33929  shuffling. We use different algorithms for calculating weights depending on our mixing mode.
33930 
33931  In simple mode we don't do any blending (except for converting between mono, which is done in a later step). Instead we just
33932  map 1:1 matching channels. In this mode, if no channels in the input channel map correspond to anything in the output channel
33933  map, nothing will be heard!
33934  */
33935 
33936  /* In all cases we need to make sure all channels that are present in both channel maps have a 1:1 mapping. */
33937  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
33938  ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
33939 
33940  for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
33941  ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut];
33942 
33943  if (channelPosIn == channelPosOut) {
33944  if (pConverter->format == ma_format_s16) {
33945  pConverter->weights.s16[iChannelIn][iChannelOut] = (1 << MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT);
33946  } else {
33947  pConverter->weights.f32[iChannelIn][iChannelOut] = 1;
33948  }
33949  }
33950  }
33951  }
33952 
33953  /*
33954  The mono channel is accumulated on all other channels, except LFE. Make sure in this loop we exclude output mono channels since
33955  they were handled in the pass above.
33956  */
33957  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
33958  ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
33959 
33960  if (channelPosIn == MA_CHANNEL_MONO) {
33961  for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
33962  ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut];
33963 
33964  if (channelPosOut != MA_CHANNEL_NONE && channelPosOut != MA_CHANNEL_MONO && channelPosOut != MA_CHANNEL_LFE) {
33965  if (pConverter->format == ma_format_s16) {
33966  pConverter->weights.s16[iChannelIn][iChannelOut] = (1 << MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT);
33967  } else {
33968  pConverter->weights.f32[iChannelIn][iChannelOut] = 1;
33969  }
33970  }
33971  }
33972  }
33973  }
33974 
33975  /* The output mono channel is the average of all non-none, non-mono and non-lfe input channels. */
33976  {
33977  ma_uint32 len = 0;
33978  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
33979  ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
33980 
33981  if (channelPosIn != MA_CHANNEL_NONE && channelPosIn != MA_CHANNEL_MONO && channelPosIn != MA_CHANNEL_LFE) {
33982  len += 1;
33983  }
33984  }
33985 
33986  if (len > 0) {
33987  float monoWeight = 1.0f / len;
33988 
33989  for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
33990  ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut];
33991 
33992  if (channelPosOut == MA_CHANNEL_MONO) {
33993  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
33994  ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
33995 
33996  if (channelPosIn != MA_CHANNEL_NONE && channelPosIn != MA_CHANNEL_MONO && channelPosIn != MA_CHANNEL_LFE) {
33997  if (pConverter->format == ma_format_s16) {
33998  pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fp(monoWeight);
33999  } else {
34000  pConverter->weights.f32[iChannelIn][iChannelOut] = monoWeight;
34001  }
34002  }
34003  }
34004  }
34005  }
34006  }
34007  }
34008 
34009 
34010  /* Input and output channels that are not present on the other side need to be blended in based on spatial locality. */
34011  switch (pConverter->mixingMode)
34012  {
34013  case ma_channel_mix_mode_rectangular:
34014  {
34015  /* Unmapped input channels. */
34016  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
34017  ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
34018 
34019  if (ma_is_spatial_channel_position(channelPosIn)) {
34020  if (!ma_channel_map_contains_channel_position(pConverter->channelsOut, pConverter->channelMapOut, channelPosIn)) {
34021  for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
34022  ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut];
34023 
34024  if (ma_is_spatial_channel_position(channelPosOut)) {
34025  float weight = 0;
34026  if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) {
34027  weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut);
34028  }
34029 
34030  /* Only apply the weight if we haven't already got some contribution from the respective channels. */
34031  if (pConverter->format == ma_format_s16) {
34032  if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) {
34033  pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fp(weight);
34034  }
34035  } else {
34036  if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) {
34037  pConverter->weights.f32[iChannelIn][iChannelOut] = weight;
34038  }
34039  }
34040  }
34041  }
34042  }
34043  }
34044  }
34045 
34046  /* Unmapped output channels. */
34047  for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
34048  ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut];
34049 
34050  if (ma_is_spatial_channel_position(channelPosOut)) {
34051  if (!ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->channelMapIn, channelPosOut)) {
34052  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
34053  ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
34054 
34055  if (ma_is_spatial_channel_position(channelPosIn)) {
34056  float weight = 0;
34057  if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) {
34058  weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut);
34059  }
34060 
34061  /* Only apply the weight if we haven't already got some contribution from the respective channels. */
34062  if (pConverter->format == ma_format_s16) {
34063  if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) {
34064  pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fp(weight);
34065  }
34066  } else {
34067  if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) {
34068  pConverter->weights.f32[iChannelIn][iChannelOut] = weight;
34069  }
34070  }
34071  }
34072  }
34073  }
34074  }
34075  }
34076  } break;
34077 
34080  default:
34081  {
34082  /* Fallthrough. */
34083  } break;
34084  }
34085 
34086 
34087  return MA_SUCCESS;
34088 }
34089 
34091 {
34092  if (pConverter == NULL) {
34093  return;
34094  }
34095 }
34096 
34097 static ma_result ma_channel_converter_process_pcm_frames__passthrough(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
34098 {
34099  MA_ASSERT(pConverter != NULL);
34100  MA_ASSERT(pFramesOut != NULL);
34101  MA_ASSERT(pFramesIn != NULL);
34102 
34103  ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut));
34104  return MA_SUCCESS;
34105 }
34106 
34107 static ma_result ma_channel_converter_process_pcm_frames__simple_shuffle(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
34108 {
34109  ma_uint32 iFrame;
34110  ma_uint32 iChannelIn;
34111 
34112  MA_ASSERT(pConverter != NULL);
34113  MA_ASSERT(pFramesOut != NULL);
34114  MA_ASSERT(pFramesIn != NULL);
34115  MA_ASSERT(pConverter->channelsIn == pConverter->channelsOut);
34116 
34117  if (pConverter->format == ma_format_s16) {
34118  /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut;
34119  const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn;
34120 
34121  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34122  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
34123  pFramesOutS16[pConverter->shuffleTable[iChannelIn]] = pFramesInS16[iChannelIn];
34124  }
34125  }
34126  } else {
34127  /* */ float* pFramesOutF32 = ( float*)pFramesOut;
34128  const float* pFramesInF32 = (const float*)pFramesIn;
34129 
34130  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34131  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
34132  pFramesOutF32[pConverter->shuffleTable[iChannelIn]] = pFramesInF32[iChannelIn];
34133  }
34134  }
34135  }
34136 
34137  return MA_SUCCESS;
34138 }
34139 
34140 static ma_result ma_channel_converter_process_pcm_frames__simple_mono_expansion(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
34141 {
34142  ma_uint64 iFrame;
34143 
34144  MA_ASSERT(pConverter != NULL);
34145  MA_ASSERT(pFramesOut != NULL);
34146  MA_ASSERT(pFramesIn != NULL);
34147 
34148  if (pConverter->format == ma_format_s16) {
34149  /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut;
34150  const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn;
34151 
34152  if (pConverter->channelsOut == 2) {
34153  for (iFrame = 0; iFrame < frameCount; ++iFrame) {
34154  pFramesOutS16[iFrame*2 + 0] = pFramesInS16[iFrame];
34155  pFramesOutS16[iFrame*2 + 1] = pFramesInS16[iFrame];
34156  }
34157  } else {
34158  for (iFrame = 0; iFrame < frameCount; ++iFrame) {
34159  ma_uint32 iChannel;
34160  for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
34161  pFramesOutS16[iFrame*pConverter->channelsOut + iChannel] = pFramesInS16[iFrame];
34162  }
34163  }
34164  }
34165  } else {
34166  /* */ float* pFramesOutF32 = ( float*)pFramesOut;
34167  const float* pFramesInF32 = (const float*)pFramesIn;
34168 
34169  if (pConverter->channelsOut == 2) {
34170  for (iFrame = 0; iFrame < frameCount; ++iFrame) {
34171  pFramesOutF32[iFrame*2 + 0] = pFramesInF32[iFrame];
34172  pFramesOutF32[iFrame*2 + 1] = pFramesInF32[iFrame];
34173  }
34174  } else {
34175  for (iFrame = 0; iFrame < frameCount; ++iFrame) {
34176  ma_uint32 iChannel;
34177  for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
34178  pFramesOutF32[iFrame*pConverter->channelsOut + iChannel] = pFramesInF32[iFrame];
34179  }
34180  }
34181  }
34182  }
34183 
34184  return MA_SUCCESS;
34185 }
34186 
34187 static ma_result ma_channel_converter_process_pcm_frames__stereo_to_mono(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
34188 {
34189  ma_uint64 iFrame;
34190 
34191  MA_ASSERT(pConverter != NULL);
34192  MA_ASSERT(pFramesOut != NULL);
34193  MA_ASSERT(pFramesIn != NULL);
34194  MA_ASSERT(pConverter->channelsIn == 2);
34195  MA_ASSERT(pConverter->channelsOut == 1);
34196 
34197  if (pConverter->format == ma_format_s16) {
34198  /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut;
34199  const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn;
34200 
34201  for (iFrame = 0; iFrame < frameCount; ++iFrame) {
34202  pFramesOutS16[iFrame] = (ma_int16)(((ma_int32)pFramesInS16[iFrame*2+0] + (ma_int32)pFramesInS16[iFrame*2+1]) / 2);
34203  }
34204  } else {
34205  /* */ float* pFramesOutF32 = ( float*)pFramesOut;
34206  const float* pFramesInF32 = (const float*)pFramesIn;
34207 
34208  for (iFrame = 0; iFrame < frameCount; ++iFrame) {
34209  pFramesOutF32[iFrame] = (pFramesInF32[iFrame*2+0] + pFramesInF32[iFrame*2+0]) * 0.5f;
34210  }
34211  }
34212 
34213  return MA_SUCCESS;
34214 }
34215 
34216 static ma_result ma_channel_converter_process_pcm_frames__weights(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
34217 {
34218  ma_uint32 iFrame;
34219  ma_uint32 iChannelIn;
34220  ma_uint32 iChannelOut;
34221 
34222  MA_ASSERT(pConverter != NULL);
34223  MA_ASSERT(pFramesOut != NULL);
34224  MA_ASSERT(pFramesIn != NULL);
34225 
34226  /* This is the more complicated case. Each of the output channels is accumulated with 0 or more input channels. */
34227 
34228  /* Clear. */
34229  ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut));
34230 
34231  /* Accumulate. */
34232  if (pConverter->format == ma_format_s16) {
34233  /* */ ma_int16* pFramesOutS16 = ( ma_int16*)pFramesOut;
34234  const ma_int16* pFramesInS16 = (const ma_int16*)pFramesIn;
34235 
34236  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34237  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
34238  for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
34239  ma_int32 s = pFramesOutS16[iFrame*pConverter->channelsOut + iChannelOut];
34240  s += (pFramesInS16[iFrame*pConverter->channelsIn + iChannelIn] * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT;
34241 
34242  pFramesOutS16[iFrame*pConverter->channelsOut + iChannelOut] = (ma_int16)ma_clamp(s, -32768, 32767);
34243  }
34244  }
34245  }
34246  } else {
34247  /* */ float* pFramesOutF32 = ( float*)pFramesOut;
34248  const float* pFramesInF32 = (const float*)pFramesIn;
34249 
34250  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34251  for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
34252  for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
34253  pFramesOutF32[iFrame*pConverter->channelsOut + iChannelOut] += pFramesInF32[iFrame*pConverter->channelsIn + iChannelIn] * pConverter->weights.f32[iChannelIn][iChannelOut];
34254  }
34255  }
34256  }
34257  }
34258 
34259  return MA_SUCCESS;
34260 }
34261 
34262 ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
34263 {
34264  if (pConverter == NULL) {
34265  return MA_INVALID_ARGS;
34266  }
34267 
34268  if (pFramesOut == NULL) {
34269  return MA_INVALID_ARGS;
34270  }
34271 
34272  if (pFramesIn == NULL) {
34273  ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut));
34274  return MA_SUCCESS;
34275  }
34276 
34277  if (pConverter->isPassthrough) {
34278  return ma_channel_converter_process_pcm_frames__passthrough(pConverter, pFramesOut, pFramesIn, frameCount);
34279  } else if (pConverter->isSimpleShuffle) {
34280  return ma_channel_converter_process_pcm_frames__simple_shuffle(pConverter, pFramesOut, pFramesIn, frameCount);
34281  } else if (pConverter->isSimpleMonoExpansion) {
34282  return ma_channel_converter_process_pcm_frames__simple_mono_expansion(pConverter, pFramesOut, pFramesIn, frameCount);
34283  } else if (pConverter->isStereoToMono) {
34284  return ma_channel_converter_process_pcm_frames__stereo_to_mono(pConverter, pFramesOut, pFramesIn, frameCount);
34285  } else {
34286  return ma_channel_converter_process_pcm_frames__weights(pConverter, pFramesOut, pFramesIn, frameCount);
34287  }
34288 }
34289 
34290 
34291 /**************************************************************************************************************************************************************
34292 
34293 Data Conversion
34294 
34295 **************************************************************************************************************************************************************/
34297 {
34300 
34301  config.ditherMode = ma_dither_mode_none;
34302  config.resampling.algorithm = ma_resample_algorithm_linear;
34303  config.resampling.allowDynamicSampleRate = MA_FALSE; /* Disable dynamic sample rates by default because dynamic rate adjustments should be quite rare and it allows an optimization for cases when the in and out sample rates are the same. */
34304 
34305  /* Linear resampling defaults. */
34306  config.resampling.linear.lpfOrder = 1;
34307  config.resampling.linear.lpfNyquistFactor = 1;
34308 
34309  /* Speex resampling defaults. */
34310  config.resampling.speex.quality = 3;
34311 
34312  return config;
34313 }
34314 
34315 ma_data_converter_config ma_data_converter_config_init(ma_format formatIn, ma_format formatOut, ma_uint32 channelsIn, ma_uint32 channelsOut, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
34316 {
34318  config.formatIn = formatIn;
34319  config.formatOut = formatOut;
34320  config.channelsIn = channelsIn;
34321  config.channelsOut = channelsOut;
34322  config.sampleRateIn = sampleRateIn;
34323  config.sampleRateOut = sampleRateOut;
34324 
34325  return config;
34326 }
34327 
34329 {
34330  ma_result result;
34331  ma_format midFormat;
34332 
34333  if (pConverter == NULL) {
34334  return MA_INVALID_ARGS;
34335  }
34336 
34337  MA_ZERO_OBJECT(pConverter);
34338 
34339  if (pConfig == NULL) {
34340  return MA_INVALID_ARGS;
34341  }
34342 
34343  pConverter->config = *pConfig;
34344 
34345  /*
34346  We want to avoid as much data conversion as possible. The channel converter and resampler both support s16 and f32 natively. We need to decide
34347  on the format to use for this stage. We call this the mid format because it's used in the middle stage of the conversion pipeline. If the output
34348  format is either s16 or f32 we use that one. If that is not the case it will do the same thing for the input format. If it's neither we just
34349  use f32.
34350  */
34351  /* */ if (pConverter->config.formatOut == ma_format_s16 || pConverter->config.formatOut == ma_format_f32) {
34352  midFormat = pConverter->config.formatOut;
34353  } else if (pConverter->config.formatIn == ma_format_s16 || pConverter->config.formatIn == ma_format_f32) {
34354  midFormat = pConverter->config.formatIn;
34355  } else {
34356  midFormat = ma_format_f32;
34357  }
34358 
34359  if (pConverter->config.formatIn != midFormat) {
34360  pConverter->hasPreFormatConversion = MA_TRUE;
34361  }
34362  if (pConverter->config.formatOut != midFormat) {
34363  pConverter->hasPostFormatConversion = MA_TRUE;
34364  }
34365 
34366 
34367  /* Channel converter. We always initialize this, but we check if it configures itself as a passthrough to determine whether or not it's needed. */
34368  {
34369  ma_uint32 iChannelIn;
34370  ma_uint32 iChannelOut;
34371  ma_channel_converter_config channelConverterConfig;
34372 
34373  channelConverterConfig = ma_channel_converter_config_init(midFormat, pConverter->config.channelsIn, pConverter->config.channelMapIn, pConverter->config.channelsOut, pConverter->config.channelMapOut, pConverter->config.channelMixMode);
34374 
34375  /* Channel weights. */
34376  for (iChannelIn = 0; iChannelIn < pConverter->config.channelsIn; iChannelIn += 1) {
34377  for (iChannelOut = 0; iChannelOut < pConverter->config.channelsOut; iChannelOut += 1) {
34378  channelConverterConfig.weights[iChannelIn][iChannelOut] = pConverter->config.channelWeights[iChannelIn][iChannelOut];
34379  }
34380  }
34381 
34382  result = ma_channel_converter_init(&channelConverterConfig, &pConverter->channelConverter);
34383  if (result != MA_SUCCESS) {
34384  return result;
34385  }
34386 
34387  /* If the channel converter is not a passthrough we need to enable it. Otherwise we can skip it. */
34388  if (pConverter->channelConverter.isPassthrough == MA_FALSE) {
34389  pConverter->hasChannelConverter = MA_TRUE;
34390  }
34391  }
34392 
34393 
34394  /* Always enable dynamic sample rates if the input sample rate is different because we're always going to need a resampler in this case anyway. */
34395  if (pConverter->config.resampling.allowDynamicSampleRate == MA_FALSE) {
34396  pConverter->config.resampling.allowDynamicSampleRate = pConverter->config.sampleRateIn != pConverter->config.sampleRateOut;
34397  }
34398 
34399  /* Resampler. */
34400  if (pConverter->config.resampling.allowDynamicSampleRate) {
34401  ma_resampler_config resamplerConfig;
34402  ma_uint32 resamplerChannels;
34403 
34404  /* The resampler is the most expensive part of the conversion process, so we need to do it at the stage where the channel count is at it's lowest. */
34405  if (pConverter->config.channelsIn < pConverter->config.channelsOut) {
34406  resamplerChannels = pConverter->config.channelsIn;
34407  } else {
34408  resamplerChannels = pConverter->config.channelsOut;
34409  }
34410 
34411  resamplerConfig = ma_resampler_config_init(midFormat, resamplerChannels, pConverter->config.sampleRateIn, pConverter->config.sampleRateOut, pConverter->config.resampling.algorithm);
34412  resamplerConfig.linear.lpfOrder = pConverter->config.resampling.linear.lpfOrder;
34413  resamplerConfig.linear.lpfNyquistFactor = pConverter->config.resampling.linear.lpfNyquistFactor;
34414  resamplerConfig.speex.quality = pConverter->config.resampling.speex.quality;
34415 
34416  result = ma_resampler_init(&resamplerConfig, &pConverter->resampler);
34417  if (result != MA_SUCCESS) {
34418  return result;
34419  }
34420 
34421  pConverter->hasResampler = MA_TRUE;
34422  }
34423 
34424  /* We can enable passthrough optimizations if applicable. Note that we'll only be able to do this if the sample rate is static. */
34425  if (pConverter->hasPreFormatConversion == MA_FALSE &&
34426  pConverter->hasPostFormatConversion == MA_FALSE &&
34427  pConverter->hasChannelConverter == MA_FALSE &&
34428  pConverter->hasResampler == MA_FALSE) {
34429  pConverter->isPassthrough = MA_TRUE;
34430  }
34431 
34432  return MA_SUCCESS;
34433 }
34434 
34436 {
34437  if (pConverter == NULL) {
34438  return;
34439  }
34440 
34441  if (pConverter->hasResampler) {
34442  ma_resampler_uninit(&pConverter->resampler);
34443  }
34444 }
34445 
34446 static ma_result ma_data_converter_process_pcm_frames__passthrough(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
34447 {
34448  ma_uint64 frameCountIn;
34449  ma_uint64 frameCountOut;
34450  ma_uint64 frameCount;
34451 
34452  MA_ASSERT(pConverter != NULL);
34453 
34454  frameCountIn = 0;
34455  if (pFrameCountIn != NULL) {
34456  frameCountIn = *pFrameCountIn;
34457  }
34458 
34459  frameCountOut = 0;
34460  if (pFrameCountOut != NULL) {
34461  frameCountOut = *pFrameCountOut;
34462  }
34463 
34464  frameCount = ma_min(frameCountIn, frameCountOut);
34465 
34466  if (pFramesOut != NULL) {
34467  if (pFramesIn != NULL) {
34468  ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
34469  } else {
34470  ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
34471  }
34472  }
34473 
34474  if (pFrameCountIn != NULL) {
34475  *pFrameCountIn = frameCount;
34476  }
34477  if (pFrameCountOut != NULL) {
34478  *pFrameCountOut = frameCount;
34479  }
34480 
34481  return MA_SUCCESS;
34482 }
34483 
34484 static ma_result ma_data_converter_process_pcm_frames__format_only(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
34485 {
34486  ma_uint64 frameCountIn;
34487  ma_uint64 frameCountOut;
34488  ma_uint64 frameCount;
34489 
34490  MA_ASSERT(pConverter != NULL);
34491 
34492  frameCountIn = 0;
34493  if (pFrameCountIn != NULL) {
34494  frameCountIn = *pFrameCountIn;
34495  }
34496 
34497  frameCountOut = 0;
34498  if (pFrameCountOut != NULL) {
34499  frameCountOut = *pFrameCountOut;
34500  }
34501 
34502  frameCount = ma_min(frameCountIn, frameCountOut);
34503 
34504  if (pFramesOut != NULL) {
34505  if (pFramesIn != NULL) {
34506  ma_convert_pcm_frames_format(pFramesOut, pConverter->config.formatOut, pFramesIn, pConverter->config.formatIn, frameCount, pConverter->config.channelsIn, pConverter->config.ditherMode);
34507  } else {
34508  ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
34509  }
34510  }
34511 
34512  if (pFrameCountIn != NULL) {
34513  *pFrameCountIn = frameCount;
34514  }
34515  if (pFrameCountOut != NULL) {
34516  *pFrameCountOut = frameCount;
34517  }
34518 
34519  return MA_SUCCESS;
34520 }
34521 
34522 
34523 static ma_result ma_data_converter_process_pcm_frames__resample_with_format_conversion(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
34524 {
34525  ma_result result = MA_SUCCESS;
34526  ma_uint64 frameCountIn;
34527  ma_uint64 frameCountOut;
34528  ma_uint64 framesProcessedIn;
34529  ma_uint64 framesProcessedOut;
34530 
34531  MA_ASSERT(pConverter != NULL);
34532 
34533  frameCountIn = 0;
34534  if (pFrameCountIn != NULL) {
34535  frameCountIn = *pFrameCountIn;
34536  }
34537 
34538  frameCountOut = 0;
34539  if (pFrameCountOut != NULL) {
34540  frameCountOut = *pFrameCountOut;
34541  }
34542 
34543  framesProcessedIn = 0;
34544  framesProcessedOut = 0;
34545 
34546  while (framesProcessedOut < frameCountOut) {
34547  ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
34548  const ma_uint32 tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels);
34549  const void* pFramesInThisIteration;
34550  /* */ void* pFramesOutThisIteration;
34551  ma_uint64 frameCountInThisIteration;
34552  ma_uint64 frameCountOutThisIteration;
34553 
34554  if (pFramesIn != NULL) {
34555  pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn));
34556  } else {
34557  pFramesInThisIteration = NULL;
34558  }
34559 
34560  if (pFramesOut != NULL) {
34561  pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
34562  } else {
34563  pFramesOutThisIteration = NULL;
34564  }
34565 
34566  /* Do a pre format conversion if necessary. */
34567  if (pConverter->hasPreFormatConversion) {
34568  ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
34569  const ma_uint32 tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels);
34570 
34571  frameCountInThisIteration = (frameCountIn - framesProcessedIn);
34572  if (frameCountInThisIteration > tempBufferInCap) {
34573  frameCountInThisIteration = tempBufferInCap;
34574  }
34575 
34576  if (pConverter->hasPostFormatConversion) {
34577  if (frameCountInThisIteration > tempBufferOutCap) {
34578  frameCountInThisIteration = tempBufferOutCap;
34579  }
34580  }
34581 
34582  if (pFramesInThisIteration != NULL) {
34583  ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.config.format, pFramesInThisIteration, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode);
34584  } else {
34585  MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn));
34586  }
34587 
34588  frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
34589 
34590  if (pConverter->hasPostFormatConversion) {
34591  /* Both input and output conversion required. Output to the temp buffer. */
34592  if (frameCountOutThisIteration > tempBufferOutCap) {
34593  frameCountOutThisIteration = tempBufferOutCap;
34594  }
34595 
34596  result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferIn, &frameCountInThisIteration, pTempBufferOut, &frameCountOutThisIteration);
34597  } else {
34598  /* Only pre-format required. Output straight to the output buffer. */
34599  result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferIn, &frameCountInThisIteration, pFramesOutThisIteration, &frameCountOutThisIteration);
34600  }
34601 
34602  if (result != MA_SUCCESS) {
34603  break;
34604  }
34605  } else {
34606  /* No pre-format required. Just read straight from the input buffer. */
34607  MA_ASSERT(pConverter->hasPostFormatConversion == MA_TRUE);
34608 
34609  frameCountInThisIteration = (frameCountIn - framesProcessedIn);
34610  frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
34611  if (frameCountOutThisIteration > tempBufferOutCap) {
34612  frameCountOutThisIteration = tempBufferOutCap;
34613  }
34614 
34615  result = ma_resampler_process_pcm_frames(&pConverter->resampler, pFramesInThisIteration, &frameCountInThisIteration, pTempBufferOut, &frameCountOutThisIteration);
34616  if (result != MA_SUCCESS) {
34617  break;
34618  }
34619  }
34620 
34621  /* If we are doing a post format conversion we need to do that now. */
34622  if (pConverter->hasPostFormatConversion) {
34623  if (pFramesOutThisIteration != NULL) {
34624  ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->config.formatOut, pTempBufferOut, pConverter->resampler.config.format, frameCountOutThisIteration, pConverter->resampler.config.channels, pConverter->config.ditherMode);
34625  }
34626  }
34627 
34628  framesProcessedIn += frameCountInThisIteration;
34629  framesProcessedOut += frameCountOutThisIteration;
34630 
34631  MA_ASSERT(framesProcessedIn <= frameCountIn);
34632  MA_ASSERT(framesProcessedOut <= frameCountOut);
34633 
34634  if (frameCountOutThisIteration == 0) {
34635  break; /* Consumed all of our input data. */
34636  }
34637  }
34638 
34639  if (pFrameCountIn != NULL) {
34640  *pFrameCountIn = framesProcessedIn;
34641  }
34642  if (pFrameCountOut != NULL) {
34643  *pFrameCountOut = framesProcessedOut;
34644  }
34645 
34646  return result;
34647 }
34648 
34649 static ma_result ma_data_converter_process_pcm_frames__resample_only(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
34650 {
34651  MA_ASSERT(pConverter != NULL);
34652 
34653  if (pConverter->hasPreFormatConversion == MA_FALSE && pConverter->hasPostFormatConversion == MA_FALSE) {
34654  /* Neither pre- nor post-format required. This is simple case where only resampling is required. */
34655  return ma_resampler_process_pcm_frames(&pConverter->resampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
34656  } else {
34657  /* Format conversion required. */
34658  return ma_data_converter_process_pcm_frames__resample_with_format_conversion(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
34659  }
34660 }
34661 
34662 static ma_result ma_data_converter_process_pcm_frames__channels_only(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
34663 {
34664  ma_result result;
34665  ma_uint64 frameCountIn;
34666  ma_uint64 frameCountOut;
34667  ma_uint64 frameCount;
34668 
34669  MA_ASSERT(pConverter != NULL);
34670 
34671  frameCountIn = 0;
34672  if (pFrameCountIn != NULL) {
34673  frameCountIn = *pFrameCountIn;
34674  }
34675 
34676  frameCountOut = 0;
34677  if (pFrameCountOut != NULL) {
34678  frameCountOut = *pFrameCountOut;
34679  }
34680 
34681  frameCount = ma_min(frameCountIn, frameCountOut);
34682 
34683  if (pConverter->hasPreFormatConversion == MA_FALSE && pConverter->hasPostFormatConversion == MA_FALSE) {
34684  /* No format conversion required. */
34685  result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pFramesOut, pFramesIn, frameCount);
34686  if (result != MA_SUCCESS) {
34687  return result;
34688  }
34689  } else {
34690  /* Format conversion required. */
34691  ma_uint64 framesProcessed = 0;
34692 
34693  while (framesProcessed < frameCount) {
34694  ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
34695  const ma_uint32 tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut);
34696  const void* pFramesInThisIteration;
34697  /* */ void* pFramesOutThisIteration;
34698  ma_uint64 frameCountThisIteration;
34699 
34700  if (pFramesIn != NULL) {
34701  pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessed * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn));
34702  } else {
34703  pFramesInThisIteration = NULL;
34704  }
34705 
34706  if (pFramesOut != NULL) {
34707  pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessed * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
34708  } else {
34709  pFramesOutThisIteration = NULL;
34710  }
34711 
34712  /* Do a pre format conversion if necessary. */
34713  if (pConverter->hasPreFormatConversion) {
34714  ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
34715  const ma_uint32 tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsIn);
34716 
34717  frameCountThisIteration = (frameCount - framesProcessed);
34718  if (frameCountThisIteration > tempBufferInCap) {
34719  frameCountThisIteration = tempBufferInCap;
34720  }
34721 
34722  if (pConverter->hasPostFormatConversion) {
34723  if (frameCountThisIteration > tempBufferOutCap) {
34724  frameCountThisIteration = tempBufferOutCap;
34725  }
34726  }
34727 
34728  if (pFramesInThisIteration != NULL) {
34729  ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pFramesInThisIteration, pConverter->config.formatIn, frameCountThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode);
34730  } else {
34731  MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn));
34732  }
34733 
34734  if (pConverter->hasPostFormatConversion) {
34735  /* Both input and output conversion required. Output to the temp buffer. */
34736  result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferOut, pTempBufferIn, frameCountThisIteration);
34737  } else {
34738  /* Only pre-format required. Output straight to the output buffer. */
34739  result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pFramesOutThisIteration, pTempBufferIn, frameCountThisIteration);
34740  }
34741 
34742  if (result != MA_SUCCESS) {
34743  break;
34744  }
34745  } else {
34746  /* No pre-format required. Just read straight from the input buffer. */
34747  MA_ASSERT(pConverter->hasPostFormatConversion == MA_TRUE);
34748 
34749  frameCountThisIteration = (frameCount - framesProcessed);
34750  if (frameCountThisIteration > tempBufferOutCap) {
34751  frameCountThisIteration = tempBufferOutCap;
34752  }
34753 
34754  result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferOut, pFramesInThisIteration, frameCountThisIteration);
34755  if (result != MA_SUCCESS) {
34756  break;
34757  }
34758  }
34759 
34760  /* If we are doing a post format conversion we need to do that now. */
34761  if (pConverter->hasPostFormatConversion) {
34762  if (pFramesOutThisIteration != NULL) {
34763  ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->config.formatOut, pTempBufferOut, pConverter->channelConverter.format, frameCountThisIteration, pConverter->channelConverter.channelsOut, pConverter->config.ditherMode);
34764  }
34765  }
34766 
34767  framesProcessed += frameCountThisIteration;
34768  }
34769  }
34770 
34771  if (pFrameCountIn != NULL) {
34772  *pFrameCountIn = frameCount;
34773  }
34774  if (pFrameCountOut != NULL) {
34775  *pFrameCountOut = frameCount;
34776  }
34777 
34778  return MA_SUCCESS;
34779 }
34780 
34781 static ma_result ma_data_converter_process_pcm_frames__resampling_first(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
34782 {
34783  ma_result result;
34784  ma_uint64 frameCountIn;
34785  ma_uint64 frameCountOut;
34786  ma_uint64 framesProcessedIn;
34787  ma_uint64 framesProcessedOut;
34788  ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In resampler format. */
34789  ma_uint64 tempBufferInCap;
34790  ma_uint8 pTempBufferMid[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In resampler format, channel converter input format. */
34791  ma_uint64 tempBufferMidCap;
34792  ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In channel converter output format. */
34793  ma_uint64 tempBufferOutCap;
34794 
34795  MA_ASSERT(pConverter != NULL);
34796  MA_ASSERT(pConverter->resampler.config.format == pConverter->channelConverter.format);
34797  MA_ASSERT(pConverter->resampler.config.channels == pConverter->channelConverter.channelsIn);
34798  MA_ASSERT(pConverter->resampler.config.channels < pConverter->channelConverter.channelsOut);
34799 
34800  frameCountIn = 0;
34801  if (pFrameCountIn != NULL) {
34802  frameCountIn = *pFrameCountIn;
34803  }
34804 
34805  frameCountOut = 0;
34806  if (pFrameCountOut != NULL) {
34807  frameCountOut = *pFrameCountOut;
34808  }
34809 
34810  framesProcessedIn = 0;
34811  framesProcessedOut = 0;
34812 
34813  tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels);
34814  tempBufferMidCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels);
34815  tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut);
34816 
34817  while (framesProcessedOut < frameCountOut) {
34818  ma_uint64 frameCountInThisIteration;
34819  ma_uint64 frameCountOutThisIteration;
34820  const void* pRunningFramesIn = NULL;
34821  void* pRunningFramesOut = NULL;
34822  const void* pResampleBufferIn;
34823  void* pChannelsBufferOut;
34824 
34825  if (pFramesIn != NULL) {
34826  pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn));
34827  }
34828  if (pFramesOut != NULL) {
34829  pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
34830  }
34831 
34832  /* Run input data through the resampler and output it to the temporary buffer. */
34833  frameCountInThisIteration = (frameCountIn - framesProcessedIn);
34834 
34835  if (pConverter->hasPreFormatConversion) {
34836  if (frameCountInThisIteration > tempBufferInCap) {
34837  frameCountInThisIteration = tempBufferInCap;
34838  }
34839  }
34840 
34841  frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
34842  if (frameCountOutThisIteration > tempBufferMidCap) {
34843  frameCountOutThisIteration = tempBufferMidCap;
34844  }
34845 
34846  /* We can't read more frames than can fit in the output buffer. */
34847  if (pConverter->hasPostFormatConversion) {
34848  if (frameCountOutThisIteration > tempBufferOutCap) {
34849  frameCountOutThisIteration = tempBufferOutCap;
34850  }
34851  }
34852 
34853  /* We need to ensure we don't try to process too many input frames that we run out of room in the output buffer. If this happens we'll end up glitching. */
34854  {
34855  ma_uint64 requiredInputFrameCount = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration);
34856  if (frameCountInThisIteration > requiredInputFrameCount) {
34857  frameCountInThisIteration = requiredInputFrameCount;
34858  }
34859  }
34860 
34861  if (pConverter->hasPreFormatConversion) {
34862  if (pFramesIn != NULL) {
34863  ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.config.format, pRunningFramesIn, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode);
34864  pResampleBufferIn = pTempBufferIn;
34865  } else {
34866  pResampleBufferIn = NULL;
34867  }
34868  } else {
34869  pResampleBufferIn = pRunningFramesIn;
34870  }
34871 
34872  result = ma_resampler_process_pcm_frames(&pConverter->resampler, pResampleBufferIn, &frameCountInThisIteration, pTempBufferMid, &frameCountOutThisIteration);
34873  if (result != MA_SUCCESS) {
34874  return result;
34875  }
34876 
34877 
34878  /*
34879  The input data has been resampled so now we need to run it through the channel converter. The input data is always contained in pTempBufferMid. We only need to do
34880  this part if we have an output buffer.
34881  */
34882  if (pFramesOut != NULL) {
34883  if (pConverter->hasPostFormatConversion) {
34884  pChannelsBufferOut = pTempBufferOut;
34885  } else {
34886  pChannelsBufferOut = pRunningFramesOut;
34887  }
34888 
34889  result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pChannelsBufferOut, pTempBufferMid, frameCountOutThisIteration);
34890  if (result != MA_SUCCESS) {
34891  return result;
34892  }
34893 
34894  /* Finally we do post format conversion. */
34895  if (pConverter->hasPostFormatConversion) {
34896  ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->config.formatOut, pChannelsBufferOut, pConverter->channelConverter.format, frameCountOutThisIteration, pConverter->channelConverter.channelsOut, pConverter->config.ditherMode);
34897  }
34898  }
34899 
34900 
34901  framesProcessedIn += frameCountInThisIteration;
34902  framesProcessedOut += frameCountOutThisIteration;
34903 
34904  MA_ASSERT(framesProcessedIn <= frameCountIn);
34905  MA_ASSERT(framesProcessedOut <= frameCountOut);
34906 
34907  if (frameCountOutThisIteration == 0) {
34908  break; /* Consumed all of our input data. */
34909  }
34910  }
34911 
34912  if (pFrameCountIn != NULL) {
34913  *pFrameCountIn = framesProcessedIn;
34914  }
34915  if (pFrameCountOut != NULL) {
34916  *pFrameCountOut = framesProcessedOut;
34917  }
34918 
34919  return MA_SUCCESS;
34920 }
34921 
34922 static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
34923 {
34924  ma_result result;
34925  ma_uint64 frameCountIn;
34926  ma_uint64 frameCountOut;
34927  ma_uint64 framesProcessedIn;
34928  ma_uint64 framesProcessedOut;
34929  ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In resampler format. */
34930  ma_uint64 tempBufferInCap;
34931  ma_uint8 pTempBufferMid[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In resampler format, channel converter input format. */
34932  ma_uint64 tempBufferMidCap;
34933  ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In channel converter output format. */
34934  ma_uint64 tempBufferOutCap;
34935 
34936  MA_ASSERT(pConverter != NULL);
34937  MA_ASSERT(pConverter->resampler.config.format == pConverter->channelConverter.format);
34938  MA_ASSERT(pConverter->resampler.config.channels == pConverter->channelConverter.channelsOut);
34939  MA_ASSERT(pConverter->resampler.config.channels < pConverter->channelConverter.channelsIn);
34940 
34941  frameCountIn = 0;
34942  if (pFrameCountIn != NULL) {
34943  frameCountIn = *pFrameCountIn;
34944  }
34945 
34946  frameCountOut = 0;
34947  if (pFrameCountOut != NULL) {
34948  frameCountOut = *pFrameCountOut;
34949  }
34950 
34951  framesProcessedIn = 0;
34952  framesProcessedOut = 0;
34953 
34954  tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsIn);
34955  tempBufferMidCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut);
34956  tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels);
34957 
34958  while (framesProcessedOut < frameCountOut) {
34959  ma_uint64 frameCountInThisIteration;
34960  ma_uint64 frameCountOutThisIteration;
34961  const void* pRunningFramesIn = NULL;
34962  void* pRunningFramesOut = NULL;
34963  const void* pChannelsBufferIn;
34964  void* pResampleBufferOut;
34965 
34966  if (pFramesIn != NULL) {
34967  pRunningFramesIn = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn));
34968  }
34969  if (pFramesOut != NULL) {
34970  pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
34971  }
34972 
34973  /* Run input data through the channel converter and output it to the temporary buffer. */
34974  frameCountInThisIteration = (frameCountIn - framesProcessedIn);
34975 
34976  if (pConverter->hasPreFormatConversion) {
34977  if (frameCountInThisIteration > tempBufferInCap) {
34978  frameCountInThisIteration = tempBufferInCap;
34979  }
34980 
34981  if (pRunningFramesIn != NULL) {
34982  ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pRunningFramesIn, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode);
34983  pChannelsBufferIn = pTempBufferIn;
34984  } else {
34985  pChannelsBufferIn = NULL;
34986  }
34987  } else {
34988  pChannelsBufferIn = pRunningFramesIn;
34989  }
34990 
34991  /*
34992  We can't convert more frames than will fit in the output buffer. We shouldn't actually need to do this check because the channel count is always reduced
34993  in this case which means we should always have capacity, but I'm leaving it here just for safety for future maintenance.
34994  */
34995  if (frameCountInThisIteration > tempBufferMidCap) {
34996  frameCountInThisIteration = tempBufferMidCap;
34997  }
34998 
34999  /*
35000  Make sure we don't read any more input frames than we need to fill the output frame count. If we do this we will end up in a situation where we lose some
35001  input samples and will end up glitching.
35002  */
35003  frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
35004  if (frameCountOutThisIteration > tempBufferMidCap) {
35005  frameCountOutThisIteration = tempBufferMidCap;
35006  }
35007 
35008  if (pConverter->hasPostFormatConversion) {
35009  ma_uint64 requiredInputFrameCount;
35010 
35011  if (frameCountOutThisIteration > tempBufferOutCap) {
35012  frameCountOutThisIteration = tempBufferOutCap;
35013  }
35014 
35015  requiredInputFrameCount = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration);
35016  if (frameCountInThisIteration > requiredInputFrameCount) {
35017  frameCountInThisIteration = requiredInputFrameCount;
35018  }
35019  }
35020 
35021  result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferMid, pChannelsBufferIn, frameCountInThisIteration);
35022  if (result != MA_SUCCESS) {
35023  return result;
35024  }
35025 
35026 
35027  /* At this point we have converted the channels to the output channel count which we now need to resample. */
35028  if (pConverter->hasPostFormatConversion) {
35029  pResampleBufferOut = pTempBufferOut;
35030  } else {
35031  pResampleBufferOut = pRunningFramesOut;
35032  }
35033 
35034  result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferMid, &frameCountInThisIteration, pResampleBufferOut, &frameCountOutThisIteration);
35035  if (result != MA_SUCCESS) {
35036  return result;
35037  }
35038 
35039  /* Finally we can do the post format conversion. */
35040  if (pConverter->hasPostFormatConversion) {
35041  if (pRunningFramesOut != NULL) {
35042  ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->config.formatOut, pResampleBufferOut, pConverter->resampler.config.format, frameCountOutThisIteration, pConverter->config.channelsOut, pConverter->config.ditherMode);
35043  }
35044  }
35045 
35046  framesProcessedIn += frameCountInThisIteration;
35047  framesProcessedOut += frameCountOutThisIteration;
35048 
35049  MA_ASSERT(framesProcessedIn <= frameCountIn);
35050  MA_ASSERT(framesProcessedOut <= frameCountOut);
35051 
35052  if (frameCountOutThisIteration == 0) {
35053  break; /* Consumed all of our input data. */
35054  }
35055  }
35056 
35057  if (pFrameCountIn != NULL) {
35058  *pFrameCountIn = framesProcessedIn;
35059  }
35060  if (pFrameCountOut != NULL) {
35061  *pFrameCountOut = framesProcessedOut;
35062  }
35063 
35064  return MA_SUCCESS;
35065 }
35066 
35067 ma_result ma_data_converter_process_pcm_frames(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
35068 {
35069  if (pConverter == NULL) {
35070  return MA_INVALID_ARGS;
35071  }
35072 
35073  if (pConverter->isPassthrough) {
35074  return ma_data_converter_process_pcm_frames__passthrough(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
35075  }
35076 
35077  /*
35078  Here is where the real work is done. Getting here means we're not using a passthrough and we need to move the data through each of the relevant stages. The order
35079  of our stages depends on the input and output channel count. If the input channels is less than the output channels we want to do sample rate conversion first so
35080  that it has less work (resampling is the most expensive part of format conversion).
35081  */
35082  if (pConverter->config.channelsIn < pConverter->config.channelsOut) {
35083  /* Do resampling first, if necessary. */
35084  MA_ASSERT(pConverter->hasChannelConverter == MA_TRUE);
35085 
35086  if (pConverter->hasResampler) {
35087  /* Resampling first. */
35088  return ma_data_converter_process_pcm_frames__resampling_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
35089  } else {
35090  /* Resampling not required. */
35091  return ma_data_converter_process_pcm_frames__channels_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
35092  }
35093  } else {
35094  /* Do channel conversion first, if necessary. */
35095  if (pConverter->hasChannelConverter) {
35096  if (pConverter->hasResampler) {
35097  /* Channel routing first. */
35098  return ma_data_converter_process_pcm_frames__channels_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
35099  } else {
35100  /* Resampling not required. */
35101  return ma_data_converter_process_pcm_frames__channels_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
35102  }
35103  } else {
35104  /* Channel routing not required. */
35105  if (pConverter->hasResampler) {
35106  /* Resampling only. */
35107  return ma_data_converter_process_pcm_frames__resample_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
35108  } else {
35109  /* No channel routing nor resampling required. Just format conversion. */
35110  return ma_data_converter_process_pcm_frames__format_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
35111  }
35112  }
35113  }
35114 }
35115 
35116 ma_result ma_data_converter_set_rate(ma_data_converter* pConverter, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
35117 {
35118  if (pConverter == NULL) {
35119  return MA_INVALID_ARGS;
35120  }
35121 
35122  if (pConverter->hasResampler == MA_FALSE) {
35123  return MA_INVALID_OPERATION; /* Dynamic resampling not enabled. */
35124  }
35125 
35126  return ma_resampler_set_rate(&pConverter->resampler, sampleRateIn, sampleRateOut);
35127 }
35128 
35129 ma_result ma_data_converter_set_rate_ratio(ma_data_converter* pConverter, float ratioInOut)
35130 {
35131  if (pConverter == NULL) {
35132  return MA_INVALID_ARGS;
35133  }
35134 
35135  if (pConverter->hasResampler == MA_FALSE) {
35136  return MA_INVALID_OPERATION; /* Dynamic resampling not enabled. */
35137  }
35138 
35139  return ma_resampler_set_rate_ratio(&pConverter->resampler, ratioInOut);
35140 }
35141 
35143 {
35144  if (pConverter == NULL) {
35145  return 0;
35146  }
35147 
35148  if (pConverter->hasResampler) {
35149  return ma_resampler_get_required_input_frame_count(&pConverter->resampler, outputFrameCount);
35150  } else {
35151  return outputFrameCount; /* 1:1 */
35152  }
35153 }
35154 
35156 {
35157  if (pConverter == NULL) {
35158  return 0;
35159  }
35160 
35161  if (pConverter->hasResampler) {
35162  return ma_resampler_get_expected_output_frame_count(&pConverter->resampler, inputFrameCount);
35163  } else {
35164  return inputFrameCount; /* 1:1 */
35165  }
35166 }
35167 
35169 {
35170  if (pConverter == NULL) {
35171  return 0;
35172  }
35173 
35174  if (pConverter->hasResampler) {
35175  return ma_resampler_get_input_latency(&pConverter->resampler);
35176  }
35177 
35178  return 0; /* No latency without a resampler. */
35179 }
35180 
35182 {
35183  if (pConverter == NULL) {
35184  return 0;
35185  }
35186 
35187  if (pConverter->hasResampler) {
35188  return ma_resampler_get_output_latency(&pConverter->resampler);
35189  }
35190 
35191  return 0; /* No latency without a resampler. */
35192 }
35193 
35194 
35195 
35196 /**************************************************************************************************************************************************************
35197 
35198 Format Conversion
35199 
35200 **************************************************************************************************************************************************************/
35201 
35203 {
35204  return (ma_int16)(x * 32767.0f);
35205 }
35206 
35207 /* u8 */
35208 void ma_pcm_u8_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35209 {
35210  (void)ditherMode;
35211  ma_copy_memory_64(dst, src, count * sizeof(ma_uint8));
35212 }
35213 
35214 
35215 static MA_INLINE void ma_pcm_u8_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35216 {
35217  ma_int16* dst_s16 = (ma_int16*)dst;
35218  const ma_uint8* src_u8 = (const ma_uint8*)src;
35219 
35220  ma_uint64 i;
35221  for (i = 0; i < count; i += 1) {
35222  ma_int16 x = src_u8[i];
35223  x = x - 128;
35224  x = x << 8;
35225  dst_s16[i] = x;
35226  }
35227 
35228  (void)ditherMode;
35229 }
35230 
35231 static MA_INLINE void ma_pcm_u8_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35232 {
35233  ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode);
35234 }
35235 
35236 #if defined(MA_SUPPORT_SSE2)
35237 static MA_INLINE void ma_pcm_u8_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35238 {
35239  ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
35240 }
35241 #endif
35242 #if defined(MA_SUPPORT_AVX2)
35243 static MA_INLINE void ma_pcm_u8_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35244 {
35245  ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
35246 }
35247 #endif
35248 #if defined(MA_SUPPORT_NEON)
35249 static MA_INLINE void ma_pcm_u8_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35250 {
35251  ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
35252 }
35253 #endif
35254 
35255 void ma_pcm_u8_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35256 {
35257 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35258  ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode);
35259 #else
35260  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35261  if (ma_has_avx2()) {
35262  ma_pcm_u8_to_s16__avx2(dst, src, count, ditherMode);
35263  } else
35264  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35265  if (ma_has_sse2()) {
35266  ma_pcm_u8_to_s16__sse2(dst, src, count, ditherMode);
35267  } else
35268  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35269  if (ma_has_neon()) {
35270  ma_pcm_u8_to_s16__neon(dst, src, count, ditherMode);
35271  } else
35272  #endif
35273  {
35274  ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
35275  }
35276 #endif
35277 }
35278 
35279 
35280 static MA_INLINE void ma_pcm_u8_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35281 {
35282  ma_uint8* dst_s24 = (ma_uint8*)dst;
35283  const ma_uint8* src_u8 = (const ma_uint8*)src;
35284 
35285  ma_uint64 i;
35286  for (i = 0; i < count; i += 1) {
35287  ma_int16 x = src_u8[i];
35288  x = x - 128;
35289 
35290  dst_s24[i*3+0] = 0;
35291  dst_s24[i*3+1] = 0;
35292  dst_s24[i*3+2] = (ma_uint8)((ma_int8)x);
35293  }
35294 
35295  (void)ditherMode;
35296 }
35297 
35298 static MA_INLINE void ma_pcm_u8_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35299 {
35300  ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode);
35301 }
35302 
35303 #if defined(MA_SUPPORT_SSE2)
35304 static MA_INLINE void ma_pcm_u8_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35305 {
35306  ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
35307 }
35308 #endif
35309 #if defined(MA_SUPPORT_AVX2)
35310 static MA_INLINE void ma_pcm_u8_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35311 {
35312  ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
35313 }
35314 #endif
35315 #if defined(MA_SUPPORT_NEON)
35316 static MA_INLINE void ma_pcm_u8_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35317 {
35318  ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
35319 }
35320 #endif
35321 
35322 void ma_pcm_u8_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35323 {
35324 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35325  ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode);
35326 #else
35327  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35328  if (ma_has_avx2()) {
35329  ma_pcm_u8_to_s24__avx2(dst, src, count, ditherMode);
35330  } else
35331  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35332  if (ma_has_sse2()) {
35333  ma_pcm_u8_to_s24__sse2(dst, src, count, ditherMode);
35334  } else
35335  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35336  if (ma_has_neon()) {
35337  ma_pcm_u8_to_s24__neon(dst, src, count, ditherMode);
35338  } else
35339  #endif
35340  {
35341  ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
35342  }
35343 #endif
35344 }
35345 
35346 
35347 static MA_INLINE void ma_pcm_u8_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35348 {
35349  ma_int32* dst_s32 = (ma_int32*)dst;
35350  const ma_uint8* src_u8 = (const ma_uint8*)src;
35351 
35352  ma_uint64 i;
35353  for (i = 0; i < count; i += 1) {
35354  ma_int32 x = src_u8[i];
35355  x = x - 128;
35356  x = x << 24;
35357  dst_s32[i] = x;
35358  }
35359 
35360  (void)ditherMode;
35361 }
35362 
35363 static MA_INLINE void ma_pcm_u8_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35364 {
35365  ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode);
35366 }
35367 
35368 #if defined(MA_SUPPORT_SSE2)
35369 static MA_INLINE void ma_pcm_u8_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35370 {
35371  ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
35372 }
35373 #endif
35374 #if defined(MA_SUPPORT_AVX2)
35375 static MA_INLINE void ma_pcm_u8_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35376 {
35377  ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
35378 }
35379 #endif
35380 #if defined(MA_SUPPORT_NEON)
35381 static MA_INLINE void ma_pcm_u8_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35382 {
35383  ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
35384 }
35385 #endif
35386 
35387 void ma_pcm_u8_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35388 {
35389 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35390  ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode);
35391 #else
35392  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35393  if (ma_has_avx2()) {
35394  ma_pcm_u8_to_s32__avx2(dst, src, count, ditherMode);
35395  } else
35396  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35397  if (ma_has_sse2()) {
35398  ma_pcm_u8_to_s32__sse2(dst, src, count, ditherMode);
35399  } else
35400  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35401  if (ma_has_neon()) {
35402  ma_pcm_u8_to_s32__neon(dst, src, count, ditherMode);
35403  } else
35404  #endif
35405  {
35406  ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
35407  }
35408 #endif
35409 }
35410 
35411 
35412 static MA_INLINE void ma_pcm_u8_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35413 {
35414  float* dst_f32 = (float*)dst;
35415  const ma_uint8* src_u8 = (const ma_uint8*)src;
35416 
35417  ma_uint64 i;
35418  for (i = 0; i < count; i += 1) {
35419  float x = (float)src_u8[i];
35420  x = x * 0.00784313725490196078f; /* 0..255 to 0..2 */
35421  x = x - 1; /* 0..2 to -1..1 */
35422 
35423  dst_f32[i] = x;
35424  }
35425 
35426  (void)ditherMode;
35427 }
35428 
35429 static MA_INLINE void ma_pcm_u8_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35430 {
35431  ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode);
35432 }
35433 
35434 #if defined(MA_SUPPORT_SSE2)
35435 static MA_INLINE void ma_pcm_u8_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35436 {
35437  ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
35438 }
35439 #endif
35440 #if defined(MA_SUPPORT_AVX2)
35441 static MA_INLINE void ma_pcm_u8_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35442 {
35443  ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
35444 }
35445 #endif
35446 #if defined(MA_SUPPORT_NEON)
35447 static MA_INLINE void ma_pcm_u8_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35448 {
35449  ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
35450 }
35451 #endif
35452 
35453 void ma_pcm_u8_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35454 {
35455 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35456  ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode);
35457 #else
35458  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35459  if (ma_has_avx2()) {
35460  ma_pcm_u8_to_f32__avx2(dst, src, count, ditherMode);
35461  } else
35462  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35463  if (ma_has_sse2()) {
35464  ma_pcm_u8_to_f32__sse2(dst, src, count, ditherMode);
35465  } else
35466  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35467  if (ma_has_neon()) {
35468  ma_pcm_u8_to_f32__neon(dst, src, count, ditherMode);
35469  } else
35470  #endif
35471  {
35472  ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
35473  }
35474 #endif
35475 }
35476 
35477 
35478 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35479 static MA_INLINE void ma_pcm_interleave_u8__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
35480 {
35481  ma_uint8* dst_u8 = (ma_uint8*)dst;
35482  const ma_uint8** src_u8 = (const ma_uint8**)src;
35483 
35484  ma_uint64 iFrame;
35485  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
35486  ma_uint32 iChannel;
35487  for (iChannel = 0; iChannel < channels; iChannel += 1) {
35488  dst_u8[iFrame*channels + iChannel] = src_u8[iChannel][iFrame];
35489  }
35490  }
35491 }
35492 #else
35493 static MA_INLINE void ma_pcm_interleave_u8__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
35494 {
35495  ma_uint8* dst_u8 = (ma_uint8*)dst;
35496  const ma_uint8** src_u8 = (const ma_uint8**)src;
35497 
35498  if (channels == 1) {
35499  ma_copy_memory_64(dst, src[0], frameCount * sizeof(ma_uint8));
35500  } else if (channels == 2) {
35501  ma_uint64 iFrame;
35502  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
35503  dst_u8[iFrame*2 + 0] = src_u8[0][iFrame];
35504  dst_u8[iFrame*2 + 1] = src_u8[1][iFrame];
35505  }
35506  } else {
35507  ma_uint64 iFrame;
35508  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
35509  ma_uint32 iChannel;
35510  for (iChannel = 0; iChannel < channels; iChannel += 1) {
35511  dst_u8[iFrame*channels + iChannel] = src_u8[iChannel][iFrame];
35512  }
35513  }
35514  }
35515 }
35516 #endif
35517 
35518 void ma_pcm_interleave_u8(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
35519 {
35520 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35521  ma_pcm_interleave_u8__reference(dst, src, frameCount, channels);
35522 #else
35523  ma_pcm_interleave_u8__optimized(dst, src, frameCount, channels);
35524 #endif
35525 }
35526 
35527 
35528 static MA_INLINE void ma_pcm_deinterleave_u8__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
35529 {
35530  ma_uint8** dst_u8 = (ma_uint8**)dst;
35531  const ma_uint8* src_u8 = (const ma_uint8*)src;
35532 
35533  ma_uint64 iFrame;
35534  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
35535  ma_uint32 iChannel;
35536  for (iChannel = 0; iChannel < channels; iChannel += 1) {
35537  dst_u8[iChannel][iFrame] = src_u8[iFrame*channels + iChannel];
35538  }
35539  }
35540 }
35541 
35542 static MA_INLINE void ma_pcm_deinterleave_u8__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
35543 {
35544  ma_pcm_deinterleave_u8__reference(dst, src, frameCount, channels);
35545 }
35546 
35547 void ma_pcm_deinterleave_u8(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
35548 {
35549 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35550  ma_pcm_deinterleave_u8__reference(dst, src, frameCount, channels);
35551 #else
35552  ma_pcm_deinterleave_u8__optimized(dst, src, frameCount, channels);
35553 #endif
35554 }
35555 
35556 
35557 /* s16 */
35558 static MA_INLINE void ma_pcm_s16_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35559 {
35560  ma_uint8* dst_u8 = (ma_uint8*)dst;
35561  const ma_int16* src_s16 = (const ma_int16*)src;
35562 
35563  if (ditherMode == ma_dither_mode_none) {
35564  ma_uint64 i;
35565  for (i = 0; i < count; i += 1) {
35566  ma_int16 x = src_s16[i];
35567  x = x >> 8;
35568  x = x + 128;
35569  dst_u8[i] = (ma_uint8)x;
35570  }
35571  } else {
35572  ma_uint64 i;
35573  for (i = 0; i < count; i += 1) {
35574  ma_int16 x = src_s16[i];
35575 
35576  /* Dither. Don't overflow. */
35577  ma_int32 dither = ma_dither_s32(ditherMode, -0x80, 0x7F);
35578  if ((x + dither) <= 0x7FFF) {
35579  x = (ma_int16)(x + dither);
35580  } else {
35581  x = 0x7FFF;
35582  }
35583 
35584  x = x >> 8;
35585  x = x + 128;
35586  dst_u8[i] = (ma_uint8)x;
35587  }
35588  }
35589 }
35590 
35591 static MA_INLINE void ma_pcm_s16_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35592 {
35593  ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode);
35594 }
35595 
35596 #if defined(MA_SUPPORT_SSE2)
35597 static MA_INLINE void ma_pcm_s16_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35598 {
35599  ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
35600 }
35601 #endif
35602 #if defined(MA_SUPPORT_AVX2)
35603 static MA_INLINE void ma_pcm_s16_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35604 {
35605  ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
35606 }
35607 #endif
35608 #if defined(MA_SUPPORT_NEON)
35609 static MA_INLINE void ma_pcm_s16_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35610 {
35611  ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
35612 }
35613 #endif
35614 
35615 void ma_pcm_s16_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35616 {
35617 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35618  ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode);
35619 #else
35620  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35621  if (ma_has_avx2()) {
35622  ma_pcm_s16_to_u8__avx2(dst, src, count, ditherMode);
35623  } else
35624  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35625  if (ma_has_sse2()) {
35626  ma_pcm_s16_to_u8__sse2(dst, src, count, ditherMode);
35627  } else
35628  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35629  if (ma_has_neon()) {
35630  ma_pcm_s16_to_u8__neon(dst, src, count, ditherMode);
35631  } else
35632  #endif
35633  {
35634  ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
35635  }
35636 #endif
35637 }
35638 
35639 
35640 void ma_pcm_s16_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35641 {
35642  (void)ditherMode;
35643  ma_copy_memory_64(dst, src, count * sizeof(ma_int16));
35644 }
35645 
35646 
35647 static MA_INLINE void ma_pcm_s16_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35648 {
35649  ma_uint8* dst_s24 = (ma_uint8*)dst;
35650  const ma_int16* src_s16 = (const ma_int16*)src;
35651 
35652  ma_uint64 i;
35653  for (i = 0; i < count; i += 1) {
35654  dst_s24[i*3+0] = 0;
35655  dst_s24[i*3+1] = (ma_uint8)(src_s16[i] & 0xFF);
35656  dst_s24[i*3+2] = (ma_uint8)(src_s16[i] >> 8);
35657  }
35658 
35659  (void)ditherMode;
35660 }
35661 
35662 static MA_INLINE void ma_pcm_s16_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35663 {
35664  ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode);
35665 }
35666 
35667 #if defined(MA_SUPPORT_SSE2)
35668 static MA_INLINE void ma_pcm_s16_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35669 {
35670  ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
35671 }
35672 #endif
35673 #if defined(MA_SUPPORT_AVX2)
35674 static MA_INLINE void ma_pcm_s16_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35675 {
35676  ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
35677 }
35678 #endif
35679 #if defined(MA_SUPPORT_NEON)
35680 static MA_INLINE void ma_pcm_s16_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35681 {
35682  ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
35683 }
35684 #endif
35685 
35686 void ma_pcm_s16_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35687 {
35688 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35689  ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode);
35690 #else
35691  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35692  if (ma_has_avx2()) {
35693  ma_pcm_s16_to_s24__avx2(dst, src, count, ditherMode);
35694  } else
35695  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35696  if (ma_has_sse2()) {
35697  ma_pcm_s16_to_s24__sse2(dst, src, count, ditherMode);
35698  } else
35699  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35700  if (ma_has_neon()) {
35701  ma_pcm_s16_to_s24__neon(dst, src, count, ditherMode);
35702  } else
35703  #endif
35704  {
35705  ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
35706  }
35707 #endif
35708 }
35709 
35710 
35711 static MA_INLINE void ma_pcm_s16_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35712 {
35713  ma_int32* dst_s32 = (ma_int32*)dst;
35714  const ma_int16* src_s16 = (const ma_int16*)src;
35715 
35716  ma_uint64 i;
35717  for (i = 0; i < count; i += 1) {
35718  dst_s32[i] = src_s16[i] << 16;
35719  }
35720 
35721  (void)ditherMode;
35722 }
35723 
35724 static MA_INLINE void ma_pcm_s16_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35725 {
35726  ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode);
35727 }
35728 
35729 #if defined(MA_SUPPORT_SSE2)
35730 static MA_INLINE void ma_pcm_s16_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35731 {
35732  ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
35733 }
35734 #endif
35735 #if defined(MA_SUPPORT_AVX2)
35736 static MA_INLINE void ma_pcm_s16_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35737 {
35738  ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
35739 }
35740 #endif
35741 #if defined(MA_SUPPORT_NEON)
35742 static MA_INLINE void ma_pcm_s16_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35743 {
35744  ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
35745 }
35746 #endif
35747 
35748 void ma_pcm_s16_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35749 {
35750 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35751  ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode);
35752 #else
35753  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35754  if (ma_has_avx2()) {
35755  ma_pcm_s16_to_s32__avx2(dst, src, count, ditherMode);
35756  } else
35757  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35758  if (ma_has_sse2()) {
35759  ma_pcm_s16_to_s32__sse2(dst, src, count, ditherMode);
35760  } else
35761  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35762  if (ma_has_neon()) {
35763  ma_pcm_s16_to_s32__neon(dst, src, count, ditherMode);
35764  } else
35765  #endif
35766  {
35767  ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
35768  }
35769 #endif
35770 }
35771 
35772 
35773 static MA_INLINE void ma_pcm_s16_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35774 {
35775  float* dst_f32 = (float*)dst;
35776  const ma_int16* src_s16 = (const ma_int16*)src;
35777 
35778  ma_uint64 i;
35779  for (i = 0; i < count; i += 1) {
35780  float x = (float)src_s16[i];
35781 
35782 #if 0
35783  /* The accurate way. */
35784  x = x + 32768.0f; /* -32768..32767 to 0..65535 */
35785  x = x * 0.00003051804379339284f; /* 0..65535 to 0..2 */
35786  x = x - 1; /* 0..2 to -1..1 */
35787 #else
35788  /* The fast way. */
35789  x = x * 0.000030517578125f; /* -32768..32767 to -1..0.999969482421875 */
35790 #endif
35791 
35792  dst_f32[i] = x;
35793  }
35794 
35795  (void)ditherMode;
35796 }
35797 
35798 static MA_INLINE void ma_pcm_s16_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35799 {
35800  ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode);
35801 }
35802 
35803 #if defined(MA_SUPPORT_SSE2)
35804 static MA_INLINE void ma_pcm_s16_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35805 {
35806  ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
35807 }
35808 #endif
35809 #if defined(MA_SUPPORT_AVX2)
35810 static MA_INLINE void ma_pcm_s16_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35811 {
35812  ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
35813 }
35814 #endif
35815 #if defined(MA_SUPPORT_NEON)
35816 static MA_INLINE void ma_pcm_s16_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35817 {
35818  ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
35819 }
35820 #endif
35821 
35822 void ma_pcm_s16_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35823 {
35824 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35825  ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode);
35826 #else
35827  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35828  if (ma_has_avx2()) {
35829  ma_pcm_s16_to_f32__avx2(dst, src, count, ditherMode);
35830  } else
35831  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35832  if (ma_has_sse2()) {
35833  ma_pcm_s16_to_f32__sse2(dst, src, count, ditherMode);
35834  } else
35835  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35836  if (ma_has_neon()) {
35837  ma_pcm_s16_to_f32__neon(dst, src, count, ditherMode);
35838  } else
35839  #endif
35840  {
35841  ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
35842  }
35843 #endif
35844 }
35845 
35846 
35847 static MA_INLINE void ma_pcm_interleave_s16__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
35848 {
35849  ma_int16* dst_s16 = (ma_int16*)dst;
35850  const ma_int16** src_s16 = (const ma_int16**)src;
35851 
35852  ma_uint64 iFrame;
35853  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
35854  ma_uint32 iChannel;
35855  for (iChannel = 0; iChannel < channels; iChannel += 1) {
35856  dst_s16[iFrame*channels + iChannel] = src_s16[iChannel][iFrame];
35857  }
35858  }
35859 }
35860 
35861 static MA_INLINE void ma_pcm_interleave_s16__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
35862 {
35863  ma_pcm_interleave_s16__reference(dst, src, frameCount, channels);
35864 }
35865 
35866 void ma_pcm_interleave_s16(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
35867 {
35868 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35869  ma_pcm_interleave_s16__reference(dst, src, frameCount, channels);
35870 #else
35871  ma_pcm_interleave_s16__optimized(dst, src, frameCount, channels);
35872 #endif
35873 }
35874 
35875 
35876 static MA_INLINE void ma_pcm_deinterleave_s16__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
35877 {
35878  ma_int16** dst_s16 = (ma_int16**)dst;
35879  const ma_int16* src_s16 = (const ma_int16*)src;
35880 
35881  ma_uint64 iFrame;
35882  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
35883  ma_uint32 iChannel;
35884  for (iChannel = 0; iChannel < channels; iChannel += 1) {
35885  dst_s16[iChannel][iFrame] = src_s16[iFrame*channels + iChannel];
35886  }
35887  }
35888 }
35889 
35890 static MA_INLINE void ma_pcm_deinterleave_s16__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
35891 {
35892  ma_pcm_deinterleave_s16__reference(dst, src, frameCount, channels);
35893 }
35894 
35895 void ma_pcm_deinterleave_s16(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
35896 {
35897 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35898  ma_pcm_deinterleave_s16__reference(dst, src, frameCount, channels);
35899 #else
35900  ma_pcm_deinterleave_s16__optimized(dst, src, frameCount, channels);
35901 #endif
35902 }
35903 
35904 
35905 /* s24 */
35906 static MA_INLINE void ma_pcm_s24_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35907 {
35908  ma_uint8* dst_u8 = (ma_uint8*)dst;
35909  const ma_uint8* src_s24 = (const ma_uint8*)src;
35910 
35911  if (ditherMode == ma_dither_mode_none) {
35912  ma_uint64 i;
35913  for (i = 0; i < count; i += 1) {
35914  ma_int8 x = (ma_int8)src_s24[i*3 + 2] + 128;
35915  dst_u8[i] = (ma_uint8)x;
35916  }
35917  } else {
35918  ma_uint64 i;
35919  for (i = 0; i < count; i += 1) {
35920  ma_int32 x = (ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24);
35921 
35922  /* Dither. Don't overflow. */
35923  ma_int32 dither = ma_dither_s32(ditherMode, -0x800000, 0x7FFFFF);
35924  if ((ma_int64)x + dither <= 0x7FFFFFFF) {
35925  x = x + dither;
35926  } else {
35927  x = 0x7FFFFFFF;
35928  }
35929 
35930  x = x >> 24;
35931  x = x + 128;
35932  dst_u8[i] = (ma_uint8)x;
35933  }
35934  }
35935 }
35936 
35937 static MA_INLINE void ma_pcm_s24_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35938 {
35939  ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode);
35940 }
35941 
35942 #if defined(MA_SUPPORT_SSE2)
35943 static MA_INLINE void ma_pcm_s24_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35944 {
35945  ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
35946 }
35947 #endif
35948 #if defined(MA_SUPPORT_AVX2)
35949 static MA_INLINE void ma_pcm_s24_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35950 {
35951  ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
35952 }
35953 #endif
35954 #if defined(MA_SUPPORT_NEON)
35955 static MA_INLINE void ma_pcm_s24_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35956 {
35957  ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
35958 }
35959 #endif
35960 
35961 void ma_pcm_s24_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35962 {
35963 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35964  ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode);
35965 #else
35966  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35967  if (ma_has_avx2()) {
35968  ma_pcm_s24_to_u8__avx2(dst, src, count, ditherMode);
35969  } else
35970  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35971  if (ma_has_sse2()) {
35972  ma_pcm_s24_to_u8__sse2(dst, src, count, ditherMode);
35973  } else
35974  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35975  if (ma_has_neon()) {
35976  ma_pcm_s24_to_u8__neon(dst, src, count, ditherMode);
35977  } else
35978  #endif
35979  {
35980  ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
35981  }
35982 #endif
35983 }
35984 
35985 
35986 static MA_INLINE void ma_pcm_s24_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35987 {
35988  ma_int16* dst_s16 = (ma_int16*)dst;
35989  const ma_uint8* src_s24 = (const ma_uint8*)src;
35990 
35991  if (ditherMode == ma_dither_mode_none) {
35992  ma_uint64 i;
35993  for (i = 0; i < count; i += 1) {
35994  ma_uint16 dst_lo = ((ma_uint16)src_s24[i*3 + 1]);
35995  ma_uint16 dst_hi = ((ma_uint16)src_s24[i*3 + 2]) << 8;
35996  dst_s16[i] = (ma_int16)dst_lo | dst_hi;
35997  }
35998  } else {
35999  ma_uint64 i;
36000  for (i = 0; i < count; i += 1) {
36001  ma_int32 x = (ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24);
36002 
36003  /* Dither. Don't overflow. */
36004  ma_int32 dither = ma_dither_s32(ditherMode, -0x8000, 0x7FFF);
36005  if ((ma_int64)x + dither <= 0x7FFFFFFF) {
36006  x = x + dither;
36007  } else {
36008  x = 0x7FFFFFFF;
36009  }
36010 
36011  x = x >> 16;
36012  dst_s16[i] = (ma_int16)x;
36013  }
36014  }
36015 }
36016 
36017 static MA_INLINE void ma_pcm_s24_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36018 {
36019  ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode);
36020 }
36021 
36022 #if defined(MA_SUPPORT_SSE2)
36023 static MA_INLINE void ma_pcm_s24_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36024 {
36025  ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
36026 }
36027 #endif
36028 #if defined(MA_SUPPORT_AVX2)
36029 static MA_INLINE void ma_pcm_s24_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36030 {
36031  ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
36032 }
36033 #endif
36034 #if defined(MA_SUPPORT_NEON)
36035 static MA_INLINE void ma_pcm_s24_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36036 {
36037  ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
36038 }
36039 #endif
36040 
36041 void ma_pcm_s24_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36042 {
36043 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36044  ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode);
36045 #else
36046  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
36047  if (ma_has_avx2()) {
36048  ma_pcm_s24_to_s16__avx2(dst, src, count, ditherMode);
36049  } else
36050  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
36051  if (ma_has_sse2()) {
36052  ma_pcm_s24_to_s16__sse2(dst, src, count, ditherMode);
36053  } else
36054  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
36055  if (ma_has_neon()) {
36056  ma_pcm_s24_to_s16__neon(dst, src, count, ditherMode);
36057  } else
36058  #endif
36059  {
36060  ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
36061  }
36062 #endif
36063 }
36064 
36065 
36066 void ma_pcm_s24_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36067 {
36068  (void)ditherMode;
36069 
36070  ma_copy_memory_64(dst, src, count * 3);
36071 }
36072 
36073 
36074 static MA_INLINE void ma_pcm_s24_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36075 {
36076  ma_int32* dst_s32 = (ma_int32*)dst;
36077  const ma_uint8* src_s24 = (const ma_uint8*)src;
36078 
36079  ma_uint64 i;
36080  for (i = 0; i < count; i += 1) {
36081  dst_s32[i] = (ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24);
36082  }
36083 
36084  (void)ditherMode;
36085 }
36086 
36087 static MA_INLINE void ma_pcm_s24_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36088 {
36089  ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode);
36090 }
36091 
36092 #if defined(MA_SUPPORT_SSE2)
36093 static MA_INLINE void ma_pcm_s24_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36094 {
36095  ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
36096 }
36097 #endif
36098 #if defined(MA_SUPPORT_AVX2)
36099 static MA_INLINE void ma_pcm_s24_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36100 {
36101  ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
36102 }
36103 #endif
36104 #if defined(MA_SUPPORT_NEON)
36105 static MA_INLINE void ma_pcm_s24_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36106 {
36107  ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
36108 }
36109 #endif
36110 
36111 void ma_pcm_s24_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36112 {
36113 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36114  ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode);
36115 #else
36116  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
36117  if (ma_has_avx2()) {
36118  ma_pcm_s24_to_s32__avx2(dst, src, count, ditherMode);
36119  } else
36120  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
36121  if (ma_has_sse2()) {
36122  ma_pcm_s24_to_s32__sse2(dst, src, count, ditherMode);
36123  } else
36124  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
36125  if (ma_has_neon()) {
36126  ma_pcm_s24_to_s32__neon(dst, src, count, ditherMode);
36127  } else
36128  #endif
36129  {
36130  ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
36131  }
36132 #endif
36133 }
36134 
36135 
36136 static MA_INLINE void ma_pcm_s24_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36137 {
36138  float* dst_f32 = (float*)dst;
36139  const ma_uint8* src_s24 = (const ma_uint8*)src;
36140 
36141  ma_uint64 i;
36142  for (i = 0; i < count; i += 1) {
36143  float x = (float)(((ma_int32)(((ma_uint32)(src_s24[i*3+0]) << 8) | ((ma_uint32)(src_s24[i*3+1]) << 16) | ((ma_uint32)(src_s24[i*3+2])) << 24)) >> 8);
36144 
36145 #if 0
36146  /* The accurate way. */
36147  x = x + 8388608.0f; /* -8388608..8388607 to 0..16777215 */
36148  x = x * 0.00000011920929665621f; /* 0..16777215 to 0..2 */
36149  x = x - 1; /* 0..2 to -1..1 */
36150 #else
36151  /* The fast way. */
36152  x = x * 0.00000011920928955078125f; /* -8388608..8388607 to -1..0.999969482421875 */
36153 #endif
36154 
36155  dst_f32[i] = x;
36156  }
36157 
36158  (void)ditherMode;
36159 }
36160 
36161 static MA_INLINE void ma_pcm_s24_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36162 {
36163  ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode);
36164 }
36165 
36166 #if defined(MA_SUPPORT_SSE2)
36167 static MA_INLINE void ma_pcm_s24_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36168 {
36169  ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
36170 }
36171 #endif
36172 #if defined(MA_SUPPORT_AVX2)
36173 static MA_INLINE void ma_pcm_s24_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36174 {
36175  ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
36176 }
36177 #endif
36178 #if defined(MA_SUPPORT_NEON)
36179 static MA_INLINE void ma_pcm_s24_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36180 {
36181  ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
36182 }
36183 #endif
36184 
36185 void ma_pcm_s24_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36186 {
36187 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36188  ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode);
36189 #else
36190  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
36191  if (ma_has_avx2()) {
36192  ma_pcm_s24_to_f32__avx2(dst, src, count, ditherMode);
36193  } else
36194  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
36195  if (ma_has_sse2()) {
36196  ma_pcm_s24_to_f32__sse2(dst, src, count, ditherMode);
36197  } else
36198  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
36199  if (ma_has_neon()) {
36200  ma_pcm_s24_to_f32__neon(dst, src, count, ditherMode);
36201  } else
36202  #endif
36203  {
36204  ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
36205  }
36206 #endif
36207 }
36208 
36209 
36210 static MA_INLINE void ma_pcm_interleave_s24__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
36211 {
36212  ma_uint8* dst8 = (ma_uint8*)dst;
36213  const ma_uint8** src8 = (const ma_uint8**)src;
36214 
36215  ma_uint64 iFrame;
36216  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
36217  ma_uint32 iChannel;
36218  for (iChannel = 0; iChannel < channels; iChannel += 1) {
36219  dst8[iFrame*3*channels + iChannel*3 + 0] = src8[iChannel][iFrame*3 + 0];
36220  dst8[iFrame*3*channels + iChannel*3 + 1] = src8[iChannel][iFrame*3 + 1];
36221  dst8[iFrame*3*channels + iChannel*3 + 2] = src8[iChannel][iFrame*3 + 2];
36222  }
36223  }
36224 }
36225 
36226 static MA_INLINE void ma_pcm_interleave_s24__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
36227 {
36228  ma_pcm_interleave_s24__reference(dst, src, frameCount, channels);
36229 }
36230 
36231 void ma_pcm_interleave_s24(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
36232 {
36233 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36234  ma_pcm_interleave_s24__reference(dst, src, frameCount, channels);
36235 #else
36236  ma_pcm_interleave_s24__optimized(dst, src, frameCount, channels);
36237 #endif
36238 }
36239 
36240 
36241 static MA_INLINE void ma_pcm_deinterleave_s24__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
36242 {
36243  ma_uint8** dst8 = (ma_uint8**)dst;
36244  const ma_uint8* src8 = (const ma_uint8*)src;
36245 
36246  ma_uint32 iFrame;
36247  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
36248  ma_uint32 iChannel;
36249  for (iChannel = 0; iChannel < channels; iChannel += 1) {
36250  dst8[iChannel][iFrame*3 + 0] = src8[iFrame*3*channels + iChannel*3 + 0];
36251  dst8[iChannel][iFrame*3 + 1] = src8[iFrame*3*channels + iChannel*3 + 1];
36252  dst8[iChannel][iFrame*3 + 2] = src8[iFrame*3*channels + iChannel*3 + 2];
36253  }
36254  }
36255 }
36256 
36257 static MA_INLINE void ma_pcm_deinterleave_s24__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
36258 {
36259  ma_pcm_deinterleave_s24__reference(dst, src, frameCount, channels);
36260 }
36261 
36262 void ma_pcm_deinterleave_s24(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
36263 {
36264 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36265  ma_pcm_deinterleave_s24__reference(dst, src, frameCount, channels);
36266 #else
36267  ma_pcm_deinterleave_s24__optimized(dst, src, frameCount, channels);
36268 #endif
36269 }
36270 
36271 
36272 
36273 /* s32 */
36274 static MA_INLINE void ma_pcm_s32_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36275 {
36276  ma_uint8* dst_u8 = (ma_uint8*)dst;
36277  const ma_int32* src_s32 = (const ma_int32*)src;
36278 
36279  if (ditherMode == ma_dither_mode_none) {
36280  ma_uint64 i;
36281  for (i = 0; i < count; i += 1) {
36282  ma_int32 x = src_s32[i];
36283  x = x >> 24;
36284  x = x + 128;
36285  dst_u8[i] = (ma_uint8)x;
36286  }
36287  } else {
36288  ma_uint64 i;
36289  for (i = 0; i < count; i += 1) {
36290  ma_int32 x = src_s32[i];
36291 
36292  /* Dither. Don't overflow. */
36293  ma_int32 dither = ma_dither_s32(ditherMode, -0x800000, 0x7FFFFF);
36294  if ((ma_int64)x + dither <= 0x7FFFFFFF) {
36295  x = x + dither;
36296  } else {
36297  x = 0x7FFFFFFF;
36298  }
36299 
36300  x = x >> 24;
36301  x = x + 128;
36302  dst_u8[i] = (ma_uint8)x;
36303  }
36304  }
36305 }
36306 
36307 static MA_INLINE void ma_pcm_s32_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36308 {
36309  ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode);
36310 }
36311 
36312 #if defined(MA_SUPPORT_SSE2)
36313 static MA_INLINE void ma_pcm_s32_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36314 {
36315  ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
36316 }
36317 #endif
36318 #if defined(MA_SUPPORT_AVX2)
36319 static MA_INLINE void ma_pcm_s32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36320 {
36321  ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
36322 }
36323 #endif
36324 #if defined(MA_SUPPORT_NEON)
36325 static MA_INLINE void ma_pcm_s32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36326 {
36327  ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
36328 }
36329 #endif
36330 
36331 void ma_pcm_s32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36332 {
36333 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36334  ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode);
36335 #else
36336  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
36337  if (ma_has_avx2()) {
36338  ma_pcm_s32_to_u8__avx2(dst, src, count, ditherMode);
36339  } else
36340  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
36341  if (ma_has_sse2()) {
36342  ma_pcm_s32_to_u8__sse2(dst, src, count, ditherMode);
36343  } else
36344  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
36345  if (ma_has_neon()) {
36346  ma_pcm_s32_to_u8__neon(dst, src, count, ditherMode);
36347  } else
36348  #endif
36349  {
36350  ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
36351  }
36352 #endif
36353 }
36354 
36355 
36356 static MA_INLINE void ma_pcm_s32_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36357 {
36358  ma_int16* dst_s16 = (ma_int16*)dst;
36359  const ma_int32* src_s32 = (const ma_int32*)src;
36360 
36361  if (ditherMode == ma_dither_mode_none) {
36362  ma_uint64 i;
36363  for (i = 0; i < count; i += 1) {
36364  ma_int32 x = src_s32[i];
36365  x = x >> 16;
36366  dst_s16[i] = (ma_int16)x;
36367  }
36368  } else {
36369  ma_uint64 i;
36370  for (i = 0; i < count; i += 1) {
36371  ma_int32 x = src_s32[i];
36372 
36373  /* Dither. Don't overflow. */
36374  ma_int32 dither = ma_dither_s32(ditherMode, -0x8000, 0x7FFF);
36375  if ((ma_int64)x + dither <= 0x7FFFFFFF) {
36376  x = x + dither;
36377  } else {
36378  x = 0x7FFFFFFF;
36379  }
36380 
36381  x = x >> 16;
36382  dst_s16[i] = (ma_int16)x;
36383  }
36384  }
36385 }
36386 
36387 static MA_INLINE void ma_pcm_s32_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36388 {
36389  ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode);
36390 }
36391 
36392 #if defined(MA_SUPPORT_SSE2)
36393 static MA_INLINE void ma_pcm_s32_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36394 {
36395  ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
36396 }
36397 #endif
36398 #if defined(MA_SUPPORT_AVX2)
36399 static MA_INLINE void ma_pcm_s32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36400 {
36401  ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
36402 }
36403 #endif
36404 #if defined(MA_SUPPORT_NEON)
36405 static MA_INLINE void ma_pcm_s32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36406 {
36407  ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
36408 }
36409 #endif
36410 
36411 void ma_pcm_s32_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36412 {
36413 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36414  ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode);
36415 #else
36416  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
36417  if (ma_has_avx2()) {
36418  ma_pcm_s32_to_s16__avx2(dst, src, count, ditherMode);
36419  } else
36420  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
36421  if (ma_has_sse2()) {
36422  ma_pcm_s32_to_s16__sse2(dst, src, count, ditherMode);
36423  } else
36424  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
36425  if (ma_has_neon()) {
36426  ma_pcm_s32_to_s16__neon(dst, src, count, ditherMode);
36427  } else
36428  #endif
36429  {
36430  ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
36431  }
36432 #endif
36433 }
36434 
36435 
36436 static MA_INLINE void ma_pcm_s32_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36437 {
36438  ma_uint8* dst_s24 = (ma_uint8*)dst;
36439  const ma_int32* src_s32 = (const ma_int32*)src;
36440 
36441  ma_uint64 i;
36442  for (i = 0; i < count; i += 1) {
36443  ma_uint32 x = (ma_uint32)src_s32[i];
36444  dst_s24[i*3+0] = (ma_uint8)((x & 0x0000FF00) >> 8);
36445  dst_s24[i*3+1] = (ma_uint8)((x & 0x00FF0000) >> 16);
36446  dst_s24[i*3+2] = (ma_uint8)((x & 0xFF000000) >> 24);
36447  }
36448 
36449  (void)ditherMode; /* No dithering for s32 -> s24. */
36450 }
36451 
36452 static MA_INLINE void ma_pcm_s32_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36453 {
36454  ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode);
36455 }
36456 
36457 #if defined(MA_SUPPORT_SSE2)
36458 static MA_INLINE void ma_pcm_s32_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36459 {
36460  ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
36461 }
36462 #endif
36463 #if defined(MA_SUPPORT_AVX2)
36464 static MA_INLINE void ma_pcm_s32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36465 {
36466  ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
36467 }
36468 #endif
36469 #if defined(MA_SUPPORT_NEON)
36470 static MA_INLINE void ma_pcm_s32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36471 {
36472  ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
36473 }
36474 #endif
36475 
36476 void ma_pcm_s32_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36477 {
36478 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36479  ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode);
36480 #else
36481  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
36482  if (ma_has_avx2()) {
36483  ma_pcm_s32_to_s24__avx2(dst, src, count, ditherMode);
36484  } else
36485  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
36486  if (ma_has_sse2()) {
36487  ma_pcm_s32_to_s24__sse2(dst, src, count, ditherMode);
36488  } else
36489  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
36490  if (ma_has_neon()) {
36491  ma_pcm_s32_to_s24__neon(dst, src, count, ditherMode);
36492  } else
36493  #endif
36494  {
36495  ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
36496  }
36497 #endif
36498 }
36499 
36500 
36501 void ma_pcm_s32_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36502 {
36503  (void)ditherMode;
36504 
36505  ma_copy_memory_64(dst, src, count * sizeof(ma_int32));
36506 }
36507 
36508 
36509 static MA_INLINE void ma_pcm_s32_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36510 {
36511  float* dst_f32 = (float*)dst;
36512  const ma_int32* src_s32 = (const ma_int32*)src;
36513 
36514  ma_uint64 i;
36515  for (i = 0; i < count; i += 1) {
36516  double x = src_s32[i];
36517 
36518 #if 0
36519  x = x + 2147483648.0;
36520  x = x * 0.0000000004656612873077392578125;
36521  x = x - 1;
36522 #else
36523  x = x / 2147483648.0;
36524 #endif
36525 
36526  dst_f32[i] = (float)x;
36527  }
36528 
36529  (void)ditherMode; /* No dithering for s32 -> f32. */
36530 }
36531 
36532 static MA_INLINE void ma_pcm_s32_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36533 {
36534  ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode);
36535 }
36536 
36537 #if defined(MA_SUPPORT_SSE2)
36538 static MA_INLINE void ma_pcm_s32_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36539 {
36540  ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
36541 }
36542 #endif
36543 #if defined(MA_SUPPORT_AVX2)
36544 static MA_INLINE void ma_pcm_s32_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36545 {
36546  ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
36547 }
36548 #endif
36549 #if defined(MA_SUPPORT_NEON)
36550 static MA_INLINE void ma_pcm_s32_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36551 {
36552  ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
36553 }
36554 #endif
36555 
36556 void ma_pcm_s32_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36557 {
36558 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36559  ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode);
36560 #else
36561  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
36562  if (ma_has_avx2()) {
36563  ma_pcm_s32_to_f32__avx2(dst, src, count, ditherMode);
36564  } else
36565  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
36566  if (ma_has_sse2()) {
36567  ma_pcm_s32_to_f32__sse2(dst, src, count, ditherMode);
36568  } else
36569  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
36570  if (ma_has_neon()) {
36571  ma_pcm_s32_to_f32__neon(dst, src, count, ditherMode);
36572  } else
36573  #endif
36574  {
36575  ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
36576  }
36577 #endif
36578 }
36579 
36580 
36581 static MA_INLINE void ma_pcm_interleave_s32__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
36582 {
36583  ma_int32* dst_s32 = (ma_int32*)dst;
36584  const ma_int32** src_s32 = (const ma_int32**)src;
36585 
36586  ma_uint64 iFrame;
36587  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
36588  ma_uint32 iChannel;
36589  for (iChannel = 0; iChannel < channels; iChannel += 1) {
36590  dst_s32[iFrame*channels + iChannel] = src_s32[iChannel][iFrame];
36591  }
36592  }
36593 }
36594 
36595 static MA_INLINE void ma_pcm_interleave_s32__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
36596 {
36597  ma_pcm_interleave_s32__reference(dst, src, frameCount, channels);
36598 }
36599 
36600 void ma_pcm_interleave_s32(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
36601 {
36602 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36603  ma_pcm_interleave_s32__reference(dst, src, frameCount, channels);
36604 #else
36605  ma_pcm_interleave_s32__optimized(dst, src, frameCount, channels);
36606 #endif
36607 }
36608 
36609 
36610 static MA_INLINE void ma_pcm_deinterleave_s32__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
36611 {
36612  ma_int32** dst_s32 = (ma_int32**)dst;
36613  const ma_int32* src_s32 = (const ma_int32*)src;
36614 
36615  ma_uint64 iFrame;
36616  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
36617  ma_uint32 iChannel;
36618  for (iChannel = 0; iChannel < channels; iChannel += 1) {
36619  dst_s32[iChannel][iFrame] = src_s32[iFrame*channels + iChannel];
36620  }
36621  }
36622 }
36623 
36624 static MA_INLINE void ma_pcm_deinterleave_s32__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
36625 {
36626  ma_pcm_deinterleave_s32__reference(dst, src, frameCount, channels);
36627 }
36628 
36629 void ma_pcm_deinterleave_s32(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
36630 {
36631 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36632  ma_pcm_deinterleave_s32__reference(dst, src, frameCount, channels);
36633 #else
36634  ma_pcm_deinterleave_s32__optimized(dst, src, frameCount, channels);
36635 #endif
36636 }
36637 
36638 
36639 /* f32 */
36640 static MA_INLINE void ma_pcm_f32_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36641 {
36642  ma_uint64 i;
36643 
36644  ma_uint8* dst_u8 = (ma_uint8*)dst;
36645  const float* src_f32 = (const float*)src;
36646 
36647  float ditherMin = 0;
36648  float ditherMax = 0;
36649  if (ditherMode != ma_dither_mode_none) {
36650  ditherMin = 1.0f / -128;
36651  ditherMax = 1.0f / 127;
36652  }
36653 
36654  for (i = 0; i < count; i += 1) {
36655  float x = src_f32[i];
36656  x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
36657  x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */
36658  x = x + 1; /* -1..1 to 0..2 */
36659  x = x * 127.5f; /* 0..2 to 0..255 */
36660 
36661  dst_u8[i] = (ma_uint8)x;
36662  }
36663 }
36664 
36665 static MA_INLINE void ma_pcm_f32_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36666 {
36667  ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode);
36668 }
36669 
36670 #if defined(MA_SUPPORT_SSE2)
36671 static MA_INLINE void ma_pcm_f32_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36672 {
36673  ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
36674 }
36675 #endif
36676 #if defined(MA_SUPPORT_AVX2)
36677 static MA_INLINE void ma_pcm_f32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36678 {
36679  ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
36680 }
36681 #endif
36682 #if defined(MA_SUPPORT_NEON)
36683 static MA_INLINE void ma_pcm_f32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36684 {
36685  ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
36686 }
36687 #endif
36688 
36689 void ma_pcm_f32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36690 {
36691 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36692  ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode);
36693 #else
36694  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
36695  if (ma_has_avx2()) {
36696  ma_pcm_f32_to_u8__avx2(dst, src, count, ditherMode);
36697  } else
36698  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
36699  if (ma_has_sse2()) {
36700  ma_pcm_f32_to_u8__sse2(dst, src, count, ditherMode);
36701  } else
36702  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
36703  if (ma_has_neon()) {
36704  ma_pcm_f32_to_u8__neon(dst, src, count, ditherMode);
36705  } else
36706  #endif
36707  {
36708  ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
36709  }
36710 #endif
36711 }
36712 
36713 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36714 static MA_INLINE void ma_pcm_f32_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36715 {
36716  ma_uint64 i;
36717 
36718  ma_int16* dst_s16 = (ma_int16*)dst;
36719  const float* src_f32 = (const float*)src;
36720 
36721  float ditherMin = 0;
36722  float ditherMax = 0;
36723  if (ditherMode != ma_dither_mode_none) {
36724  ditherMin = 1.0f / -32768;
36725  ditherMax = 1.0f / 32767;
36726  }
36727 
36728  for (i = 0; i < count; i += 1) {
36729  float x = src_f32[i];
36730  x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
36731  x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */
36732 
36733 #if 0
36734  /* The accurate way. */
36735  x = x + 1; /* -1..1 to 0..2 */
36736  x = x * 32767.5f; /* 0..2 to 0..65535 */
36737  x = x - 32768.0f; /* 0...65535 to -32768..32767 */
36738 #else
36739  /* The fast way. */
36740  x = x * 32767.0f; /* -1..1 to -32767..32767 */
36741 #endif
36742 
36743  dst_s16[i] = (ma_int16)x;
36744  }
36745 }
36746 #else
36747 static MA_INLINE void ma_pcm_f32_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36748 {
36749  ma_uint64 i;
36750  ma_uint64 i4;
36751  ma_uint64 count4;
36752 
36753  ma_int16* dst_s16 = (ma_int16*)dst;
36754  const float* src_f32 = (const float*)src;
36755 
36756  float ditherMin = 0;
36757  float ditherMax = 0;
36758  if (ditherMode != ma_dither_mode_none) {
36759  ditherMin = 1.0f / -32768;
36760  ditherMax = 1.0f / 32767;
36761  }
36762 
36763  /* Unrolled. */
36764  i = 0;
36765  count4 = count >> 2;
36766  for (i4 = 0; i4 < count4; i4 += 1) {
36767  float d0 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
36768  float d1 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
36769  float d2 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
36770  float d3 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
36771 
36772  float x0 = src_f32[i+0];
36773  float x1 = src_f32[i+1];
36774  float x2 = src_f32[i+2];
36775  float x3 = src_f32[i+3];
36776 
36777  x0 = x0 + d0;
36778  x1 = x1 + d1;
36779  x2 = x2 + d2;
36780  x3 = x3 + d3;
36781 
36782  x0 = ((x0 < -1) ? -1 : ((x0 > 1) ? 1 : x0));
36783  x1 = ((x1 < -1) ? -1 : ((x1 > 1) ? 1 : x1));
36784  x2 = ((x2 < -1) ? -1 : ((x2 > 1) ? 1 : x2));
36785  x3 = ((x3 < -1) ? -1 : ((x3 > 1) ? 1 : x3));
36786 
36787  x0 = x0 * 32767.0f;
36788  x1 = x1 * 32767.0f;
36789  x2 = x2 * 32767.0f;
36790  x3 = x3 * 32767.0f;
36791 
36792  dst_s16[i+0] = (ma_int16)x0;
36793  dst_s16[i+1] = (ma_int16)x1;
36794  dst_s16[i+2] = (ma_int16)x2;
36795  dst_s16[i+3] = (ma_int16)x3;
36796 
36797  i += 4;
36798  }
36799 
36800  /* Leftover. */
36801  for (; i < count; i += 1) {
36802  float x = src_f32[i];
36803  x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
36804  x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */
36805  x = x * 32767.0f; /* -1..1 to -32767..32767 */
36806 
36807  dst_s16[i] = (ma_int16)x;
36808  }
36809 }
36810 
36811 #if defined(MA_SUPPORT_SSE2)
36812 static MA_INLINE void ma_pcm_f32_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36813 {
36814  ma_uint64 i;
36815  ma_uint64 i8;
36816  ma_uint64 count8;
36817  ma_int16* dst_s16;
36818  const float* src_f32;
36819  float ditherMin;
36820  float ditherMax;
36821 
36822  /* Both the input and output buffers need to be aligned to 16 bytes. */
36823  if ((((ma_uintptr)dst & 15) != 0) || (((ma_uintptr)src & 15) != 0)) {
36824  ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
36825  return;
36826  }
36827 
36828  dst_s16 = (ma_int16*)dst;
36829  src_f32 = (const float*)src;
36830 
36831  ditherMin = 0;
36832  ditherMax = 0;
36833  if (ditherMode != ma_dither_mode_none) {
36834  ditherMin = 1.0f / -32768;
36835  ditherMax = 1.0f / 32767;
36836  }
36837 
36838  i = 0;
36839 
36840  /* SSE2. SSE allows us to output 8 s16's at a time which means our loop is unrolled 8 times. */
36841  count8 = count >> 3;
36842  for (i8 = 0; i8 < count8; i8 += 1) {
36843  __m128 d0;
36844  __m128 d1;
36845  __m128 x0;
36846  __m128 x1;
36847 
36848  if (ditherMode == ma_dither_mode_none) {
36849  d0 = _mm_set1_ps(0);
36850  d1 = _mm_set1_ps(0);
36851  } else if (ditherMode == ma_dither_mode_rectangle) {
36852  d0 = _mm_set_ps(
36853  ma_dither_f32_rectangle(ditherMin, ditherMax),
36854  ma_dither_f32_rectangle(ditherMin, ditherMax),
36855  ma_dither_f32_rectangle(ditherMin, ditherMax),
36856  ma_dither_f32_rectangle(ditherMin, ditherMax)
36857  );
36858  d1 = _mm_set_ps(
36859  ma_dither_f32_rectangle(ditherMin, ditherMax),
36860  ma_dither_f32_rectangle(ditherMin, ditherMax),
36861  ma_dither_f32_rectangle(ditherMin, ditherMax),
36862  ma_dither_f32_rectangle(ditherMin, ditherMax)
36863  );
36864  } else {
36865  d0 = _mm_set_ps(
36866  ma_dither_f32_triangle(ditherMin, ditherMax),
36867  ma_dither_f32_triangle(ditherMin, ditherMax),
36868  ma_dither_f32_triangle(ditherMin, ditherMax),
36869  ma_dither_f32_triangle(ditherMin, ditherMax)
36870  );
36871  d1 = _mm_set_ps(
36872  ma_dither_f32_triangle(ditherMin, ditherMax),
36873  ma_dither_f32_triangle(ditherMin, ditherMax),
36874  ma_dither_f32_triangle(ditherMin, ditherMax),
36875  ma_dither_f32_triangle(ditherMin, ditherMax)
36876  );
36877  }
36878 
36879  x0 = *((__m128*)(src_f32 + i) + 0);
36880  x1 = *((__m128*)(src_f32 + i) + 1);
36881 
36882  x0 = _mm_add_ps(x0, d0);
36883  x1 = _mm_add_ps(x1, d1);
36884 
36885  x0 = _mm_mul_ps(x0, _mm_set1_ps(32767.0f));
36886  x1 = _mm_mul_ps(x1, _mm_set1_ps(32767.0f));
36887 
36888  _mm_stream_si128(((__m128i*)(dst_s16 + i)), _mm_packs_epi32(_mm_cvttps_epi32(x0), _mm_cvttps_epi32(x1)));
36889 
36890  i += 8;
36891  }
36892 
36893 
36894  /* Leftover. */
36895  for (; i < count; i += 1) {
36896  float x = src_f32[i];
36897  x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
36898  x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */
36899  x = x * 32767.0f; /* -1..1 to -32767..32767 */
36900 
36901  dst_s16[i] = (ma_int16)x;
36902  }
36903 }
36904 #endif /* SSE2 */
36905 
36906 #if defined(MA_SUPPORT_AVX2)
36907 static MA_INLINE void ma_pcm_f32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
36908 {
36909  ma_uint64 i;
36910  ma_uint64 i16;
36911  ma_uint64 count16;
36912  ma_int16* dst_s16;
36913  const float* src_f32;
36914  float ditherMin;
36915  float ditherMax;
36916 
36917  /* Both the input and output buffers need to be aligned to 32 bytes. */
36918  if ((((ma_uintptr)dst & 31) != 0) || (((ma_uintptr)src & 31) != 0)) {
36919  ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
36920  return;
36921  }
36922 
36923  dst_s16 = (ma_int16*)dst;
36924  src_f32 = (const float*)src;
36925 
36926  ditherMin = 0;
36927  ditherMax = 0;
36928  if (ditherMode != ma_dither_mode_none) {
36929  ditherMin = 1.0f / -32768;
36930  ditherMax = 1.0f / 32767;
36931  }
36932 
36933  i = 0;
36934 
36935  /* AVX2. AVX2 allows us to output 16 s16's at a time which means our loop is unrolled 16 times. */
36936  count16 = count >> 4;
36937  for (i16 = 0; i16 < count16; i16 += 1) {
36938  __m256 d0;
36939  __m256 d1;
36940  __m256 x0;
36941  __m256 x1;
36942  __m256i i0;
36943  __m256i i1;
36944  __m256i p0;
36945  __m256i p1;
36946  __m256i r;
36947 
36948  if (ditherMode == ma_dither_mode_none) {
36949  d0 = _mm256_set1_ps(0);
36950  d1 = _mm256_set1_ps(0);
36951  } else if (ditherMode == ma_dither_mode_rectangle) {
36952  d0 = _mm256_set_ps(
36953  ma_dither_f32_rectangle(ditherMin, ditherMax),
36954  ma_dither_f32_rectangle(ditherMin, ditherMax),
36955  ma_dither_f32_rectangle(ditherMin, ditherMax),
36956  ma_dither_f32_rectangle(ditherMin, ditherMax),
36957  ma_dither_f32_rectangle(ditherMin, ditherMax),
36958  ma_dither_f32_rectangle(ditherMin, ditherMax),
36959  ma_dither_f32_rectangle(ditherMin, ditherMax),
36960  ma_dither_f32_rectangle(ditherMin, ditherMax)
36961  );
36962  d1 = _mm256_set_ps(
36963  ma_dither_f32_rectangle(ditherMin, ditherMax),
36964  ma_dither_f32_rectangle(ditherMin, ditherMax),
36965  ma_dither_f32_rectangle(ditherMin, ditherMax),
36966  ma_dither_f32_rectangle(ditherMin, ditherMax),
36967  ma_dither_f32_rectangle(ditherMin, ditherMax),
36968  ma_dither_f32_rectangle(ditherMin, ditherMax),
36969  ma_dither_f32_rectangle(ditherMin, ditherMax),
36970  ma_dither_f32_rectangle(ditherMin, ditherMax)
36971  );
36972  } else {
36973  d0 = _mm256_set_ps(
36974  ma_dither_f32_triangle(ditherMin, ditherMax),
36975  ma_dither_f32_triangle(ditherMin, ditherMax),
36976  ma_dither_f32_triangle(ditherMin, ditherMax),
36977  ma_dither_f32_triangle(ditherMin, ditherMax),
36978  ma_dither_f32_triangle(ditherMin, ditherMax),
36979  ma_dither_f32_triangle(ditherMin, ditherMax),
36980  ma_dither_f32_triangle(ditherMin, ditherMax),
36981  ma_dither_f32_triangle(ditherMin, ditherMax)
36982  );
36983  d1 = _mm256_set_ps(
36984  ma_dither_f32_triangle(ditherMin, ditherMax),
36985  ma_dither_f32_triangle(ditherMin, ditherMax),
36986  ma_dither_f32_triangle(ditherMin, ditherMax),
36987  ma_dither_f32_triangle(ditherMin, ditherMax),
36988  ma_dither_f32_triangle(ditherMin, ditherMax),
36989  ma_dither_f32_triangle(ditherMin, ditherMax),
36990  ma_dither_f32_triangle(ditherMin, ditherMax),
36991  ma_dither_f32_triangle(ditherMin, ditherMax)
36992  );
36993  }
36994 
36995  x0 = *((__m256*)(src_f32 + i) + 0);
36996  x1 = *((__m256*)(src_f32 + i) + 1);
36997 
36998  x0 = _mm256_add_ps(x0, d0);
36999  x1 = _mm256_add_ps(x1, d1);
37000 
37001  x0 = _mm256_mul_ps(x0, _mm256_set1_ps(32767.0f));
37002  x1 = _mm256_mul_ps(x1, _mm256_set1_ps(32767.0f));
37003 
37004  /* Computing the final result is a little more complicated for AVX2 than SSE2. */
37005  i0 = _mm256_cvttps_epi32(x0);
37006  i1 = _mm256_cvttps_epi32(x1);
37007  p0 = _mm256_permute2x128_si256(i0, i1, 0 | 32);
37008  p1 = _mm256_permute2x128_si256(i0, i1, 1 | 48);
37009  r = _mm256_packs_epi32(p0, p1);
37010 
37011  _mm256_stream_si256(((__m256i*)(dst_s16 + i)), r);
37012 
37013  i += 16;
37014  }
37015 
37016 
37017  /* Leftover. */
37018  for (; i < count; i += 1) {
37019  float x = src_f32[i];
37020  x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
37021  x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */
37022  x = x * 32767.0f; /* -1..1 to -32767..32767 */
37023 
37024  dst_s16[i] = (ma_int16)x;
37025  }
37026 }
37027 #endif /* AVX2 */
37028 
37029 #if defined(MA_SUPPORT_NEON)
37030 static MA_INLINE void ma_pcm_f32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37031 {
37032  ma_uint64 i;
37033  ma_uint64 i8;
37034  ma_uint64 count8;
37035  ma_int16* dst_s16;
37036  const float* src_f32;
37037  float ditherMin;
37038  float ditherMax;
37039 
37040  if (!ma_has_neon()) {
37041  return ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
37042  }
37043 
37044  /* Both the input and output buffers need to be aligned to 16 bytes. */
37045  if ((((ma_uintptr)dst & 15) != 0) || (((ma_uintptr)src & 15) != 0)) {
37046  ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
37047  return;
37048  }
37049 
37050  dst_s16 = (ma_int16*)dst;
37051  src_f32 = (const float*)src;
37052 
37053  ditherMin = 0;
37054  ditherMax = 0;
37055  if (ditherMode != ma_dither_mode_none) {
37056  ditherMin = 1.0f / -32768;
37057  ditherMax = 1.0f / 32767;
37058  }
37059 
37060  i = 0;
37061 
37062  /* NEON. NEON allows us to output 8 s16's at a time which means our loop is unrolled 8 times. */
37063  count8 = count >> 3;
37064  for (i8 = 0; i8 < count8; i8 += 1) {
37065  float32x4_t d0;
37066  float32x4_t d1;
37067  float32x4_t x0;
37068  float32x4_t x1;
37069  int32x4_t i0;
37070  int32x4_t i1;
37071 
37072  if (ditherMode == ma_dither_mode_none) {
37073  d0 = vmovq_n_f32(0);
37074  d1 = vmovq_n_f32(0);
37075  } else if (ditherMode == ma_dither_mode_rectangle) {
37076  float d0v[4];
37077  d0v[0] = ma_dither_f32_rectangle(ditherMin, ditherMax);
37078  d0v[1] = ma_dither_f32_rectangle(ditherMin, ditherMax);
37079  d0v[2] = ma_dither_f32_rectangle(ditherMin, ditherMax);
37080  d0v[3] = ma_dither_f32_rectangle(ditherMin, ditherMax);
37081  d0 = vld1q_f32(d0v);
37082 
37083  float d1v[4];
37084  d1v[0] = ma_dither_f32_rectangle(ditherMin, ditherMax);
37085  d1v[1] = ma_dither_f32_rectangle(ditherMin, ditherMax);
37086  d1v[2] = ma_dither_f32_rectangle(ditherMin, ditherMax);
37087  d1v[3] = ma_dither_f32_rectangle(ditherMin, ditherMax);
37088  d1 = vld1q_f32(d1v);
37089  } else {
37090  float d0v[4];
37091  d0v[0] = ma_dither_f32_triangle(ditherMin, ditherMax);
37092  d0v[1] = ma_dither_f32_triangle(ditherMin, ditherMax);
37093  d0v[2] = ma_dither_f32_triangle(ditherMin, ditherMax);
37094  d0v[3] = ma_dither_f32_triangle(ditherMin, ditherMax);
37095  d0 = vld1q_f32(d0v);
37096 
37097  float d1v[4];
37098  d1v[0] = ma_dither_f32_triangle(ditherMin, ditherMax);
37099  d1v[1] = ma_dither_f32_triangle(ditherMin, ditherMax);
37100  d1v[2] = ma_dither_f32_triangle(ditherMin, ditherMax);
37101  d1v[3] = ma_dither_f32_triangle(ditherMin, ditherMax);
37102  d1 = vld1q_f32(d1v);
37103  }
37104 
37105  x0 = *((float32x4_t*)(src_f32 + i) + 0);
37106  x1 = *((float32x4_t*)(src_f32 + i) + 1);
37107 
37108  x0 = vaddq_f32(x0, d0);
37109  x1 = vaddq_f32(x1, d1);
37110 
37111  x0 = vmulq_n_f32(x0, 32767.0f);
37112  x1 = vmulq_n_f32(x1, 32767.0f);
37113 
37114  i0 = vcvtq_s32_f32(x0);
37115  i1 = vcvtq_s32_f32(x1);
37116  *((int16x8_t*)(dst_s16 + i)) = vcombine_s16(vqmovn_s32(i0), vqmovn_s32(i1));
37117 
37118  i += 8;
37119  }
37120 
37121 
37122  /* Leftover. */
37123  for (; i < count; i += 1) {
37124  float x = src_f32[i];
37125  x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
37126  x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */
37127  x = x * 32767.0f; /* -1..1 to -32767..32767 */
37128 
37129  dst_s16[i] = (ma_int16)x;
37130  }
37131 }
37132 #endif /* Neon */
37133 #endif /* MA_USE_REFERENCE_CONVERSION_APIS */
37134 
37135 void ma_pcm_f32_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37136 {
37137 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
37138  ma_pcm_f32_to_s16__reference(dst, src, count, ditherMode);
37139 #else
37140  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
37141  if (ma_has_avx2()) {
37142  ma_pcm_f32_to_s16__avx2(dst, src, count, ditherMode);
37143  } else
37144  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
37145  if (ma_has_sse2()) {
37146  ma_pcm_f32_to_s16__sse2(dst, src, count, ditherMode);
37147  } else
37148  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
37149  if (ma_has_neon()) {
37150  ma_pcm_f32_to_s16__neon(dst, src, count, ditherMode);
37151  } else
37152  #endif
37153  {
37154  ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
37155  }
37156 #endif
37157 }
37158 
37159 
37160 static MA_INLINE void ma_pcm_f32_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37161 {
37162  ma_uint8* dst_s24 = (ma_uint8*)dst;
37163  const float* src_f32 = (const float*)src;
37164 
37165  ma_uint64 i;
37166  for (i = 0; i < count; i += 1) {
37167  ma_int32 r;
37168  float x = src_f32[i];
37169  x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */
37170 
37171 #if 0
37172  /* The accurate way. */
37173  x = x + 1; /* -1..1 to 0..2 */
37174  x = x * 8388607.5f; /* 0..2 to 0..16777215 */
37175  x = x - 8388608.0f; /* 0..16777215 to -8388608..8388607 */
37176 #else
37177  /* The fast way. */
37178  x = x * 8388607.0f; /* -1..1 to -8388607..8388607 */
37179 #endif
37180 
37181  r = (ma_int32)x;
37182  dst_s24[(i*3)+0] = (ma_uint8)((r & 0x0000FF) >> 0);
37183  dst_s24[(i*3)+1] = (ma_uint8)((r & 0x00FF00) >> 8);
37184  dst_s24[(i*3)+2] = (ma_uint8)((r & 0xFF0000) >> 16);
37185  }
37186 
37187  (void)ditherMode; /* No dithering for f32 -> s24. */
37188 }
37189 
37190 static MA_INLINE void ma_pcm_f32_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37191 {
37192  ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode);
37193 }
37194 
37195 #if defined(MA_SUPPORT_SSE2)
37196 static MA_INLINE void ma_pcm_f32_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37197 {
37198  ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
37199 }
37200 #endif
37201 #if defined(MA_SUPPORT_AVX2)
37202 static MA_INLINE void ma_pcm_f32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37203 {
37204  ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
37205 }
37206 #endif
37207 #if defined(MA_SUPPORT_NEON)
37208 static MA_INLINE void ma_pcm_f32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37209 {
37210  ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
37211 }
37212 #endif
37213 
37214 void ma_pcm_f32_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37215 {
37216 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
37217  ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode);
37218 #else
37219  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
37220  if (ma_has_avx2()) {
37221  ma_pcm_f32_to_s24__avx2(dst, src, count, ditherMode);
37222  } else
37223  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
37224  if (ma_has_sse2()) {
37225  ma_pcm_f32_to_s24__sse2(dst, src, count, ditherMode);
37226  } else
37227  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
37228  if (ma_has_neon()) {
37229  ma_pcm_f32_to_s24__neon(dst, src, count, ditherMode);
37230  } else
37231  #endif
37232  {
37233  ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
37234  }
37235 #endif
37236 }
37237 
37238 
37239 static MA_INLINE void ma_pcm_f32_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37240 {
37241  ma_int32* dst_s32 = (ma_int32*)dst;
37242  const float* src_f32 = (const float*)src;
37243 
37244  ma_uint32 i;
37245  for (i = 0; i < count; i += 1) {
37246  double x = src_f32[i];
37247  x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */
37248 
37249 #if 0
37250  /* The accurate way. */
37251  x = x + 1; /* -1..1 to 0..2 */
37252  x = x * 2147483647.5; /* 0..2 to 0..4294967295 */
37253  x = x - 2147483648.0; /* 0...4294967295 to -2147483648..2147483647 */
37254 #else
37255  /* The fast way. */
37256  x = x * 2147483647.0; /* -1..1 to -2147483647..2147483647 */
37257 #endif
37258 
37259  dst_s32[i] = (ma_int32)x;
37260  }
37261 
37262  (void)ditherMode; /* No dithering for f32 -> s32. */
37263 }
37264 
37265 static MA_INLINE void ma_pcm_f32_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37266 {
37267  ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode);
37268 }
37269 
37270 #if defined(MA_SUPPORT_SSE2)
37271 static MA_INLINE void ma_pcm_f32_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37272 {
37273  ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
37274 }
37275 #endif
37276 #if defined(MA_SUPPORT_AVX2)
37277 static MA_INLINE void ma_pcm_f32_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37278 {
37279  ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
37280 }
37281 #endif
37282 #if defined(MA_SUPPORT_NEON)
37283 static MA_INLINE void ma_pcm_f32_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37284 {
37285  ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
37286 }
37287 #endif
37288 
37289 void ma_pcm_f32_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37290 {
37291 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
37292  ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode);
37293 #else
37294  # if MA_PREFERRED_SIMD == MA_SIMD_AVX2
37295  if (ma_has_avx2()) {
37296  ma_pcm_f32_to_s32__avx2(dst, src, count, ditherMode);
37297  } else
37298  #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
37299  if (ma_has_sse2()) {
37300  ma_pcm_f32_to_s32__sse2(dst, src, count, ditherMode);
37301  } else
37302  #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
37303  if (ma_has_neon()) {
37304  ma_pcm_f32_to_s32__neon(dst, src, count, ditherMode);
37305  } else
37306  #endif
37307  {
37308  ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
37309  }
37310 #endif
37311 }
37312 
37313 
37314 void ma_pcm_f32_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
37315 {
37316  (void)ditherMode;
37317 
37318  ma_copy_memory_64(dst, src, count * sizeof(float));
37319 }
37320 
37321 
37322 static void ma_pcm_interleave_f32__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
37323 {
37324  float* dst_f32 = (float*)dst;
37325  const float** src_f32 = (const float**)src;
37326 
37327  ma_uint64 iFrame;
37328  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
37329  ma_uint32 iChannel;
37330  for (iChannel = 0; iChannel < channels; iChannel += 1) {
37331  dst_f32[iFrame*channels + iChannel] = src_f32[iChannel][iFrame];
37332  }
37333  }
37334 }
37335 
37336 static void ma_pcm_interleave_f32__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
37337 {
37338  ma_pcm_interleave_f32__reference(dst, src, frameCount, channels);
37339 }
37340 
37341 void ma_pcm_interleave_f32(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
37342 {
37343 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
37344  ma_pcm_interleave_f32__reference(dst, src, frameCount, channels);
37345 #else
37346  ma_pcm_interleave_f32__optimized(dst, src, frameCount, channels);
37347 #endif
37348 }
37349 
37350 
37351 static void ma_pcm_deinterleave_f32__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
37352 {
37353  float** dst_f32 = (float**)dst;
37354  const float* src_f32 = (const float*)src;
37355 
37356  ma_uint64 iFrame;
37357  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
37358  ma_uint32 iChannel;
37359  for (iChannel = 0; iChannel < channels; iChannel += 1) {
37360  dst_f32[iChannel][iFrame] = src_f32[iFrame*channels + iChannel];
37361  }
37362  }
37363 }
37364 
37365 static void ma_pcm_deinterleave_f32__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
37366 {
37367  ma_pcm_deinterleave_f32__reference(dst, src, frameCount, channels);
37368 }
37369 
37370 void ma_pcm_deinterleave_f32(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
37371 {
37372 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
37373  ma_pcm_deinterleave_f32__reference(dst, src, frameCount, channels);
37374 #else
37375  ma_pcm_deinterleave_f32__optimized(dst, src, frameCount, channels);
37376 #endif
37377 }
37378 
37379 
37380 void ma_pcm_convert(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 sampleCount, ma_dither_mode ditherMode)
37381 {
37382  if (formatOut == formatIn) {
37383  ma_copy_memory_64(pOut, pIn, sampleCount * ma_get_bytes_per_sample(formatOut));
37384  return;
37385  }
37386 
37387  switch (formatIn)
37388  {
37389  case ma_format_u8:
37390  {
37391  switch (formatOut)
37392  {
37393  case ma_format_s16: ma_pcm_u8_to_s16(pOut, pIn, sampleCount, ditherMode); return;
37394  case ma_format_s24: ma_pcm_u8_to_s24(pOut, pIn, sampleCount, ditherMode); return;
37395  case ma_format_s32: ma_pcm_u8_to_s32(pOut, pIn, sampleCount, ditherMode); return;
37396  case ma_format_f32: ma_pcm_u8_to_f32(pOut, pIn, sampleCount, ditherMode); return;
37397  default: break;
37398  }
37399  } break;
37400 
37401  case ma_format_s16:
37402  {
37403  switch (formatOut)
37404  {
37405  case ma_format_u8: ma_pcm_s16_to_u8( pOut, pIn, sampleCount, ditherMode); return;
37406  case ma_format_s24: ma_pcm_s16_to_s24(pOut, pIn, sampleCount, ditherMode); return;
37407  case ma_format_s32: ma_pcm_s16_to_s32(pOut, pIn, sampleCount, ditherMode); return;
37408  case ma_format_f32: ma_pcm_s16_to_f32(pOut, pIn, sampleCount, ditherMode); return;
37409  default: break;
37410  }
37411  } break;
37412 
37413  case ma_format_s24:
37414  {
37415  switch (formatOut)
37416  {
37417  case ma_format_u8: ma_pcm_s24_to_u8( pOut, pIn, sampleCount, ditherMode); return;
37418  case ma_format_s16: ma_pcm_s24_to_s16(pOut, pIn, sampleCount, ditherMode); return;
37419  case ma_format_s32: ma_pcm_s24_to_s32(pOut, pIn, sampleCount, ditherMode); return;
37420  case ma_format_f32: ma_pcm_s24_to_f32(pOut, pIn, sampleCount, ditherMode); return;
37421  default: break;
37422  }
37423  } break;
37424 
37425  case ma_format_s32:
37426  {
37427  switch (formatOut)
37428  {
37429  case ma_format_u8: ma_pcm_s32_to_u8( pOut, pIn, sampleCount, ditherMode); return;
37430  case ma_format_s16: ma_pcm_s32_to_s16(pOut, pIn, sampleCount, ditherMode); return;
37431  case ma_format_s24: ma_pcm_s32_to_s24(pOut, pIn, sampleCount, ditherMode); return;
37432  case ma_format_f32: ma_pcm_s32_to_f32(pOut, pIn, sampleCount, ditherMode); return;
37433  default: break;
37434  }
37435  } break;
37436 
37437  case ma_format_f32:
37438  {
37439  switch (formatOut)
37440  {
37441  case ma_format_u8: ma_pcm_f32_to_u8( pOut, pIn, sampleCount, ditherMode); return;
37442  case ma_format_s16: ma_pcm_f32_to_s16(pOut, pIn, sampleCount, ditherMode); return;
37443  case ma_format_s24: ma_pcm_f32_to_s24(pOut, pIn, sampleCount, ditherMode); return;
37444  case ma_format_s32: ma_pcm_f32_to_s32(pOut, pIn, sampleCount, ditherMode); return;
37445  default: break;
37446  }
37447  } break;
37448 
37449  default: break;
37450  }
37451 }
37452 
37453 void ma_convert_pcm_frames_format(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 frameCount, ma_uint32 channels, ma_dither_mode ditherMode)
37454 {
37455  ma_pcm_convert(pOut, formatOut, pIn, formatIn, frameCount * channels, ditherMode);
37456 }
37457 
37458 void ma_deinterleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void* pInterleavedPCMFrames, void** ppDeinterleavedPCMFrames)
37459 {
37460  if (pInterleavedPCMFrames == NULL || ppDeinterleavedPCMFrames == NULL) {
37461  return; /* Invalid args. */
37462  }
37463 
37464  /* For efficiency we do this per format. */
37465  switch (format) {
37466  case ma_format_s16:
37467  {
37468  const ma_int16* pSrcS16 = (const ma_int16*)pInterleavedPCMFrames;
37469  ma_uint64 iPCMFrame;
37470  for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
37471  ma_uint32 iChannel;
37472  for (iChannel = 0; iChannel < channels; ++iChannel) {
37473  ma_int16* pDstS16 = (ma_int16*)ppDeinterleavedPCMFrames[iChannel];
37474  pDstS16[iPCMFrame] = pSrcS16[iPCMFrame*channels+iChannel];
37475  }
37476  }
37477  } break;
37478 
37479  case ma_format_f32:
37480  {
37481  const float* pSrcF32 = (const float*)pInterleavedPCMFrames;
37482  ma_uint64 iPCMFrame;
37483  for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
37484  ma_uint32 iChannel;
37485  for (iChannel = 0; iChannel < channels; ++iChannel) {
37486  float* pDstF32 = (float*)ppDeinterleavedPCMFrames[iChannel];
37487  pDstF32[iPCMFrame] = pSrcF32[iPCMFrame*channels+iChannel];
37488  }
37489  }
37490  } break;
37491 
37492  default:
37493  {
37494  ma_uint32 sampleSizeInBytes = ma_get_bytes_per_sample(format);
37495  ma_uint64 iPCMFrame;
37496  for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
37497  ma_uint32 iChannel;
37498  for (iChannel = 0; iChannel < channels; ++iChannel) {
37499  void* pDst = ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel], iPCMFrame*sampleSizeInBytes);
37500  const void* pSrc = ma_offset_ptr(pInterleavedPCMFrames, (iPCMFrame*channels+iChannel)*sampleSizeInBytes);
37501  memcpy(pDst, pSrc, sampleSizeInBytes);
37502  }
37503  }
37504  } break;
37505  }
37506 }
37507 
37508 void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames)
37509 {
37510  switch (format)
37511  {
37512  case ma_format_s16:
37513  {
37514  ma_int16* pDstS16 = (ma_int16*)pInterleavedPCMFrames;
37515  ma_uint64 iPCMFrame;
37516  for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
37517  ma_uint32 iChannel;
37518  for (iChannel = 0; iChannel < channels; ++iChannel) {
37519  const ma_int16* pSrcS16 = (const ma_int16*)ppDeinterleavedPCMFrames[iChannel];
37520  pDstS16[iPCMFrame*channels+iChannel] = pSrcS16[iPCMFrame];
37521  }
37522  }
37523  } break;
37524 
37525  case ma_format_f32:
37526  {
37527  float* pDstF32 = (float*)pInterleavedPCMFrames;
37528  ma_uint64 iPCMFrame;
37529  for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
37530  ma_uint32 iChannel;
37531  for (iChannel = 0; iChannel < channels; ++iChannel) {
37532  const float* pSrcF32 = (const float*)ppDeinterleavedPCMFrames[iChannel];
37533  pDstF32[iPCMFrame*channels+iChannel] = pSrcF32[iPCMFrame];
37534  }
37535  }
37536  } break;
37537 
37538  default:
37539  {
37540  ma_uint32 sampleSizeInBytes = ma_get_bytes_per_sample(format);
37541  ma_uint64 iPCMFrame;
37542  for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
37543  ma_uint32 iChannel;
37544  for (iChannel = 0; iChannel < channels; ++iChannel) {
37545  void* pDst = ma_offset_ptr(pInterleavedPCMFrames, (iPCMFrame*channels+iChannel)*sampleSizeInBytes);
37546  const void* pSrc = ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel], iPCMFrame*sampleSizeInBytes);
37547  memcpy(pDst, pSrc, sampleSizeInBytes);
37548  }
37549  }
37550  } break;
37551  }
37552 }
37553 
37554 
37555 
37556 /**************************************************************************************************************************************************************
37557 
37558 Channel Maps
37559 
37560 **************************************************************************************************************************************************************/
37562 {
37563  /* Based off the speaker configurations mentioned here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-ksaudio_channel_config */
37564  switch (channels)
37565  {
37566  case 1:
37567  {
37568  channelMap[0] = MA_CHANNEL_MONO;
37569  } break;
37570 
37571  case 2:
37572  {
37573  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37574  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37575  } break;
37576 
37577  case 3: /* Not defined, but best guess. */
37578  {
37579  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37580  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37581  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37582  } break;
37583 
37584  case 4:
37585  {
37586 #ifndef MA_USE_QUAD_MICROSOFT_CHANNEL_MAP
37587  /* Surround. Using the Surround profile has the advantage of the 3rd channel (MA_CHANNEL_FRONT_CENTER) mapping nicely with higher channel counts. */
37588  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37589  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37590  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37591  channelMap[3] = MA_CHANNEL_BACK_CENTER;
37592 #else
37593  /* Quad. */
37594  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37595  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37596  channelMap[2] = MA_CHANNEL_BACK_LEFT;
37597  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
37598 #endif
37599  } break;
37600 
37601  case 5: /* Not defined, but best guess. */
37602  {
37603  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37604  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37605  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37606  channelMap[3] = MA_CHANNEL_BACK_LEFT;
37607  channelMap[4] = MA_CHANNEL_BACK_RIGHT;
37608  } break;
37609 
37610  case 6:
37611  {
37612  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37613  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37614  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37615  channelMap[3] = MA_CHANNEL_LFE;
37616  channelMap[4] = MA_CHANNEL_SIDE_LEFT;
37617  channelMap[5] = MA_CHANNEL_SIDE_RIGHT;
37618  } break;
37619 
37620  case 7: /* Not defined, but best guess. */
37621  {
37622  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37623  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37624  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37625  channelMap[3] = MA_CHANNEL_LFE;
37626  channelMap[4] = MA_CHANNEL_BACK_CENTER;
37627  channelMap[5] = MA_CHANNEL_SIDE_LEFT;
37628  channelMap[6] = MA_CHANNEL_SIDE_RIGHT;
37629  } break;
37630 
37631  case 8:
37632  default:
37633  {
37634  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37635  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37636  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37637  channelMap[3] = MA_CHANNEL_LFE;
37638  channelMap[4] = MA_CHANNEL_BACK_LEFT;
37639  channelMap[5] = MA_CHANNEL_BACK_RIGHT;
37640  channelMap[6] = MA_CHANNEL_SIDE_LEFT;
37641  channelMap[7] = MA_CHANNEL_SIDE_RIGHT;
37642  } break;
37643  }
37644 
37645  /* Remainder. */
37646  if (channels > 8) {
37647  ma_uint32 iChannel;
37648  for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) {
37649  channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
37650  }
37651  }
37652 }
37653 
37654 static void ma_get_standard_channel_map_alsa(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS])
37655 {
37656  switch (channels)
37657  {
37658  case 1:
37659  {
37660  channelMap[0] = MA_CHANNEL_MONO;
37661  } break;
37662 
37663  case 2:
37664  {
37665  channelMap[0] = MA_CHANNEL_LEFT;
37666  channelMap[1] = MA_CHANNEL_RIGHT;
37667  } break;
37668 
37669  case 3:
37670  {
37671  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37672  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37673  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37674  } break;
37675 
37676  case 4:
37677  {
37678  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37679  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37680  channelMap[2] = MA_CHANNEL_BACK_LEFT;
37681  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
37682  } break;
37683 
37684  case 5:
37685  {
37686  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37687  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37688  channelMap[2] = MA_CHANNEL_BACK_LEFT;
37689  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
37690  channelMap[4] = MA_CHANNEL_FRONT_CENTER;
37691  } break;
37692 
37693  case 6:
37694  {
37695  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37696  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37697  channelMap[2] = MA_CHANNEL_BACK_LEFT;
37698  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
37699  channelMap[4] = MA_CHANNEL_FRONT_CENTER;
37700  channelMap[5] = MA_CHANNEL_LFE;
37701  } break;
37702 
37703  case 7:
37704  {
37705  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37706  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37707  channelMap[2] = MA_CHANNEL_BACK_LEFT;
37708  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
37709  channelMap[4] = MA_CHANNEL_FRONT_CENTER;
37710  channelMap[5] = MA_CHANNEL_LFE;
37711  channelMap[6] = MA_CHANNEL_BACK_CENTER;
37712  } break;
37713 
37714  case 8:
37715  default:
37716  {
37717  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37718  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37719  channelMap[2] = MA_CHANNEL_BACK_LEFT;
37720  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
37721  channelMap[4] = MA_CHANNEL_FRONT_CENTER;
37722  channelMap[5] = MA_CHANNEL_LFE;
37723  channelMap[6] = MA_CHANNEL_SIDE_LEFT;
37724  channelMap[7] = MA_CHANNEL_SIDE_RIGHT;
37725  } break;
37726  }
37727 
37728  /* Remainder. */
37729  if (channels > 8) {
37730  ma_uint32 iChannel;
37731  for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) {
37732  channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
37733  }
37734  }
37735 }
37736 
37738 {
37739  switch (channels)
37740  {
37741  case 1:
37742  {
37743  channelMap[0] = MA_CHANNEL_MONO;
37744  } break;
37745 
37746  case 2:
37747  {
37748  channelMap[0] = MA_CHANNEL_LEFT;
37749  channelMap[1] = MA_CHANNEL_RIGHT;
37750  } break;
37751 
37752  case 3:
37753  {
37754  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37755  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37756  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37757  } break;
37758 
37759  case 4:
37760  {
37761  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37762  channelMap[1] = MA_CHANNEL_FRONT_CENTER;
37763  channelMap[2] = MA_CHANNEL_FRONT_RIGHT;
37764  channelMap[3] = MA_CHANNEL_BACK_CENTER;
37765  } break;
37766 
37767  case 5:
37768  {
37769  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37770  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37771  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37772  channelMap[3] = MA_CHANNEL_BACK_LEFT;
37773  channelMap[4] = MA_CHANNEL_BACK_RIGHT;
37774  } break;
37775 
37776  case 6:
37777  {
37778  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37779  channelMap[1] = MA_CHANNEL_SIDE_LEFT;
37780  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37781  channelMap[3] = MA_CHANNEL_FRONT_RIGHT;
37782  channelMap[4] = MA_CHANNEL_SIDE_RIGHT;
37783  channelMap[5] = MA_CHANNEL_BACK_CENTER;
37784  } break;
37785  }
37786 
37787  /* Remainder. */
37788  if (channels > 8) {
37789  ma_uint32 iChannel;
37790  for (iChannel = 6; iChannel < MA_MAX_CHANNELS; ++iChannel) {
37791  channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6));
37792  }
37793  }
37794 }
37795 
37796 static void ma_get_standard_channel_map_flac(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS])
37797 {
37798  switch (channels)
37799  {
37800  case 1:
37801  {
37802  channelMap[0] = MA_CHANNEL_MONO;
37803  } break;
37804 
37805  case 2:
37806  {
37807  channelMap[0] = MA_CHANNEL_LEFT;
37808  channelMap[1] = MA_CHANNEL_RIGHT;
37809  } break;
37810 
37811  case 3:
37812  {
37813  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37814  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37815  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37816  } break;
37817 
37818  case 4:
37819  {
37820  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37821  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37822  channelMap[2] = MA_CHANNEL_BACK_LEFT;
37823  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
37824  } break;
37825 
37826  case 5:
37827  {
37828  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37829  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37830  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37831  channelMap[3] = MA_CHANNEL_BACK_LEFT;
37832  channelMap[4] = MA_CHANNEL_BACK_RIGHT;
37833  } break;
37834 
37835  case 6:
37836  {
37837  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37838  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37839  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37840  channelMap[3] = MA_CHANNEL_LFE;
37841  channelMap[4] = MA_CHANNEL_BACK_LEFT;
37842  channelMap[5] = MA_CHANNEL_BACK_RIGHT;
37843  } break;
37844 
37845  case 7:
37846  {
37847  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37848  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37849  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37850  channelMap[3] = MA_CHANNEL_LFE;
37851  channelMap[4] = MA_CHANNEL_BACK_CENTER;
37852  channelMap[5] = MA_CHANNEL_SIDE_LEFT;
37853  channelMap[6] = MA_CHANNEL_SIDE_RIGHT;
37854  } break;
37855 
37856  case 8:
37857  default:
37858  {
37859  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37860  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37861  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
37862  channelMap[3] = MA_CHANNEL_LFE;
37863  channelMap[4] = MA_CHANNEL_BACK_LEFT;
37864  channelMap[5] = MA_CHANNEL_BACK_RIGHT;
37865  channelMap[6] = MA_CHANNEL_SIDE_LEFT;
37866  channelMap[7] = MA_CHANNEL_SIDE_RIGHT;
37867  } break;
37868  }
37869 
37870  /* Remainder. */
37871  if (channels > 8) {
37872  ma_uint32 iChannel;
37873  for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) {
37874  channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
37875  }
37876  }
37877 }
37878 
37880 {
37881  /* In Vorbis' type 0 channel mapping, the first two channels are not always the standard left/right - it will have the center speaker where the right usually goes. Why?! */
37882  switch (channels)
37883  {
37884  case 1:
37885  {
37886  channelMap[0] = MA_CHANNEL_MONO;
37887  } break;
37888 
37889  case 2:
37890  {
37891  channelMap[0] = MA_CHANNEL_LEFT;
37892  channelMap[1] = MA_CHANNEL_RIGHT;
37893  } break;
37894 
37895  case 3:
37896  {
37897  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37898  channelMap[1] = MA_CHANNEL_FRONT_CENTER;
37899  channelMap[2] = MA_CHANNEL_FRONT_RIGHT;
37900  } break;
37901 
37902  case 4:
37903  {
37904  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37905  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37906  channelMap[2] = MA_CHANNEL_BACK_LEFT;
37907  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
37908  } break;
37909 
37910  case 5:
37911  {
37912  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37913  channelMap[1] = MA_CHANNEL_FRONT_CENTER;
37914  channelMap[2] = MA_CHANNEL_FRONT_RIGHT;
37915  channelMap[3] = MA_CHANNEL_BACK_LEFT;
37916  channelMap[4] = MA_CHANNEL_BACK_RIGHT;
37917  } break;
37918 
37919  case 6:
37920  {
37921  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37922  channelMap[1] = MA_CHANNEL_FRONT_CENTER;
37923  channelMap[2] = MA_CHANNEL_FRONT_RIGHT;
37924  channelMap[3] = MA_CHANNEL_BACK_LEFT;
37925  channelMap[4] = MA_CHANNEL_BACK_RIGHT;
37926  channelMap[5] = MA_CHANNEL_LFE;
37927  } break;
37928 
37929  case 7:
37930  {
37931  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37932  channelMap[1] = MA_CHANNEL_FRONT_CENTER;
37933  channelMap[2] = MA_CHANNEL_FRONT_RIGHT;
37934  channelMap[3] = MA_CHANNEL_SIDE_LEFT;
37935  channelMap[4] = MA_CHANNEL_SIDE_RIGHT;
37936  channelMap[5] = MA_CHANNEL_BACK_CENTER;
37937  channelMap[6] = MA_CHANNEL_LFE;
37938  } break;
37939 
37940  case 8:
37941  default:
37942  {
37943  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37944  channelMap[1] = MA_CHANNEL_FRONT_CENTER;
37945  channelMap[2] = MA_CHANNEL_FRONT_RIGHT;
37946  channelMap[3] = MA_CHANNEL_SIDE_LEFT;
37947  channelMap[4] = MA_CHANNEL_SIDE_RIGHT;
37948  channelMap[5] = MA_CHANNEL_BACK_LEFT;
37949  channelMap[6] = MA_CHANNEL_BACK_RIGHT;
37950  channelMap[7] = MA_CHANNEL_LFE;
37951  } break;
37952  }
37953 
37954  /* Remainder. */
37955  if (channels > 8) {
37956  ma_uint32 iChannel;
37957  for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) {
37958  channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
37959  }
37960  }
37961 }
37962 
37964 {
37965  switch (channels)
37966  {
37967  case 1:
37968  {
37969  channelMap[0] = MA_CHANNEL_MONO;
37970  } break;
37971 
37972  case 2:
37973  {
37974  channelMap[0] = MA_CHANNEL_LEFT;
37975  channelMap[1] = MA_CHANNEL_RIGHT;
37976  } break;
37977 
37978  case 3:
37979  {
37980  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37981  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37982  channelMap[2] = MA_CHANNEL_BACK_CENTER;
37983  } break;
37984 
37985  case 4:
37986  {
37987  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37988  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37989  channelMap[2] = MA_CHANNEL_BACK_LEFT;
37990  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
37991  } break;
37992 
37993  case 5:
37994  {
37995  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
37996  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
37997  channelMap[2] = MA_CHANNEL_BACK_LEFT;
37998  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
37999  channelMap[4] = MA_CHANNEL_FRONT_CENTER;
38000  } break;
38001 
38002  case 6:
38003  {
38004  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
38005  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
38006  channelMap[2] = MA_CHANNEL_BACK_LEFT;
38007  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
38008  channelMap[4] = MA_CHANNEL_FRONT_CENTER;
38009  channelMap[5] = MA_CHANNEL_LFE;
38010  } break;
38011 
38012  case 7:
38013  {
38014  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
38015  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
38016  channelMap[2] = MA_CHANNEL_BACK_LEFT;
38017  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
38018  channelMap[4] = MA_CHANNEL_FRONT_CENTER;
38019  channelMap[5] = MA_CHANNEL_BACK_CENTER;
38020  channelMap[6] = MA_CHANNEL_LFE;
38021  } break;
38022 
38023  case 8:
38024  default:
38025  {
38026  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
38027  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
38028  channelMap[2] = MA_CHANNEL_BACK_LEFT;
38029  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
38030  channelMap[4] = MA_CHANNEL_FRONT_CENTER;
38031  channelMap[5] = MA_CHANNEL_LFE;
38032  channelMap[6] = MA_CHANNEL_SIDE_LEFT;
38033  channelMap[7] = MA_CHANNEL_SIDE_RIGHT;
38034  } break;
38035  }
38036 
38037  /* Remainder. */
38038  if (channels > 8) {
38039  ma_uint32 iChannel;
38040  for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) {
38041  channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
38042  }
38043  }
38044 }
38045 
38046 static void ma_get_standard_channel_map_sndio(ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS])
38047 {
38048  switch (channels)
38049  {
38050  case 1:
38051  {
38052  channelMap[0] = MA_CHANNEL_MONO;
38053  } break;
38054 
38055  case 2:
38056  {
38057  channelMap[0] = MA_CHANNEL_LEFT;
38058  channelMap[1] = MA_CHANNEL_RIGHT;
38059  } break;
38060 
38061  case 3:
38062  {
38063  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
38064  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
38065  channelMap[2] = MA_CHANNEL_FRONT_CENTER;
38066  } break;
38067 
38068  case 4:
38069  {
38070  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
38071  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
38072  channelMap[2] = MA_CHANNEL_BACK_LEFT;
38073  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
38074  } break;
38075 
38076  case 5:
38077  {
38078  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
38079  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
38080  channelMap[2] = MA_CHANNEL_BACK_LEFT;
38081  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
38082  channelMap[4] = MA_CHANNEL_FRONT_CENTER;
38083  } break;
38084 
38085  case 6:
38086  default:
38087  {
38088  channelMap[0] = MA_CHANNEL_FRONT_LEFT;
38089  channelMap[1] = MA_CHANNEL_FRONT_RIGHT;
38090  channelMap[2] = MA_CHANNEL_BACK_LEFT;
38091  channelMap[3] = MA_CHANNEL_BACK_RIGHT;
38092  channelMap[4] = MA_CHANNEL_FRONT_CENTER;
38093  channelMap[5] = MA_CHANNEL_LFE;
38094  } break;
38095  }
38096 
38097  /* Remainder. */
38098  if (channels > 6) {
38099  ma_uint32 iChannel;
38100  for (iChannel = 6; iChannel < MA_MAX_CHANNELS; ++iChannel) {
38101  channelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6));
38102  }
38103  }
38104 }
38105 
38106 void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS])
38107 {
38108  switch (standardChannelMap)
38109  {
38111  {
38112  ma_get_standard_channel_map_alsa(channels, channelMap);
38113  } break;
38114 
38116  {
38117  ma_get_standard_channel_map_rfc3551(channels, channelMap);
38118  } break;
38119 
38121  {
38122  ma_get_standard_channel_map_flac(channels, channelMap);
38123  } break;
38124 
38126  {
38127  ma_get_standard_channel_map_vorbis(channels, channelMap);
38128  } break;
38129 
38131  {
38132  ma_get_standard_channel_map_sound4(channels, channelMap);
38133  } break;
38134 
38136  {
38137  ma_get_standard_channel_map_sndio(channels, channelMap);
38138  } break;
38139 
38141  default:
38142  {
38143  ma_get_standard_channel_map_microsoft(channels, channelMap);
38144  } break;
38145  }
38146 }
38147 
38148 void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels)
38149 {
38150  if (pOut != NULL && pIn != NULL && channels > 0) {
38151  MA_COPY_MEMORY(pOut, pIn, sizeof(*pOut) * channels);
38152  }
38153 }
38154 
38156 {
38157  if (channelMap == NULL) {
38158  return MA_FALSE;
38159  }
38160 
38161  /* A channel count of 0 is invalid. */
38162  if (channels == 0) {
38163  return MA_FALSE;
38164  }
38165 
38166  /* It does not make sense to have a mono channel when there is more than 1 channel. */
38167  if (channels > 1) {
38168  ma_uint32 iChannel;
38169  for (iChannel = 0; iChannel < channels; ++iChannel) {
38170  if (channelMap[iChannel] == MA_CHANNEL_MONO) {
38171  return MA_FALSE;
38172  }
38173  }
38174  }
38175 
38176  return MA_TRUE;
38177 }
38178 
38179 ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel channelMapA[MA_MAX_CHANNELS], const ma_channel channelMapB[MA_MAX_CHANNELS])
38180 {
38181  ma_uint32 iChannel;
38182 
38183  if (channelMapA == channelMapB) {
38184  return MA_FALSE;
38185  }
38186 
38187  if (channels == 0 || channels > MA_MAX_CHANNELS) {
38188  return MA_FALSE;
38189  }
38190 
38191  for (iChannel = 0; iChannel < channels; ++iChannel) {
38192  if (channelMapA[iChannel] != channelMapB[iChannel]) {
38193  return MA_FALSE;
38194  }
38195  }
38196 
38197  return MA_TRUE;
38198 }
38199 
38201 {
38202  ma_uint32 iChannel;
38203 
38204  for (iChannel = 0; iChannel < channels; ++iChannel) {
38205  if (channelMap[iChannel] != MA_CHANNEL_NONE) {
38206  return MA_FALSE;
38207  }
38208  }
38209 
38210  return MA_TRUE;
38211 }
38212 
38214 {
38215  ma_uint32 iChannel;
38216  for (iChannel = 0; iChannel < channels; ++iChannel) {
38217  if (channelMap[iChannel] == channelPosition) {
38218  return MA_TRUE;
38219  }
38220  }
38221 
38222  return MA_FALSE;
38223 }
38224 
38225 
38226 
38227 /**************************************************************************************************************************************************************
38228 
38229 Conversion Helpers
38230 
38231 **************************************************************************************************************************************************************/
38232 ma_uint64 ma_convert_frames(void* pOut, ma_uint64 frameCountOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, const void* pIn, ma_uint64 frameCountIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn)
38233 {
38235 
38236  config = ma_data_converter_config_init(formatIn, formatOut, channelsIn, channelsOut, sampleRateIn, sampleRateOut);
38239  config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
38240 
38241  return ma_convert_frames_ex(pOut, frameCountOut, pIn, frameCountIn, &config);
38242 }
38243 
38244 ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const void* pIn, ma_uint64 frameCountIn, const ma_data_converter_config* pConfig)
38245 {
38246  ma_result result;
38247  ma_data_converter converter;
38248 
38249  if (frameCountIn == 0 || pConfig == NULL) {
38250  return 0;
38251  }
38252 
38253  result = ma_data_converter_init(pConfig, &converter);
38254  if (result != MA_SUCCESS) {
38255  return 0; /* Failed to initialize the data converter. */
38256  }
38257 
38258  if (pOut == NULL) {
38259  frameCountOut = ma_data_converter_get_expected_output_frame_count(&converter, frameCountIn);
38260  } else {
38261  result = ma_data_converter_process_pcm_frames(&converter, pIn, &frameCountIn, pOut, &frameCountOut);
38262  if (result != MA_SUCCESS) {
38263  frameCountOut = 0;
38264  }
38265  }
38266 
38267  ma_data_converter_uninit(&converter);
38268  return frameCountOut;
38269 }
38270 
38271 
38272 /**************************************************************************************************************************************************************
38273 
38274 Ring Buffer
38275 
38276 **************************************************************************************************************************************************************/
38278 {
38279  return encodedOffset & 0x7FFFFFFF;
38280 }
38281 
38283 {
38284  return encodedOffset & 0x80000000;
38285 }
38286 
38288 {
38289  MA_ASSERT(pRB != NULL);
38291 }
38292 
38294 {
38295  MA_ASSERT(pRB != NULL);
38297 }
38298 
38299 MA_INLINE ma_uint32 ma_rb__construct_offset(ma_uint32 offsetInBytes, ma_uint32 offsetLoopFlag)
38300 {
38301  return offsetLoopFlag | offsetInBytes;
38302 }
38303 
38304 MA_INLINE void ma_rb__deconstruct_offset(ma_uint32 encodedOffset, ma_uint32* pOffsetInBytes, ma_uint32* pOffsetLoopFlag)
38305 {
38306  MA_ASSERT(pOffsetInBytes != NULL);
38307  MA_ASSERT(pOffsetLoopFlag != NULL);
38308 
38309  *pOffsetInBytes = ma_rb__extract_offset_in_bytes(encodedOffset);
38310  *pOffsetLoopFlag = ma_rb__extract_offset_loop_flag(encodedOffset);
38311 }
38312 
38313 
38314 ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCount, size_t subbufferStrideInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB)
38315 {
38316  ma_result result;
38317  const ma_uint32 maxSubBufferSize = 0x7FFFFFFF - (MA_SIMD_ALIGNMENT-1);
38318 
38319  if (pRB == NULL) {
38320  return MA_INVALID_ARGS;
38321  }
38322 
38323  if (subbufferSizeInBytes == 0 || subbufferCount == 0) {
38324  return MA_INVALID_ARGS;
38325  }
38326 
38327  if (subbufferSizeInBytes > maxSubBufferSize) {
38328  return MA_INVALID_ARGS; /* Maximum buffer size is ~2GB. The most significant bit is a flag for use internally. */
38329  }
38330 
38331 
38332  MA_ZERO_OBJECT(pRB);
38333 
38334  result = ma_allocation_callbacks_init_copy(&pRB->allocationCallbacks, pAllocationCallbacks);
38335  if (result != MA_SUCCESS) {
38336  return result;
38337  }
38338 
38339  pRB->subbufferSizeInBytes = (ma_uint32)subbufferSizeInBytes;
38340  pRB->subbufferCount = (ma_uint32)subbufferCount;
38341 
38342  if (pOptionalPreallocatedBuffer != NULL) {
38343  pRB->subbufferStrideInBytes = (ma_uint32)subbufferStrideInBytes;
38344  pRB->pBuffer = pOptionalPreallocatedBuffer;
38345  } else {
38346  size_t bufferSizeInBytes;
38347 
38348  /*
38349  Here is where we allocate our own buffer. We always want to align this to MA_SIMD_ALIGNMENT for future SIMD optimization opportunity. To do this
38350  we need to make sure the stride is a multiple of MA_SIMD_ALIGNMENT.
38351  */
38353 
38354  bufferSizeInBytes = (size_t)pRB->subbufferCount*pRB->subbufferStrideInBytes;
38355  pRB->pBuffer = ma_aligned_malloc(bufferSizeInBytes, MA_SIMD_ALIGNMENT, &pRB->allocationCallbacks);
38356  if (pRB->pBuffer == NULL) {
38357  return MA_OUT_OF_MEMORY;
38358  }
38359 
38360  MA_ZERO_MEMORY(pRB->pBuffer, bufferSizeInBytes);
38361  pRB->ownsBuffer = MA_TRUE;
38362  }
38363 
38364  return MA_SUCCESS;
38365 }
38366 
38367 ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB)
38368 {
38369  return ma_rb_init_ex(bufferSizeInBytes, 1, 0, pOptionalPreallocatedBuffer, pAllocationCallbacks, pRB);
38370 }
38371 
38372 void ma_rb_uninit(ma_rb* pRB)
38373 {
38374  if (pRB == NULL) {
38375  return;
38376  }
38377 
38378  if (pRB->ownsBuffer) {
38380  }
38381 }
38382 
38383 void ma_rb_reset(ma_rb* pRB)
38384 {
38385  if (pRB == NULL) {
38386  return;
38387  }
38388 
38389  pRB->encodedReadOffset = 0;
38390  pRB->encodedWriteOffset = 0;
38391 }
38392 
38393 ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut)
38394 {
38395  ma_uint32 writeOffset;
38396  ma_uint32 writeOffsetInBytes;
38397  ma_uint32 writeOffsetLoopFlag;
38398  ma_uint32 readOffset;
38399  ma_uint32 readOffsetInBytes;
38400  ma_uint32 readOffsetLoopFlag;
38401  size_t bytesAvailable;
38402  size_t bytesRequested;
38403 
38404  if (pRB == NULL || pSizeInBytes == NULL || ppBufferOut == NULL) {
38405  return MA_INVALID_ARGS;
38406  }
38407 
38408  /* The returned buffer should never move ahead of the write pointer. */
38409  writeOffset = pRB->encodedWriteOffset;
38410  ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
38411 
38412  readOffset = pRB->encodedReadOffset;
38413  ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
38414 
38415  /*
38416  The number of bytes available depends on whether or not the read and write pointers are on the same loop iteration. If so, we
38417  can only read up to the write pointer. If not, we can only read up to the end of the buffer.
38418  */
38419  if (readOffsetLoopFlag == writeOffsetLoopFlag) {
38420  bytesAvailable = writeOffsetInBytes - readOffsetInBytes;
38421  } else {
38422  bytesAvailable = pRB->subbufferSizeInBytes - readOffsetInBytes;
38423  }
38424 
38425  bytesRequested = *pSizeInBytes;
38426  if (bytesRequested > bytesAvailable) {
38427  bytesRequested = bytesAvailable;
38428  }
38429 
38430  *pSizeInBytes = bytesRequested;
38431  (*ppBufferOut) = ma_rb__get_read_ptr(pRB);
38432 
38433  return MA_SUCCESS;
38434 }
38435 
38436 ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut)
38437 {
38438  ma_uint32 readOffset;
38439  ma_uint32 readOffsetInBytes;
38440  ma_uint32 readOffsetLoopFlag;
38441  ma_uint32 newReadOffsetInBytes;
38442  ma_uint32 newReadOffsetLoopFlag;
38443 
38444  if (pRB == NULL) {
38445  return MA_INVALID_ARGS;
38446  }
38447 
38448  /* Validate the buffer. */
38449  if (pBufferOut != ma_rb__get_read_ptr(pRB)) {
38450  return MA_INVALID_ARGS;
38451  }
38452 
38453  readOffset = pRB->encodedReadOffset;
38454  ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
38455 
38456  /* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */
38457  newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + sizeInBytes);
38458  if (newReadOffsetInBytes > pRB->subbufferSizeInBytes) {
38459  return MA_INVALID_ARGS; /* <-- sizeInBytes will cause the read offset to overflow. */
38460  }
38461 
38462  /* Move the read pointer back to the start if necessary. */
38463  newReadOffsetLoopFlag = readOffsetLoopFlag;
38464  if (newReadOffsetInBytes == pRB->subbufferSizeInBytes) {
38465  newReadOffsetInBytes = 0;
38466  newReadOffsetLoopFlag ^= 0x80000000;
38467  }
38468 
38469  ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetLoopFlag, newReadOffsetInBytes));
38470  return MA_SUCCESS;
38471 }
38472 
38473 ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut)
38474 {
38475  ma_uint32 readOffset;
38476  ma_uint32 readOffsetInBytes;
38477  ma_uint32 readOffsetLoopFlag;
38478  ma_uint32 writeOffset;
38479  ma_uint32 writeOffsetInBytes;
38480  ma_uint32 writeOffsetLoopFlag;
38481  size_t bytesAvailable;
38482  size_t bytesRequested;
38483 
38484  if (pRB == NULL || pSizeInBytes == NULL || ppBufferOut == NULL) {
38485  return MA_INVALID_ARGS;
38486  }
38487 
38488  /* The returned buffer should never overtake the read buffer. */
38489  readOffset = pRB->encodedReadOffset;
38490  ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
38491 
38492  writeOffset = pRB->encodedWriteOffset;
38493  ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
38494 
38495  /*
38496  In the case of writing, if the write pointer and the read pointer are on the same loop iteration we can only
38497  write up to the end of the buffer. Otherwise we can only write up to the read pointer. The write pointer should
38498  never overtake the read pointer.
38499  */
38500  if (writeOffsetLoopFlag == readOffsetLoopFlag) {
38501  bytesAvailable = pRB->subbufferSizeInBytes - writeOffsetInBytes;
38502  } else {
38503  bytesAvailable = readOffsetInBytes - writeOffsetInBytes;
38504  }
38505 
38506  bytesRequested = *pSizeInBytes;
38507  if (bytesRequested > bytesAvailable) {
38508  bytesRequested = bytesAvailable;
38509  }
38510 
38511  *pSizeInBytes = bytesRequested;
38512  *ppBufferOut = ma_rb__get_write_ptr(pRB);
38513 
38514  /* Clear the buffer if desired. */
38515  if (pRB->clearOnWriteAcquire) {
38516  MA_ZERO_MEMORY(*ppBufferOut, *pSizeInBytes);
38517  }
38518 
38519  return MA_SUCCESS;
38520 }
38521 
38522 ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut)
38523 {
38524  ma_uint32 writeOffset;
38525  ma_uint32 writeOffsetInBytes;
38526  ma_uint32 writeOffsetLoopFlag;
38527  ma_uint32 newWriteOffsetInBytes;
38528  ma_uint32 newWriteOffsetLoopFlag;
38529 
38530  if (pRB == NULL) {
38531  return MA_INVALID_ARGS;
38532  }
38533 
38534  /* Validate the buffer. */
38535  if (pBufferOut != ma_rb__get_write_ptr(pRB)) {
38536  return MA_INVALID_ARGS;
38537  }
38538 
38539  writeOffset = pRB->encodedWriteOffset;
38540  ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
38541 
38542  /* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */
38543  newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + sizeInBytes);
38544  if (newWriteOffsetInBytes > pRB->subbufferSizeInBytes) {
38545  return MA_INVALID_ARGS; /* <-- sizeInBytes will cause the read offset to overflow. */
38546  }
38547 
38548  /* Move the read pointer back to the start if necessary. */
38549  newWriteOffsetLoopFlag = writeOffsetLoopFlag;
38550  if (newWriteOffsetInBytes == pRB->subbufferSizeInBytes) {
38551  newWriteOffsetInBytes = 0;
38552  newWriteOffsetLoopFlag ^= 0x80000000;
38553  }
38554 
38555  ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetLoopFlag, newWriteOffsetInBytes));
38556  return MA_SUCCESS;
38557 }
38558 
38559 ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes)
38560 {
38561  ma_uint32 readOffset;
38562  ma_uint32 readOffsetInBytes;
38563  ma_uint32 readOffsetLoopFlag;
38564  ma_uint32 writeOffset;
38565  ma_uint32 writeOffsetInBytes;
38566  ma_uint32 writeOffsetLoopFlag;
38567  ma_uint32 newReadOffsetInBytes;
38568  ma_uint32 newReadOffsetLoopFlag;
38569 
38570  if (pRB == NULL || offsetInBytes > pRB->subbufferSizeInBytes) {
38571  return MA_INVALID_ARGS;
38572  }
38573 
38574  readOffset = pRB->encodedReadOffset;
38575  ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
38576 
38577  writeOffset = pRB->encodedWriteOffset;
38578  ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
38579 
38580  newReadOffsetInBytes = readOffsetInBytes;
38581  newReadOffsetLoopFlag = readOffsetLoopFlag;
38582 
38583  /* We cannot go past the write buffer. */
38584  if (readOffsetLoopFlag == writeOffsetLoopFlag) {
38585  if ((readOffsetInBytes + offsetInBytes) > writeOffsetInBytes) {
38586  newReadOffsetInBytes = writeOffsetInBytes;
38587  } else {
38588  newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes);
38589  }
38590  } else {
38591  /* May end up looping. */
38592  if ((readOffsetInBytes + offsetInBytes) >= pRB->subbufferSizeInBytes) {
38593  newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes) - pRB->subbufferSizeInBytes;
38594  newReadOffsetLoopFlag ^= 0x80000000; /* <-- Looped. */
38595  } else {
38596  newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes);
38597  }
38598  }
38599 
38600  ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetInBytes, newReadOffsetLoopFlag));
38601  return MA_SUCCESS;
38602 }
38603 
38604 ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes)
38605 {
38606  ma_uint32 readOffset;
38607  ma_uint32 readOffsetInBytes;
38608  ma_uint32 readOffsetLoopFlag;
38609  ma_uint32 writeOffset;
38610  ma_uint32 writeOffsetInBytes;
38611  ma_uint32 writeOffsetLoopFlag;
38612  ma_uint32 newWriteOffsetInBytes;
38613  ma_uint32 newWriteOffsetLoopFlag;
38614 
38615  if (pRB == NULL) {
38616  return MA_INVALID_ARGS;
38617  }
38618 
38619  readOffset = pRB->encodedReadOffset;
38620  ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
38621 
38622  writeOffset = pRB->encodedWriteOffset;
38623  ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
38624 
38625  newWriteOffsetInBytes = writeOffsetInBytes;
38626  newWriteOffsetLoopFlag = writeOffsetLoopFlag;
38627 
38628  /* We cannot go past the write buffer. */
38629  if (readOffsetLoopFlag == writeOffsetLoopFlag) {
38630  /* May end up looping. */
38631  if ((writeOffsetInBytes + offsetInBytes) >= pRB->subbufferSizeInBytes) {
38632  newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes) - pRB->subbufferSizeInBytes;
38633  newWriteOffsetLoopFlag ^= 0x80000000; /* <-- Looped. */
38634  } else {
38635  newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes);
38636  }
38637  } else {
38638  if ((writeOffsetInBytes + offsetInBytes) > readOffsetInBytes) {
38639  newWriteOffsetInBytes = readOffsetInBytes;
38640  } else {
38641  newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes);
38642  }
38643  }
38644 
38645  ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetInBytes, newWriteOffsetLoopFlag));
38646  return MA_SUCCESS;
38647 }
38648 
38650 {
38651  ma_uint32 readOffset;
38652  ma_uint32 readOffsetInBytes;
38653  ma_uint32 readOffsetLoopFlag;
38654  ma_uint32 writeOffset;
38655  ma_uint32 writeOffsetInBytes;
38656  ma_uint32 writeOffsetLoopFlag;
38657 
38658  if (pRB == NULL) {
38659  return 0;
38660  }
38661 
38662  readOffset = pRB->encodedReadOffset;
38663  ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
38664 
38665  writeOffset = pRB->encodedWriteOffset;
38666  ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
38667 
38668  if (readOffsetLoopFlag == writeOffsetLoopFlag) {
38669  return writeOffsetInBytes - readOffsetInBytes;
38670  } else {
38671  return writeOffsetInBytes + (pRB->subbufferSizeInBytes - readOffsetInBytes);
38672  }
38673 }
38674 
38676 {
38677  ma_int32 dist;
38678 
38679  if (pRB == NULL) {
38680  return 0;
38681  }
38682 
38683  dist = ma_rb_pointer_distance(pRB);
38684  if (dist < 0) {
38685  return 0;
38686  }
38687 
38688  return dist;
38689 }
38690 
38692 {
38693  if (pRB == NULL) {
38694  return 0;
38695  }
38696 
38698 }
38699 
38700 size_t ma_rb_get_subbuffer_size(ma_rb* pRB)
38701 {
38702  if (pRB == NULL) {
38703  return 0;
38704  }
38705 
38706  return pRB->subbufferSizeInBytes;
38707 }
38708 
38709 size_t ma_rb_get_subbuffer_stride(ma_rb* pRB)
38710 {
38711  if (pRB == NULL) {
38712  return 0;
38713  }
38714 
38715  if (pRB->subbufferStrideInBytes == 0) {
38716  return (size_t)pRB->subbufferSizeInBytes;
38717  }
38718 
38719  return (size_t)pRB->subbufferStrideInBytes;
38720 }
38721 
38722 size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex)
38723 {
38724  if (pRB == NULL) {
38725  return 0;
38726  }
38727 
38728  return subbufferIndex * ma_rb_get_subbuffer_stride(pRB);
38729 }
38730 
38731 void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer)
38732 {
38733  if (pRB == NULL) {
38734  return NULL;
38735  }
38736 
38737  return ma_offset_ptr(pBuffer, ma_rb_get_subbuffer_offset(pRB, subbufferIndex));
38738 }
38739 
38740 
38742 {
38743  MA_ASSERT(pRB != NULL);
38744 
38745  return ma_get_bytes_per_frame(pRB->format, pRB->channels);
38746 }
38747 
38748 ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint32 subbufferSizeInFrames, ma_uint32 subbufferCount, ma_uint32 subbufferStrideInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_pcm_rb* pRB)
38749 {
38750  ma_uint32 bpf;
38751  ma_result result;
38752 
38753  if (pRB == NULL) {
38754  return MA_INVALID_ARGS;
38755  }
38756 
38757  MA_ZERO_OBJECT(pRB);
38758 
38759  bpf = ma_get_bytes_per_frame(format, channels);
38760  if (bpf == 0) {
38761  return MA_INVALID_ARGS;
38762  }
38763 
38764  result = ma_rb_init_ex(subbufferSizeInFrames*bpf, subbufferCount, subbufferStrideInFrames*bpf, pOptionalPreallocatedBuffer, pAllocationCallbacks, &pRB->rb);
38765  if (result != MA_SUCCESS) {
38766  return result;
38767  }
38768 
38769  pRB->format = format;
38770  pRB->channels = channels;
38771 
38772  return MA_SUCCESS;
38773 }
38774 
38775 ma_result ma_pcm_rb_init(ma_format format, ma_uint32 channels, ma_uint32 bufferSizeInFrames, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_pcm_rb* pRB)
38776 {
38777  return ma_pcm_rb_init_ex(format, channels, bufferSizeInFrames, 1, 0, pOptionalPreallocatedBuffer, pAllocationCallbacks, pRB);
38778 }
38779 
38780 void ma_pcm_rb_uninit(ma_pcm_rb* pRB)
38781 {
38782  if (pRB == NULL) {
38783  return;
38784  }
38785 
38786  ma_rb_uninit(&pRB->rb);
38787 }
38788 
38789 void ma_pcm_rb_reset(ma_pcm_rb* pRB)
38790 {
38791  if (pRB == NULL) {
38792  return;
38793  }
38794 
38795  ma_rb_reset(&pRB->rb);
38796 }
38797 
38798 ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut)
38799 {
38800  size_t sizeInBytes;
38801  ma_result result;
38802 
38803  if (pRB == NULL || pSizeInFrames == NULL) {
38804  return MA_INVALID_ARGS;
38805  }
38806 
38807  sizeInBytes = *pSizeInFrames * ma_pcm_rb_get_bpf(pRB);
38808 
38809  result = ma_rb_acquire_read(&pRB->rb, &sizeInBytes, ppBufferOut);
38810  if (result != MA_SUCCESS) {
38811  return result;
38812  }
38813 
38814  *pSizeInFrames = (ma_uint32)(sizeInBytes / (size_t)ma_pcm_rb_get_bpf(pRB));
38815  return MA_SUCCESS;
38816 }
38817 
38818 ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut)
38819 {
38820  if (pRB == NULL) {
38821  return MA_INVALID_ARGS;
38822  }
38823 
38824  return ma_rb_commit_read(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB), pBufferOut);
38825 }
38826 
38827 ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut)
38828 {
38829  size_t sizeInBytes;
38830  ma_result result;
38831 
38832  if (pRB == NULL) {
38833  return MA_INVALID_ARGS;
38834  }
38835 
38836  sizeInBytes = *pSizeInFrames * ma_pcm_rb_get_bpf(pRB);
38837 
38838  result = ma_rb_acquire_write(&pRB->rb, &sizeInBytes, ppBufferOut);
38839  if (result != MA_SUCCESS) {
38840  return result;
38841  }
38842 
38843  *pSizeInFrames = (ma_uint32)(sizeInBytes / ma_pcm_rb_get_bpf(pRB));
38844  return MA_SUCCESS;
38845 }
38846 
38847 ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut)
38848 {
38849  if (pRB == NULL) {
38850  return MA_INVALID_ARGS;
38851  }
38852 
38853  return ma_rb_commit_write(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB), pBufferOut);
38854 }
38855 
38856 ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames)
38857 {
38858  if (pRB == NULL) {
38859  return MA_INVALID_ARGS;
38860  }
38861 
38862  return ma_rb_seek_read(&pRB->rb, offsetInFrames * ma_pcm_rb_get_bpf(pRB));
38863 }
38864 
38865 ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames)
38866 {
38867  if (pRB == NULL) {
38868  return MA_INVALID_ARGS;
38869  }
38870 
38871  return ma_rb_seek_write(&pRB->rb, offsetInFrames * ma_pcm_rb_get_bpf(pRB));
38872 }
38873 
38875 {
38876  if (pRB == NULL) {
38877  return 0;
38878  }
38879 
38880  return ma_rb_pointer_distance(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
38881 }
38882 
38884 {
38885  if (pRB == NULL) {
38886  return 0;
38887  }
38888 
38889  return ma_rb_available_read(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
38890 }
38891 
38893 {
38894  if (pRB == NULL) {
38895  return 0;
38896  }
38897 
38898  return ma_rb_available_write(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
38899 }
38900 
38902 {
38903  if (pRB == NULL) {
38904  return 0;
38905  }
38906 
38907  return (ma_uint32)(ma_rb_get_subbuffer_size(&pRB->rb) / ma_pcm_rb_get_bpf(pRB));
38908 }
38909 
38911 {
38912  if (pRB == NULL) {
38913  return 0;
38914  }
38915 
38916  return (ma_uint32)(ma_rb_get_subbuffer_stride(&pRB->rb) / ma_pcm_rb_get_bpf(pRB));
38917 }
38918 
38920 {
38921  if (pRB == NULL) {
38922  return 0;
38923  }
38924 
38925  return (ma_uint32)(ma_rb_get_subbuffer_offset(&pRB->rb, subbufferIndex) / ma_pcm_rb_get_bpf(pRB));
38926 }
38927 
38928 void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer)
38929 {
38930  if (pRB == NULL) {
38931  return NULL;
38932  }
38933 
38934  return ma_rb_get_subbuffer_ptr(&pRB->rb, subbufferIndex, pBuffer);
38935 }
38936 
38937 
38938 
38939 /**************************************************************************************************************************************************************
38940 
38941 Miscellaneous Helpers
38942 
38943 **************************************************************************************************************************************************************/
38944 const char* ma_result_description(ma_result result)
38945 {
38946  switch (result)
38947  {
38948  case MA_SUCCESS: return "No error";
38949  case MA_ERROR: return "Unknown error";
38950  case MA_INVALID_ARGS: return "Invalid argument";
38951  case MA_INVALID_OPERATION: return "Invalid operation";
38952  case MA_OUT_OF_MEMORY: return "Out of memory";
38953  case MA_OUT_OF_RANGE: return "Out of range";
38954  case MA_ACCESS_DENIED: return "Permission denied";
38955  case MA_DOES_NOT_EXIST: return "Resource does not exist";
38956  case MA_ALREADY_EXISTS: return "Resource already exists";
38957  case MA_TOO_MANY_OPEN_FILES: return "Too many open files";
38958  case MA_INVALID_FILE: return "Invalid file";
38959  case MA_TOO_BIG: return "Too large";
38960  case MA_PATH_TOO_LONG: return "Path too long";
38961  case MA_NAME_TOO_LONG: return "Name too long";
38962  case MA_NOT_DIRECTORY: return "Not a directory";
38963  case MA_IS_DIRECTORY: return "Is a directory";
38964  case MA_DIRECTORY_NOT_EMPTY: return "Directory not empty";
38965  case MA_END_OF_FILE: return "End of file";
38966  case MA_NO_SPACE: return "No space available";
38967  case MA_BUSY: return "Device or resource busy";
38968  case MA_IO_ERROR: return "Input/output error";
38969  case MA_INTERRUPT: return "Interrupted";
38970  case MA_UNAVAILABLE: return "Resource unavailable";
38971  case MA_ALREADY_IN_USE: return "Resource already in use";
38972  case MA_BAD_ADDRESS: return "Bad address";
38973  case MA_BAD_SEEK: return "Illegal seek";
38974  case MA_BAD_PIPE: return "Broken pipe";
38975  case MA_DEADLOCK: return "Deadlock";
38976  case MA_TOO_MANY_LINKS: return "Too many links";
38977  case MA_NOT_IMPLEMENTED: return "Not implemented";
38978  case MA_NO_MESSAGE: return "No message of desired type";
38979  case MA_BAD_MESSAGE: return "Invalid message";
38980  case MA_NO_DATA_AVAILABLE: return "No data available";
38981  case MA_INVALID_DATA: return "Invalid data";
38982  case MA_TIMEOUT: return "Timeout";
38983  case MA_NO_NETWORK: return "Network unavailable";
38984  case MA_NOT_UNIQUE: return "Not unique";
38985  case MA_NOT_SOCKET: return "Socket operation on non-socket";
38986  case MA_NO_ADDRESS: return "Destination address required";
38987  case MA_BAD_PROTOCOL: return "Protocol wrong type for socket";
38988  case MA_PROTOCOL_UNAVAILABLE: return "Protocol not available";
38989  case MA_PROTOCOL_NOT_SUPPORTED: return "Protocol not supported";
38990  case MA_PROTOCOL_FAMILY_NOT_SUPPORTED: return "Protocol family not supported";
38991  case MA_ADDRESS_FAMILY_NOT_SUPPORTED: return "Address family not supported";
38992  case MA_SOCKET_NOT_SUPPORTED: return "Socket type not supported";
38993  case MA_CONNECTION_RESET: return "Connection reset";
38994  case MA_ALREADY_CONNECTED: return "Already connected";
38995  case MA_NOT_CONNECTED: return "Not connected";
38996  case MA_CONNECTION_REFUSED: return "Connection refused";
38997  case MA_NO_HOST: return "No host";
38998  case MA_IN_PROGRESS: return "Operation in progress";
38999  case MA_CANCELLED: return "Operation cancelled";
39000  case MA_MEMORY_ALREADY_MAPPED: return "Memory already mapped";
39001  case MA_AT_END: return "Reached end of collection";
39002 
39003  case MA_FORMAT_NOT_SUPPORTED: return "Format not supported";
39004  case MA_DEVICE_TYPE_NOT_SUPPORTED: return "Device type not supported";
39005  case MA_SHARE_MODE_NOT_SUPPORTED: return "Share mode not supported";
39006  case MA_NO_BACKEND: return "No backend";
39007  case MA_NO_DEVICE: return "No device";
39008  case MA_API_NOT_FOUND: return "API not found";
39009  case MA_INVALID_DEVICE_CONFIG: return "Invalid device config";
39010 
39011  case MA_DEVICE_NOT_INITIALIZED: return "Device not initialized";
39012  case MA_DEVICE_NOT_STARTED: return "Device not started";
39013 
39014  case MA_FAILED_TO_INIT_BACKEND: return "Failed to initialize backend";
39015  case MA_FAILED_TO_OPEN_BACKEND_DEVICE: return "Failed to open backend device";
39016  case MA_FAILED_TO_START_BACKEND_DEVICE: return "Failed to start backend device";
39017  case MA_FAILED_TO_STOP_BACKEND_DEVICE: return "Failed to stop backend device";
39018 
39019  default: return "Unknown error";
39020  }
39021 }
39022 
39023 void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
39024 {
39025  if (pAllocationCallbacks != NULL) {
39026  return ma__malloc_from_callbacks(sz, pAllocationCallbacks);
39027  } else {
39028  return ma__malloc_default(sz, NULL);
39029  }
39030 }
39031 
39032 void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
39033 {
39034  if (pAllocationCallbacks != NULL) {
39035  if (pAllocationCallbacks->onRealloc != NULL) {
39036  return pAllocationCallbacks->onRealloc(p, sz, pAllocationCallbacks->pUserData);
39037  } else {
39038  return NULL; /* This requires a native implementation of realloc(). */
39039  }
39040  } else {
39041  return ma__realloc_default(p, sz, NULL);
39042  }
39043 }
39044 
39045 void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks)
39046 {
39047  if (pAllocationCallbacks != NULL) {
39048  ma__free_from_callbacks(p, pAllocationCallbacks);
39049  } else {
39050  ma__free_default(p, NULL);
39051  }
39052 }
39053 
39054 void* ma_aligned_malloc(size_t sz, size_t alignment, const ma_allocation_callbacks* pAllocationCallbacks)
39055 {
39056  size_t extraBytes;
39057  void* pUnaligned;
39058  void* pAligned;
39059 
39060  if (alignment == 0) {
39061  return 0;
39062  }
39063 
39064  extraBytes = alignment-1 + sizeof(void*);
39065 
39066  pUnaligned = ma_malloc(sz + extraBytes, pAllocationCallbacks);
39067  if (pUnaligned == NULL) {
39068  return NULL;
39069  }
39070 
39071  pAligned = (void*)(((ma_uintptr)pUnaligned + extraBytes) & ~((ma_uintptr)(alignment-1)));
39072  ((void**)pAligned)[-1] = pUnaligned;
39073 
39074  return pAligned;
39075 }
39076 
39077 void ma_aligned_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks)
39078 {
39079  ma_free(((void**)p)[-1], pAllocationCallbacks);
39080 }
39081 
39082 const char* ma_get_format_name(ma_format format)
39083 {
39084  switch (format)
39085  {
39086  case ma_format_unknown: return "Unknown";
39087  case ma_format_u8: return "8-bit Unsigned Integer";
39088  case ma_format_s16: return "16-bit Signed Integer";
39089  case ma_format_s24: return "24-bit Signed Integer (Tightly Packed)";
39090  case ma_format_s32: return "32-bit Signed Integer";
39091  case ma_format_f32: return "32-bit IEEE Floating Point";
39092  default: return "Invalid";
39093  }
39094 }
39095 
39096 void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels)
39097 {
39098  ma_uint32 i;
39099  for (i = 0; i < channels; ++i) {
39100  pOut[i] = ma_mix_f32(pInA[i], pInB[i], factor);
39101  }
39102 }
39103 
39104 
39106 {
39107  ma_uint32 sizes[] = {
39108  0, /* unknown */
39109  1, /* u8 */
39110  2, /* s16 */
39111  3, /* s24 */
39112  4, /* s32 */
39113  4, /* f32 */
39114  };
39115  return sizes[format];
39116 }
39117 
39118 
39119 /**************************************************************************************************************************************************************
39120 
39121 Decoding
39122 
39123 **************************************************************************************************************************************************************/
39124 #ifndef MA_NO_DECODING
39125 
39126 static size_t ma_decoder_read_bytes(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead)
39127 {
39128  size_t bytesRead;
39129 
39130  MA_ASSERT(pDecoder != NULL);
39131  MA_ASSERT(pBufferOut != NULL);
39132 
39133  bytesRead = pDecoder->onRead(pDecoder, pBufferOut, bytesToRead);
39134  pDecoder->readPointer += bytesRead;
39135 
39136  return bytesRead;
39137 }
39138 
39139 static ma_bool32 ma_decoder_seek_bytes(ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin)
39140 {
39141  ma_bool32 wasSuccessful;
39142 
39143  MA_ASSERT(pDecoder != NULL);
39144 
39145  wasSuccessful = pDecoder->onSeek(pDecoder, byteOffset, origin);
39146  if (wasSuccessful) {
39147  if (origin == ma_seek_origin_start) {
39148  pDecoder->readPointer = (ma_uint64)byteOffset;
39149  } else {
39150  pDecoder->readPointer += byteOffset;
39151  }
39152  }
39153 
39154  return wasSuccessful;
39155 }
39156 
39157 
39158 ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate)
39159 {
39162  config.format = outputFormat;
39163  config.channels = outputChannels;
39164  config.sampleRate = outputSampleRate;
39165  config.resampling.algorithm = ma_resample_algorithm_linear;
39166  config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
39167  config.resampling.speex.quality = 3;
39168 
39169  /* Note that we are intentionally leaving the channel map empty here which will cause the default channel map to be used. */
39170 
39171  return config;
39172 }
39173 
39175 {
39177  if (pConfig != NULL) {
39178  config = *pConfig;
39179  } else {
39181  }
39182 
39183  return config;
39184 }
39185 
39187 {
39188  ma_data_converter_config converterConfig;
39189 
39190  MA_ASSERT(pDecoder != NULL);
39191 
39192  /* Output format. */
39193  if (pConfig->format == ma_format_unknown) {
39194  pDecoder->outputFormat = pDecoder->internalFormat;
39195  } else {
39196  pDecoder->outputFormat = pConfig->format;
39197  }
39198 
39199  if (pConfig->channels == 0) {
39200  pDecoder->outputChannels = pDecoder->internalChannels;
39201  } else {
39202  pDecoder->outputChannels = pConfig->channels;
39203  }
39204 
39205  if (pConfig->sampleRate == 0) {
39206  pDecoder->outputSampleRate = pDecoder->internalSampleRate;
39207  } else {
39208  pDecoder->outputSampleRate = pConfig->sampleRate;
39209  }
39210 
39211  if (ma_channel_map_blank(pDecoder->outputChannels, pConfig->channelMap)) {
39213  } else {
39214  MA_COPY_MEMORY(pDecoder->outputChannelMap, pConfig->channelMap, sizeof(pConfig->channelMap));
39215  }
39216 
39217 
39218  converterConfig = ma_data_converter_config_init(
39219  pDecoder->internalFormat, pDecoder->outputFormat,
39220  pDecoder->internalChannels, pDecoder->outputChannels,
39221  pDecoder->internalSampleRate, pDecoder->outputSampleRate
39222  );
39223  ma_channel_map_copy(converterConfig.channelMapIn, pDecoder->internalChannelMap, pDecoder->internalChannels);
39224  ma_channel_map_copy(converterConfig.channelMapOut, pDecoder->outputChannelMap, pDecoder->outputChannels);
39225  converterConfig.channelMixMode = pConfig->channelMixMode;
39226  converterConfig.ditherMode = pConfig->ditherMode;
39227  converterConfig.resampling.allowDynamicSampleRate = MA_FALSE; /* Never allow dynamic sample rate conversion. Setting this to true will disable passthrough optimizations. */
39228  converterConfig.resampling.algorithm = pConfig->resampling.algorithm;
39229  converterConfig.resampling.linear.lpfOrder = pConfig->resampling.linear.lpfOrder;
39230  converterConfig.resampling.speex.quality = pConfig->resampling.speex.quality;
39231 
39232  return ma_data_converter_init(&converterConfig, &pDecoder->converter);
39233 }
39234 
39235 /* WAV */
39236 #ifdef dr_wav_h
39237 #define MA_HAS_WAV
39238 
39239 static size_t ma_decoder_internal_on_read__wav(void* pUserData, void* pBufferOut, size_t bytesToRead)
39240 {
39241  ma_decoder* pDecoder = (ma_decoder*)pUserData;
39242  MA_ASSERT(pDecoder != NULL);
39243 
39244  return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead);
39245 }
39246 
39247 static drwav_bool32 ma_decoder_internal_on_seek__wav(void* pUserData, int offset, drwav_seek_origin origin)
39248 {
39249  ma_decoder* pDecoder = (ma_decoder*)pUserData;
39250  MA_ASSERT(pDecoder != NULL);
39251 
39253 }
39254 
39255 static ma_uint64 ma_decoder_internal_on_read_pcm_frames__wav(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
39256 {
39257  drwav* pWav;
39258 
39259  MA_ASSERT(pDecoder != NULL);
39260  MA_ASSERT(pFramesOut != NULL);
39261 
39262  pWav = (drwav*)pDecoder->pInternalDecoder;
39263  MA_ASSERT(pWav != NULL);
39264 
39265  switch (pDecoder->internalFormat) {
39266  case ma_format_s16: return drwav_read_pcm_frames_s16(pWav, frameCount, (drwav_int16*)pFramesOut);
39267  case ma_format_s32: return drwav_read_pcm_frames_s32(pWav, frameCount, (drwav_int32*)pFramesOut);
39268  case ma_format_f32: return drwav_read_pcm_frames_f32(pWav, frameCount, (float*)pFramesOut);
39269  default: break;
39270  }
39271 
39272  /* Should never get here. If we do, it means the internal format was not set correctly at initialization time. */
39274  return 0;
39275 }
39276 
39277 static ma_result ma_decoder_internal_on_seek_to_pcm_frame__wav(ma_decoder* pDecoder, ma_uint64 frameIndex)
39278 {
39279  drwav* pWav;
39280  drwav_bool32 result;
39281 
39282  pWav = (drwav*)pDecoder->pInternalDecoder;
39283  MA_ASSERT(pWav != NULL);
39284 
39285  result = drwav_seek_to_pcm_frame(pWav, frameIndex);
39286  if (result) {
39287  return MA_SUCCESS;
39288  } else {
39289  return MA_ERROR;
39290  }
39291 }
39292 
39293 static ma_result ma_decoder_internal_on_uninit__wav(ma_decoder* pDecoder)
39294 {
39295  drwav_uninit((drwav*)pDecoder->pInternalDecoder);
39297  return MA_SUCCESS;
39298 }
39299 
39300 static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__wav(ma_decoder* pDecoder)
39301 {
39302  return ((drwav*)pDecoder->pInternalDecoder)->totalPCMFrameCount;
39303 }
39304 
39305 static ma_result ma_decoder_init_wav__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
39306 {
39307  drwav* pWav;
39308  drwav_allocation_callbacks allocationCallbacks;
39309 
39310  MA_ASSERT(pConfig != NULL);
39311  MA_ASSERT(pDecoder != NULL);
39312 
39313  pWav = (drwav*)ma__malloc_from_callbacks(sizeof(*pWav), &pDecoder->allocationCallbacks);
39314  if (pWav == NULL) {
39315  return MA_OUT_OF_MEMORY;
39316  }
39317 
39318  allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData;
39319  allocationCallbacks.onMalloc = pDecoder->allocationCallbacks.onMalloc;
39320  allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc;
39321  allocationCallbacks.onFree = pDecoder->allocationCallbacks.onFree;
39322 
39323  /* Try opening the decoder first. */
39324  if (!drwav_init(pWav, ma_decoder_internal_on_read__wav, ma_decoder_internal_on_seek__wav, pDecoder, &allocationCallbacks)) {
39325  ma__free_from_callbacks(pWav, &pDecoder->allocationCallbacks);
39326  return MA_ERROR;
39327  }
39328 
39329  /* If we get here it means we successfully initialized the WAV decoder. We can now initialize the rest of the ma_decoder. */
39330  pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__wav;
39331  pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__wav;
39332  pDecoder->onUninit = ma_decoder_internal_on_uninit__wav;
39333  pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__wav;
39334  pDecoder->pInternalDecoder = pWav;
39335 
39336  /* Try to be as optimal as possible for the internal format. If miniaudio does not support a format we will fall back to f32. */
39337  pDecoder->internalFormat = ma_format_unknown;
39338  switch (pWav->translatedFormatTag) {
39339  case DR_WAVE_FORMAT_PCM:
39340  {
39341  if (pWav->bitsPerSample == 8) {
39342  pDecoder->internalFormat = ma_format_s16;
39343  } else if (pWav->bitsPerSample == 16) {
39344  pDecoder->internalFormat = ma_format_s16;
39345  } else if (pWav->bitsPerSample == 32) {
39346  pDecoder->internalFormat = ma_format_s32;
39347  }
39348  } break;
39349 
39351  {
39352  if (pWav->bitsPerSample == 32) {
39353  pDecoder->internalFormat = ma_format_f32;
39354  }
39355  } break;
39356 
39357  case DR_WAVE_FORMAT_ALAW:
39358  case DR_WAVE_FORMAT_MULAW:
39359  case DR_WAVE_FORMAT_ADPCM:
39361  {
39362  pDecoder->internalFormat = ma_format_s16;
39363  } break;
39364  }
39365 
39366  if (pDecoder->internalFormat == ma_format_unknown) {
39367  pDecoder->internalFormat = ma_format_f32;
39368  }
39369 
39370  pDecoder->internalChannels = pWav->channels;
39371  pDecoder->internalSampleRate = pWav->sampleRate;
39373 
39374  return MA_SUCCESS;
39375 }
39376 #endif /* dr_wav_h */
39377 
39378 /* FLAC */
39379 #ifdef dr_flac_h
39380 #define MA_HAS_FLAC
39381 
39382 static size_t ma_decoder_internal_on_read__flac(void* pUserData, void* pBufferOut, size_t bytesToRead)
39383 {
39384  ma_decoder* pDecoder = (ma_decoder*)pUserData;
39385  MA_ASSERT(pDecoder != NULL);
39386 
39387  return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead);
39388 }
39389 
39390 static drflac_bool32 ma_decoder_internal_on_seek__flac(void* pUserData, int offset, drflac_seek_origin origin)
39391 {
39392  ma_decoder* pDecoder = (ma_decoder*)pUserData;
39393  MA_ASSERT(pDecoder != NULL);
39394 
39396 }
39397 
39398 static ma_uint64 ma_decoder_internal_on_read_pcm_frames__flac(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
39399 {
39400  drflac* pFlac;
39401 
39402  MA_ASSERT(pDecoder != NULL);
39403  MA_ASSERT(pFramesOut != NULL);
39404 
39405  pFlac = (drflac*)pDecoder->pInternalDecoder;
39406  MA_ASSERT(pFlac != NULL);
39407 
39408  switch (pDecoder->internalFormat) {
39409  case ma_format_s16: return drflac_read_pcm_frames_s16(pFlac, frameCount, (drflac_int16*)pFramesOut);
39410  case ma_format_s32: return drflac_read_pcm_frames_s32(pFlac, frameCount, (drflac_int32*)pFramesOut);
39411  case ma_format_f32: return drflac_read_pcm_frames_f32(pFlac, frameCount, (float*)pFramesOut);
39412  default: break;
39413  }
39414 
39415  /* Should never get here. If we do, it means the internal format was not set correctly at initialization time. */
39417  return 0;
39418 }
39419 
39420 static ma_result ma_decoder_internal_on_seek_to_pcm_frame__flac(ma_decoder* pDecoder, ma_uint64 frameIndex)
39421 {
39422  drflac* pFlac;
39423  drflac_bool32 result;
39424 
39425  pFlac = (drflac*)pDecoder->pInternalDecoder;
39426  MA_ASSERT(pFlac != NULL);
39427 
39428  result = drflac_seek_to_pcm_frame(pFlac, frameIndex);
39429  if (result) {
39430  return MA_SUCCESS;
39431  } else {
39432  return MA_ERROR;
39433  }
39434 }
39435 
39436 static ma_result ma_decoder_internal_on_uninit__flac(ma_decoder* pDecoder)
39437 {
39438  drflac_close((drflac*)pDecoder->pInternalDecoder);
39439  return MA_SUCCESS;
39440 }
39441 
39442 static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__flac(ma_decoder* pDecoder)
39443 {
39444  return ((drflac*)pDecoder->pInternalDecoder)->totalPCMFrameCount;
39445 }
39446 
39447 static ma_result ma_decoder_init_flac__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
39448 {
39449  drflac* pFlac;
39450  drflac_allocation_callbacks allocationCallbacks;
39451 
39452  MA_ASSERT(pConfig != NULL);
39453  MA_ASSERT(pDecoder != NULL);
39454 
39455  allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData;
39456  allocationCallbacks.onMalloc = pDecoder->allocationCallbacks.onMalloc;
39457  allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc;
39458  allocationCallbacks.onFree = pDecoder->allocationCallbacks.onFree;
39459 
39460  /* Try opening the decoder first. */
39461  pFlac = drflac_open(ma_decoder_internal_on_read__flac, ma_decoder_internal_on_seek__flac, pDecoder, &allocationCallbacks);
39462  if (pFlac == NULL) {
39463  return MA_ERROR;
39464  }
39465 
39466  /* If we get here it means we successfully initialized the FLAC decoder. We can now initialize the rest of the ma_decoder. */
39467  pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__flac;
39468  pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__flac;
39469  pDecoder->onUninit = ma_decoder_internal_on_uninit__flac;
39470  pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__flac;
39471  pDecoder->pInternalDecoder = pFlac;
39472 
39473  /*
39474  dr_flac supports reading as s32, s16 and f32. Try to do a one-to-one mapping if possible, but fall back to s32 if not. s32 is the "native" FLAC format
39475  since it's the only one that's truly lossless.
39476  */
39477  pDecoder->internalFormat = ma_format_s32;
39478  if (pConfig->format == ma_format_s16) {
39479  pDecoder->internalFormat = ma_format_s16;
39480  } else if (pConfig->format == ma_format_f32) {
39481  pDecoder->internalFormat = ma_format_f32;
39482  }
39483 
39484  pDecoder->internalChannels = pFlac->channels;
39485  pDecoder->internalSampleRate = pFlac->sampleRate;
39487 
39488  return MA_SUCCESS;
39489 }
39490 #endif /* dr_flac_h */
39491 
39492 /* Vorbis */
39493 #ifdef STB_VORBIS_INCLUDE_STB_VORBIS_H
39494 #define MA_HAS_VORBIS
39495 
39496 /* The size in bytes of each chunk of data to read from the Vorbis stream. */
39497 #define MA_VORBIS_DATA_CHUNK_SIZE 4096
39498 
39499 typedef struct
39500 {
39501  stb_vorbis* pInternalVorbis;
39502  ma_uint8* pData;
39503  size_t dataSize;
39504  size_t dataCapacity;
39505  ma_uint32 framesConsumed; /* The number of frames consumed in ppPacketData. */
39506  ma_uint32 framesRemaining; /* The number of frames remaining in ppPacketData. */
39507  float** ppPacketData;
39508 } ma_vorbis_decoder;
39509 
39510 static ma_uint64 ma_vorbis_decoder_read_pcm_frames(ma_vorbis_decoder* pVorbis, ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
39511 {
39512  float* pFramesOutF;
39513  ma_uint64 totalFramesRead;
39514 
39515  MA_ASSERT(pVorbis != NULL);
39516  MA_ASSERT(pDecoder != NULL);
39517 
39518  pFramesOutF = (float*)pFramesOut;
39519 
39520  totalFramesRead = 0;
39521  while (frameCount > 0) {
39522  /* Read from the in-memory buffer first. */
39523  while (pVorbis->framesRemaining > 0 && frameCount > 0) {
39524  ma_uint32 iChannel;
39525  for (iChannel = 0; iChannel < pDecoder->internalChannels; ++iChannel) {
39526  pFramesOutF[0] = pVorbis->ppPacketData[iChannel][pVorbis->framesConsumed];
39527  pFramesOutF += 1;
39528  }
39529 
39530  pVorbis->framesConsumed += 1;
39531  pVorbis->framesRemaining -= 1;
39532  frameCount -= 1;
39533  totalFramesRead += 1;
39534  }
39535 
39536  if (frameCount == 0) {
39537  break;
39538  }
39539 
39540  MA_ASSERT(pVorbis->framesRemaining == 0);
39541 
39542  /* We've run out of cached frames, so decode the next packet and continue iteration. */
39543  do
39544  {
39545  int samplesRead;
39546  int consumedDataSize;
39547 
39548  if (pVorbis->dataSize > INT_MAX) {
39549  break; /* Too big. */
39550  }
39551 
39552  samplesRead = 0;
39553  consumedDataSize = stb_vorbis_decode_frame_pushdata(pVorbis->pInternalVorbis, pVorbis->pData, (int)pVorbis->dataSize, NULL, (float***)&pVorbis->ppPacketData, &samplesRead);
39554  if (consumedDataSize != 0) {
39555  size_t leftoverDataSize = (pVorbis->dataSize - (size_t)consumedDataSize);
39556  size_t i;
39557  for (i = 0; i < leftoverDataSize; ++i) {
39558  pVorbis->pData[i] = pVorbis->pData[i + consumedDataSize];
39559  }
39560 
39561  pVorbis->dataSize = leftoverDataSize;
39562  pVorbis->framesConsumed = 0;
39563  pVorbis->framesRemaining = samplesRead;
39564  break;
39565  } else {
39566  /* Need more data. If there's any room in the existing buffer allocation fill that first. Otherwise expand. */
39567  size_t bytesRead;
39568  if (pVorbis->dataCapacity == pVorbis->dataSize) {
39569  /* No room. Expand. */
39570  size_t oldCap = pVorbis->dataCapacity;
39571  size_t newCap = pVorbis->dataCapacity + MA_VORBIS_DATA_CHUNK_SIZE;
39572  ma_uint8* pNewData;
39573 
39574  pNewData = (ma_uint8*)ma__realloc_from_callbacks(pVorbis->pData, newCap, oldCap, &pDecoder->allocationCallbacks);
39575  if (pNewData == NULL) {
39576  return totalFramesRead; /* Out of memory. */
39577  }
39578 
39579  pVorbis->pData = pNewData;
39580  pVorbis->dataCapacity = newCap;
39581  }
39582 
39583  /* Fill in a chunk. */
39584  bytesRead = ma_decoder_read_bytes(pDecoder, pVorbis->pData + pVorbis->dataSize, (pVorbis->dataCapacity - pVorbis->dataSize));
39585  if (bytesRead == 0) {
39586  return totalFramesRead; /* Error reading more data. */
39587  }
39588 
39589  pVorbis->dataSize += bytesRead;
39590  }
39591  } while (MA_TRUE);
39592  }
39593 
39594  return totalFramesRead;
39595 }
39596 
39597 static ma_result ma_vorbis_decoder_seek_to_pcm_frame(ma_vorbis_decoder* pVorbis, ma_decoder* pDecoder, ma_uint64 frameIndex)
39598 {
39599  float buffer[4096];
39600 
39601  MA_ASSERT(pVorbis != NULL);
39602  MA_ASSERT(pDecoder != NULL);
39603 
39604  /*
39605  This is terribly inefficient because stb_vorbis does not have a good seeking solution with it's push API. Currently this just performs
39606  a full decode right from the start of the stream. Later on I'll need to write a layer that goes through all of the Ogg pages until we
39607  find the one containing the sample we need. Then we know exactly where to seek for stb_vorbis.
39608  */
39609  if (!ma_decoder_seek_bytes(pDecoder, 0, ma_seek_origin_start)) {
39610  return MA_ERROR;
39611  }
39612 
39613  stb_vorbis_flush_pushdata(pVorbis->pInternalVorbis);
39614  pVorbis->framesConsumed = 0;
39615  pVorbis->framesRemaining = 0;
39616  pVorbis->dataSize = 0;
39617 
39618  while (frameIndex > 0) {
39619  ma_uint32 framesRead;
39620  ma_uint32 framesToRead = ma_countof(buffer)/pDecoder->internalChannels;
39621  if (framesToRead > frameIndex) {
39622  framesToRead = (ma_uint32)frameIndex;
39623  }
39624 
39625  framesRead = (ma_uint32)ma_vorbis_decoder_read_pcm_frames(pVorbis, pDecoder, buffer, framesToRead);
39626  if (framesRead == 0) {
39627  return MA_ERROR;
39628  }
39629 
39630  frameIndex -= framesRead;
39631  }
39632 
39633  return MA_SUCCESS;
39634 }
39635 
39636 
39637 static ma_result ma_decoder_internal_on_seek_to_pcm_frame__vorbis(ma_decoder* pDecoder, ma_uint64 frameIndex)
39638 {
39639  ma_vorbis_decoder* pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder;
39640  MA_ASSERT(pVorbis != NULL);
39641 
39642  return ma_vorbis_decoder_seek_to_pcm_frame(pVorbis, pDecoder, frameIndex);
39643 }
39644 
39645 static ma_result ma_decoder_internal_on_uninit__vorbis(ma_decoder* pDecoder)
39646 {
39647  ma_vorbis_decoder* pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder;
39648  MA_ASSERT(pVorbis != NULL);
39649 
39650  stb_vorbis_close(pVorbis->pInternalVorbis);
39651  ma__free_from_callbacks(pVorbis->pData, &pDecoder->allocationCallbacks);
39652  ma__free_from_callbacks(pVorbis, &pDecoder->allocationCallbacks);
39653 
39654  return MA_SUCCESS;
39655 }
39656 
39657 static ma_uint64 ma_decoder_internal_on_read_pcm_frames__vorbis(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
39658 {
39659  ma_vorbis_decoder* pVorbis;
39660 
39661  MA_ASSERT(pDecoder != NULL);
39662  MA_ASSERT(pFramesOut != NULL);
39663  MA_ASSERT(pDecoder->internalFormat == ma_format_f32);
39664 
39665  pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder;
39666  MA_ASSERT(pVorbis != NULL);
39667 
39668  return ma_vorbis_decoder_read_pcm_frames(pVorbis, pDecoder, pFramesOut, frameCount);
39669 }
39670 
39671 static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__vorbis(ma_decoder* pDecoder)
39672 {
39673  /* No good way to do this with Vorbis. */
39674  (void)pDecoder;
39675  return 0;
39676 }
39677 
39678 static ma_result ma_decoder_init_vorbis__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
39679 {
39680  stb_vorbis* pInternalVorbis = NULL;
39681  size_t dataSize = 0;
39682  size_t dataCapacity = 0;
39683  ma_uint8* pData = NULL;
39684  stb_vorbis_info vorbisInfo;
39685  size_t vorbisDataSize;
39686  ma_vorbis_decoder* pVorbis;
39687 
39688  MA_ASSERT(pConfig != NULL);
39689  MA_ASSERT(pDecoder != NULL);
39690 
39691  /* We grow the buffer in chunks. */
39692  do
39693  {
39694  /* Allocate memory for a new chunk. */
39695  ma_uint8* pNewData;
39696  size_t bytesRead;
39697  int vorbisError = 0;
39698  int consumedDataSize = 0;
39699  size_t oldCapacity = dataCapacity;
39700 
39701  dataCapacity += MA_VORBIS_DATA_CHUNK_SIZE;
39702  pNewData = (ma_uint8*)ma__realloc_from_callbacks(pData, dataCapacity, oldCapacity, &pDecoder->allocationCallbacks);
39703  if (pNewData == NULL) {
39704  ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks);
39705  return MA_OUT_OF_MEMORY;
39706  }
39707 
39708  pData = pNewData;
39709 
39710  /* Fill in a chunk. */
39711  bytesRead = ma_decoder_read_bytes(pDecoder, pData + dataSize, (dataCapacity - dataSize));
39712  if (bytesRead == 0) {
39713  return MA_ERROR;
39714  }
39715 
39716  dataSize += bytesRead;
39717  if (dataSize > INT_MAX) {
39718  return MA_ERROR; /* Too big. */
39719  }
39720 
39721  pInternalVorbis = stb_vorbis_open_pushdata(pData, (int)dataSize, &consumedDataSize, &vorbisError, NULL);
39722  if (pInternalVorbis != NULL) {
39723  /*
39724  If we get here it means we were able to open the stb_vorbis decoder. There may be some leftover bytes in our buffer, so
39725  we need to move those bytes down to the front of the buffer since they'll be needed for future decoding.
39726  */
39727  size_t leftoverDataSize = (dataSize - (size_t)consumedDataSize);
39728  size_t i;
39729  for (i = 0; i < leftoverDataSize; ++i) {
39730  pData[i] = pData[i + consumedDataSize];
39731  }
39732 
39733  dataSize = leftoverDataSize;
39734  break; /* Success. */
39735  } else {
39736  if (vorbisError == VORBIS_need_more_data) {
39737  continue;
39738  } else {
39739  return MA_ERROR; /* Failed to open the stb_vorbis decoder. */
39740  }
39741  }
39742  } while (MA_TRUE);
39743 
39744 
39745  /* If we get here it means we successfully opened the Vorbis decoder. */
39746  vorbisInfo = stb_vorbis_get_info(pInternalVorbis);
39747 
39748  /* Don't allow more than MA_MAX_CHANNELS channels. */
39749  if (vorbisInfo.channels > MA_MAX_CHANNELS) {
39750  stb_vorbis_close(pInternalVorbis);
39751  ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks);
39752  return MA_ERROR; /* Too many channels. */
39753  }
39754 
39755  vorbisDataSize = sizeof(ma_vorbis_decoder) + sizeof(float)*vorbisInfo.max_frame_size;
39756  pVorbis = (ma_vorbis_decoder*)ma__malloc_from_callbacks(vorbisDataSize, &pDecoder->allocationCallbacks);
39757  if (pVorbis == NULL) {
39758  stb_vorbis_close(pInternalVorbis);
39759  ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks);
39760  return MA_OUT_OF_MEMORY;
39761  }
39762 
39763  MA_ZERO_MEMORY(pVorbis, vorbisDataSize);
39764  pVorbis->pInternalVorbis = pInternalVorbis;
39765  pVorbis->pData = pData;
39766  pVorbis->dataSize = dataSize;
39767  pVorbis->dataCapacity = dataCapacity;
39768 
39769  pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__vorbis;
39770  pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__vorbis;
39771  pDecoder->onUninit = ma_decoder_internal_on_uninit__vorbis;
39772  pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__vorbis;
39773  pDecoder->pInternalDecoder = pVorbis;
39774 
39775  /* The internal format is always f32. */
39776  pDecoder->internalFormat = ma_format_f32;
39777  pDecoder->internalChannels = vorbisInfo.channels;
39778  pDecoder->internalSampleRate = vorbisInfo.sample_rate;
39780 
39781  return MA_SUCCESS;
39782 }
39783 #endif /* STB_VORBIS_INCLUDE_STB_VORBIS_H */
39784 
39785 /* MP3 */
39786 #ifdef dr_mp3_h
39787 #define MA_HAS_MP3
39788 
39789 static size_t ma_decoder_internal_on_read__mp3(void* pUserData, void* pBufferOut, size_t bytesToRead)
39790 {
39791  ma_decoder* pDecoder = (ma_decoder*)pUserData;
39792  MA_ASSERT(pDecoder != NULL);
39793 
39794  return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead);
39795 }
39796 
39797 static drmp3_bool32 ma_decoder_internal_on_seek__mp3(void* pUserData, int offset, drmp3_seek_origin origin)
39798 {
39799  ma_decoder* pDecoder = (ma_decoder*)pUserData;
39800  MA_ASSERT(pDecoder != NULL);
39801 
39803 }
39804 
39805 static ma_uint64 ma_decoder_internal_on_read_pcm_frames__mp3(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
39806 {
39807  drmp3* pMP3;
39808 
39809  MA_ASSERT(pDecoder != NULL);
39810  MA_ASSERT(pFramesOut != NULL);
39811  MA_ASSERT(pDecoder->internalFormat == ma_format_f32);
39812 
39813  pMP3 = (drmp3*)pDecoder->pInternalDecoder;
39814  MA_ASSERT(pMP3 != NULL);
39815 
39816  return drmp3_read_pcm_frames_f32(pMP3, frameCount, (float*)pFramesOut);
39817 }
39818 
39819 static ma_result ma_decoder_internal_on_seek_to_pcm_frame__mp3(ma_decoder* pDecoder, ma_uint64 frameIndex)
39820 {
39821  drmp3* pMP3;
39822  drmp3_bool32 result;
39823 
39824  pMP3 = (drmp3*)pDecoder->pInternalDecoder;
39825  MA_ASSERT(pMP3 != NULL);
39826 
39827  result = drmp3_seek_to_pcm_frame(pMP3, frameIndex);
39828  if (result) {
39829  return MA_SUCCESS;
39830  } else {
39831  return MA_ERROR;
39832  }
39833 }
39834 
39835 static ma_result ma_decoder_internal_on_uninit__mp3(ma_decoder* pDecoder)
39836 {
39837  drmp3_uninit((drmp3*)pDecoder->pInternalDecoder);
39839  return MA_SUCCESS;
39840 }
39841 
39842 static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__mp3(ma_decoder* pDecoder)
39843 {
39844  return drmp3_get_pcm_frame_count((drmp3*)pDecoder->pInternalDecoder);
39845 }
39846 
39847 static ma_result ma_decoder_init_mp3__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
39848 {
39849  drmp3* pMP3;
39850  drmp3_config mp3Config;
39851  drmp3_allocation_callbacks allocationCallbacks;
39852 
39853  MA_ASSERT(pConfig != NULL);
39854  MA_ASSERT(pDecoder != NULL);
39855 
39856  pMP3 = (drmp3*)ma__malloc_from_callbacks(sizeof(*pMP3), &pDecoder->allocationCallbacks);
39857  if (pMP3 == NULL) {
39858  return MA_OUT_OF_MEMORY;
39859  }
39860 
39861  allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData;
39862  allocationCallbacks.onMalloc = pDecoder->allocationCallbacks.onMalloc;
39863  allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc;
39864  allocationCallbacks.onFree = pDecoder->allocationCallbacks.onFree;
39865 
39866  /*
39867  Try opening the decoder first. MP3 can have variable sample rates (it's per frame/packet). We therefore need
39868  to use some smarts to determine the most appropriate internal sample rate. These are the rules we're going
39869  to use:
39870 
39871  Sample Rates
39872  1) If an output sample rate is specified in pConfig we just use that. Otherwise;
39873  2) Fall back to 44100.
39874 
39875  The internal channel count is always stereo, and the internal format is always f32.
39876  */
39877  MA_ZERO_OBJECT(&mp3Config);
39878  mp3Config.outputChannels = 2;
39879  mp3Config.outputSampleRate = (pConfig->sampleRate != 0) ? pConfig->sampleRate : 44100;
39880  if (!drmp3_init(pMP3, ma_decoder_internal_on_read__mp3, ma_decoder_internal_on_seek__mp3, pDecoder, &mp3Config, &allocationCallbacks)) {
39881  ma__free_from_callbacks(pMP3, &pDecoder->allocationCallbacks);
39882  return MA_ERROR;
39883  }
39884 
39885  /* If we get here it means we successfully initialized the MP3 decoder. We can now initialize the rest of the ma_decoder. */
39886  pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__mp3;
39887  pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__mp3;
39888  pDecoder->onUninit = ma_decoder_internal_on_uninit__mp3;
39889  pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__mp3;
39890  pDecoder->pInternalDecoder = pMP3;
39891 
39892  /* Internal format. */
39893  pDecoder->internalFormat = ma_format_f32;
39894  pDecoder->internalChannels = pMP3->channels;
39895  pDecoder->internalSampleRate = pMP3->sampleRate;
39897 
39898  return MA_SUCCESS;
39899 }
39900 #endif /* dr_mp3_h */
39901 
39902 /* Raw */
39903 static ma_uint64 ma_decoder_internal_on_read_pcm_frames__raw(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
39904 {
39905  ma_uint32 bpf;
39906  ma_uint64 totalFramesRead;
39907  void* pRunningFramesOut;
39908 
39909 
39910  MA_ASSERT(pDecoder != NULL);
39911  MA_ASSERT(pFramesOut != NULL);
39912 
39913  /* For raw decoding we just read directly from the decoder's callbacks. */
39914  bpf = ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels);
39915 
39916  totalFramesRead = 0;
39917  pRunningFramesOut = pFramesOut;
39918 
39919  while (totalFramesRead < frameCount) {
39920  ma_uint64 framesReadThisIteration;
39921  ma_uint64 framesToReadThisIteration = (frameCount - totalFramesRead);
39922  if (framesToReadThisIteration > MA_SIZE_MAX) {
39923  framesToReadThisIteration = MA_SIZE_MAX;
39924  }
39925 
39926  framesReadThisIteration = ma_decoder_read_bytes(pDecoder, pRunningFramesOut, (size_t)framesToReadThisIteration * bpf) / bpf; /* Safe cast to size_t. */
39927 
39928  totalFramesRead += framesReadThisIteration;
39929  pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIteration * bpf);
39930 
39931  if (framesReadThisIteration < framesToReadThisIteration) {
39932  break; /* Done. */
39933  }
39934  }
39935 
39936  return totalFramesRead;
39937 }
39938 
39939 static ma_result ma_decoder_internal_on_seek_to_pcm_frame__raw(ma_decoder* pDecoder, ma_uint64 frameIndex)
39940 {
39941  ma_bool32 result = MA_FALSE;
39942  ma_uint64 totalBytesToSeek;
39943 
39944  MA_ASSERT(pDecoder != NULL);
39945 
39946  if (pDecoder->onSeek == NULL) {
39947  return MA_ERROR;
39948  }
39949 
39950  /* The callback uses a 32 bit integer whereas we use a 64 bit unsigned integer. We just need to continuously seek until we're at the correct position. */
39951  totalBytesToSeek = frameIndex * ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels);
39952  if (totalBytesToSeek < 0x7FFFFFFF) {
39953  /* Simple case. */
39954  result = ma_decoder_seek_bytes(pDecoder, (int)(frameIndex * ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels)), ma_seek_origin_start);
39955  } else {
39956  /* Complex case. Start by doing a seek relative to the start. Then keep looping using offset seeking. */
39957  result = ma_decoder_seek_bytes(pDecoder, 0x7FFFFFFF, ma_seek_origin_start);
39958  if (result == MA_TRUE) {
39959  totalBytesToSeek -= 0x7FFFFFFF;
39960 
39961  while (totalBytesToSeek > 0) {
39962  ma_uint64 bytesToSeekThisIteration = totalBytesToSeek;
39963  if (bytesToSeekThisIteration > 0x7FFFFFFF) {
39964  bytesToSeekThisIteration = 0x7FFFFFFF;
39965  }
39966 
39967  result = ma_decoder_seek_bytes(pDecoder, (int)bytesToSeekThisIteration, ma_seek_origin_current);
39968  if (result != MA_TRUE) {
39969  break;
39970  }
39971 
39972  totalBytesToSeek -= bytesToSeekThisIteration;
39973  }
39974  }
39975  }
39976 
39977  if (result) {
39978  return MA_SUCCESS;
39979  } else {
39980  return MA_ERROR;
39981  }
39982 }
39983 
39984 static ma_result ma_decoder_internal_on_uninit__raw(ma_decoder* pDecoder)
39985 {
39986  (void)pDecoder;
39987  return MA_SUCCESS;
39988 }
39989 
39990 static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__raw(ma_decoder* pDecoder)
39991 {
39992  (void)pDecoder;
39993  return 0;
39994 }
39995 
39996 static ma_result ma_decoder_init_raw__internal(const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder)
39997 {
39998  MA_ASSERT(pConfigIn != NULL);
39999  MA_ASSERT(pConfigOut != NULL);
40000  MA_ASSERT(pDecoder != NULL);
40001 
40002  pDecoder->onReadPCMFrames = ma_decoder_internal_on_read_pcm_frames__raw;
40003  pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__raw;
40004  pDecoder->onUninit = ma_decoder_internal_on_uninit__raw;
40005  pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__raw;
40006 
40007  /* Internal format. */
40008  pDecoder->internalFormat = pConfigIn->format;
40009  pDecoder->internalChannels = pConfigIn->channels;
40010  pDecoder->internalSampleRate = pConfigIn->sampleRate;
40011  ma_channel_map_copy(pDecoder->internalChannelMap, pConfigIn->channelMap, pConfigIn->channels);
40012 
40013  return MA_SUCCESS;
40014 }
40015 
40017 {
40018  MA_ASSERT(pDecoder != NULL);
40019 
40020  if (pConfig != NULL) {
40022  } else {
40024  return MA_SUCCESS;
40025  }
40026 }
40027 
40028 static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40029 {
40030  ma_result result;
40031 
40032  MA_ASSERT(pConfig != NULL);
40033 
40034  if (pDecoder == NULL) {
40035  return MA_INVALID_ARGS;
40036  }
40037 
40038  MA_ZERO_OBJECT(pDecoder);
40039 
40040  if (onRead == NULL || onSeek == NULL) {
40041  return MA_INVALID_ARGS;
40042  }
40043 
40044  pDecoder->onRead = onRead;
40045  pDecoder->onSeek = onSeek;
40046  pDecoder->pUserData = pUserData;
40047 
40048  result = ma_decoder__init_allocation_callbacks(pConfig, pDecoder);
40049  if (result != MA_SUCCESS) {
40050  return result;
40051  }
40052 
40053  return MA_SUCCESS;
40054 }
40055 
40056 static ma_result ma_decoder__postinit(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40057 {
40058  ma_result result;
40059 
40060  result = ma_decoder__init_data_converter(pDecoder, pConfig);
40061  if (result != MA_SUCCESS) {
40062  return result;
40063  }
40064 
40065  return result;
40066 }
40067 
40068 ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40069 {
40071  ma_result result;
40072 
40074 
40075  result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
40076  if (result != MA_SUCCESS) {
40077  return result;
40078  }
40079 
40080 #ifdef MA_HAS_WAV
40081  result = ma_decoder_init_wav__internal(&config, pDecoder);
40082 #else
40083  result = MA_NO_BACKEND;
40084 #endif
40085  if (result != MA_SUCCESS) {
40086  return result;
40087  }
40088 
40089  return ma_decoder__postinit(&config, pDecoder);
40090 }
40091 
40092 ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40093 {
40095  ma_result result;
40096 
40098 
40099  result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
40100  if (result != MA_SUCCESS) {
40101  return result;
40102  }
40103 
40104 #ifdef MA_HAS_FLAC
40105  result = ma_decoder_init_flac__internal(&config, pDecoder);
40106 #else
40107  result = MA_NO_BACKEND;
40108 #endif
40109  if (result != MA_SUCCESS) {
40110  return result;
40111  }
40112 
40113  return ma_decoder__postinit(&config, pDecoder);
40114 }
40115 
40116 ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40117 {
40119  ma_result result;
40120 
40122 
40123  result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
40124  if (result != MA_SUCCESS) {
40125  return result;
40126  }
40127 
40128 #ifdef MA_HAS_VORBIS
40129  result = ma_decoder_init_vorbis__internal(&config, pDecoder);
40130 #else
40131  result = MA_NO_BACKEND;
40132 #endif
40133  if (result != MA_SUCCESS) {
40134  return result;
40135  }
40136 
40137  return ma_decoder__postinit(&config, pDecoder);
40138 }
40139 
40140 ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40141 {
40143  ma_result result;
40144 
40146 
40147  result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
40148  if (result != MA_SUCCESS) {
40149  return result;
40150  }
40151 
40152 #ifdef MA_HAS_MP3
40153  result = ma_decoder_init_mp3__internal(&config, pDecoder);
40154 #else
40155  result = MA_NO_BACKEND;
40156 #endif
40157  if (result != MA_SUCCESS) {
40158  return result;
40159  }
40160 
40161  return ma_decoder__postinit(&config, pDecoder);
40162 }
40163 
40164 ma_result ma_decoder_init_raw(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder)
40165 {
40167  ma_result result;
40168 
40169  config = ma_decoder_config_init_copy(pConfigOut);
40170 
40171  result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
40172  if (result != MA_SUCCESS) {
40173  return result;
40174  }
40175 
40176  result = ma_decoder_init_raw__internal(pConfigIn, &config, pDecoder);
40177  if (result != MA_SUCCESS) {
40178  return result;
40179  }
40180 
40181  return ma_decoder__postinit(&config, pDecoder);
40182 }
40183 
40184 static ma_result ma_decoder_init__internal(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40185 {
40186  ma_result result = MA_NO_BACKEND;
40187 
40188  MA_ASSERT(pConfig != NULL);
40189  MA_ASSERT(pDecoder != NULL);
40190 
40191  /* Silence some warnings in the case that we don't have any decoder backends enabled. */
40192  (void)onRead;
40193  (void)onSeek;
40194  (void)pUserData;
40195  (void)pConfig;
40196  (void)pDecoder;
40197 
40198  /* We use trial and error to open a decoder. */
40199 
40200 #ifdef MA_HAS_WAV
40201  if (result != MA_SUCCESS) {
40202  result = ma_decoder_init_wav__internal(pConfig, pDecoder);
40203  if (result != MA_SUCCESS) {
40204  onSeek(pDecoder, 0, ma_seek_origin_start);
40205  }
40206  }
40207 #endif
40208 #ifdef MA_HAS_FLAC
40209  if (result != MA_SUCCESS) {
40210  result = ma_decoder_init_flac__internal(pConfig, pDecoder);
40211  if (result != MA_SUCCESS) {
40212  onSeek(pDecoder, 0, ma_seek_origin_start);
40213  }
40214  }
40215 #endif
40216 #ifdef MA_HAS_VORBIS
40217  if (result != MA_SUCCESS) {
40218  result = ma_decoder_init_vorbis__internal(pConfig, pDecoder);
40219  if (result != MA_SUCCESS) {
40220  onSeek(pDecoder, 0, ma_seek_origin_start);
40221  }
40222  }
40223 #endif
40224 #ifdef MA_HAS_MP3
40225  if (result != MA_SUCCESS) {
40226  result = ma_decoder_init_mp3__internal(pConfig, pDecoder);
40227  if (result != MA_SUCCESS) {
40228  onSeek(pDecoder, 0, ma_seek_origin_start);
40229  }
40230  }
40231 #endif
40232 
40233  if (result != MA_SUCCESS) {
40234  return result;
40235  }
40236 
40237  return ma_decoder__postinit(pConfig, pDecoder);
40238 }
40239 
40240 ma_result ma_decoder_init(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40241 {
40243  ma_result result;
40244 
40246 
40247  result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
40248  if (result != MA_SUCCESS) {
40249  return result;
40250  }
40251 
40252  return ma_decoder_init__internal(onRead, onSeek, pUserData, &config, pDecoder);
40253 }
40254 
40255 
40256 static size_t ma_decoder__on_read_memory(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead)
40257 {
40258  size_t bytesRemaining;
40259 
40260  MA_ASSERT(pDecoder->memory.dataSize >= pDecoder->memory.currentReadPos);
40261 
40262  bytesRemaining = pDecoder->memory.dataSize - pDecoder->memory.currentReadPos;
40263  if (bytesToRead > bytesRemaining) {
40264  bytesToRead = bytesRemaining;
40265  }
40266 
40267  if (bytesToRead > 0) {
40268  MA_COPY_MEMORY(pBufferOut, pDecoder->memory.pData + pDecoder->memory.currentReadPos, bytesToRead);
40269  pDecoder->memory.currentReadPos += bytesToRead;
40270  }
40271 
40272  return bytesToRead;
40273 }
40274 
40275 static ma_bool32 ma_decoder__on_seek_memory(ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin)
40276 {
40277  if (origin == ma_seek_origin_current) {
40278  if (byteOffset > 0) {
40279  if (pDecoder->memory.currentReadPos + byteOffset > pDecoder->memory.dataSize) {
40280  byteOffset = (int)(pDecoder->memory.dataSize - pDecoder->memory.currentReadPos); /* Trying to seek too far forward. */
40281  }
40282  } else {
40283  if (pDecoder->memory.currentReadPos < (size_t)-byteOffset) {
40284  byteOffset = -(int)pDecoder->memory.currentReadPos; /* Trying to seek too far backwards. */
40285  }
40286  }
40287 
40288  /* This will never underflow thanks to the clamps above. */
40289  pDecoder->memory.currentReadPos += byteOffset;
40290  } else {
40291  if ((ma_uint32)byteOffset <= pDecoder->memory.dataSize) {
40292  pDecoder->memory.currentReadPos = byteOffset;
40293  } else {
40294  pDecoder->memory.currentReadPos = pDecoder->memory.dataSize; /* Trying to seek too far forward. */
40295  }
40296  }
40297 
40298  return MA_TRUE;
40299 }
40300 
40301 static ma_result ma_decoder__preinit_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40302 {
40304  if (result != MA_SUCCESS) {
40305  return result;
40306  }
40307 
40308  if (pData == NULL || dataSize == 0) {
40309  return MA_INVALID_ARGS;
40310  }
40311 
40312  pDecoder->memory.pData = (const ma_uint8*)pData;
40313  pDecoder->memory.dataSize = dataSize;
40314  pDecoder->memory.currentReadPos = 0;
40315 
40316  (void)pConfig;
40317  return MA_SUCCESS;
40318 }
40319 
40320 ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40321 {
40323  ma_result result;
40324 
40325  config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */
40326 
40327  result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
40328  if (result != MA_SUCCESS) {
40329  return result;
40330  }
40331 
40333 }
40334 
40335 ma_result ma_decoder_init_memory_wav(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40336 {
40338  ma_result result;
40339 
40340  config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */
40341 
40342  result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
40343  if (result != MA_SUCCESS) {
40344  return result;
40345  }
40346 
40347 #ifdef MA_HAS_WAV
40348  result = ma_decoder_init_wav__internal(&config, pDecoder);
40349 #else
40350  result = MA_NO_BACKEND;
40351 #endif
40352  if (result != MA_SUCCESS) {
40353  return result;
40354  }
40355 
40356  return ma_decoder__postinit(&config, pDecoder);
40357 }
40358 
40359 ma_result ma_decoder_init_memory_flac(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40360 {
40362  ma_result result;
40363 
40364  config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */
40365 
40366  result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
40367  if (result != MA_SUCCESS) {
40368  return result;
40369  }
40370 
40371 #ifdef MA_HAS_FLAC
40372  result = ma_decoder_init_flac__internal(&config, pDecoder);
40373 #else
40374  result = MA_NO_BACKEND;
40375 #endif
40376  if (result != MA_SUCCESS) {
40377  return result;
40378  }
40379 
40380  return ma_decoder__postinit(&config, pDecoder);
40381 }
40382 
40383 ma_result ma_decoder_init_memory_vorbis(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40384 {
40386  ma_result result;
40387 
40388  config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */
40389 
40390  result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
40391  if (result != MA_SUCCESS) {
40392  return result;
40393  }
40394 
40395 #ifdef MA_HAS_VORBIS
40396  result = ma_decoder_init_vorbis__internal(&config, pDecoder);
40397 #else
40398  result = MA_NO_BACKEND;
40399 #endif
40400  if (result != MA_SUCCESS) {
40401  return result;
40402  }
40403 
40404  return ma_decoder__postinit(&config, pDecoder);
40405 }
40406 
40407 ma_result ma_decoder_init_memory_mp3(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40408 {
40410  ma_result result;
40411 
40412  config = ma_decoder_config_init_copy(pConfig); /* Make sure the config is not NULL. */
40413 
40414  result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
40415  if (result != MA_SUCCESS) {
40416  return result;
40417  }
40418 
40419 #ifdef MA_HAS_MP3
40420  result = ma_decoder_init_mp3__internal(&config, pDecoder);
40421 #else
40422  result = MA_NO_BACKEND;
40423 #endif
40424  if (result != MA_SUCCESS) {
40425  return result;
40426  }
40427 
40428  return ma_decoder__postinit(&config, pDecoder);
40429 }
40430 
40431 ma_result ma_decoder_init_memory_raw(const void* pData, size_t dataSize, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder)
40432 {
40434  ma_result result;
40435 
40436  config = ma_decoder_config_init_copy(pConfigOut); /* Make sure the config is not NULL. */
40437 
40438  result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
40439  if (result != MA_SUCCESS) {
40440  return result;
40441  }
40442 
40443  result = ma_decoder_init_raw__internal(pConfigIn, &config, pDecoder);
40444  if (result != MA_SUCCESS) {
40445  return result;
40446  }
40447 
40448  return ma_decoder__postinit(&config, pDecoder);
40449 }
40450 
40451 #ifndef MA_NO_STDIO
40452 static const char* ma_path_file_name(const char* path)
40453 {
40454  const char* fileName;
40455 
40456  if (path == NULL) {
40457  return NULL;
40458  }
40459 
40460  fileName = path;
40461 
40462  /* We just loop through the path until we find the last slash. */
40463  while (path[0] != '\0') {
40464  if (path[0] == '/' || path[0] == '\\') {
40465  fileName = path;
40466  }
40467 
40468  path += 1;
40469  }
40470 
40471  /* At this point the file name is sitting on a slash, so just move forward. */
40472  while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) {
40473  fileName += 1;
40474  }
40475 
40476  return fileName;
40477 }
40478 
40479 static const wchar_t* ma_path_file_name_w(const wchar_t* path)
40480 {
40481  const wchar_t* fileName;
40482 
40483  if (path == NULL) {
40484  return NULL;
40485  }
40486 
40487  fileName = path;
40488 
40489  /* We just loop through the path until we find the last slash. */
40490  while (path[0] != '\0') {
40491  if (path[0] == '/' || path[0] == '\\') {
40492  fileName = path;
40493  }
40494 
40495  path += 1;
40496  }
40497 
40498  /* At this point the file name is sitting on a slash, so just move forward. */
40499  while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) {
40500  fileName += 1;
40501  }
40502 
40503  return fileName;
40504 }
40505 
40506 
40507 static const char* ma_path_extension(const char* path)
40508 {
40509  const char* extension;
40510  const char* lastOccurance;
40511 
40512  if (path == NULL) {
40513  path = "";
40514  }
40515 
40516  extension = ma_path_file_name(path);
40517  lastOccurance = NULL;
40518 
40519  /* Just find the last '.' and return. */
40520  while (extension[0] != '\0') {
40521  if (extension[0] == '.') {
40522  extension += 1;
40523  lastOccurance = extension;
40524  }
40525 
40526  extension += 1;
40527  }
40528 
40529  return (lastOccurance != NULL) ? lastOccurance : extension;
40530 }
40531 
40532 static const wchar_t* ma_path_extension_w(const wchar_t* path)
40533 {
40534  const wchar_t* extension;
40535  const wchar_t* lastOccurance;
40536 
40537  if (path == NULL) {
40538  path = L"";
40539  }
40540 
40541  extension = ma_path_file_name_w(path);
40542  lastOccurance = NULL;
40543 
40544  /* Just find the last '.' and return. */
40545  while (extension[0] != '\0') {
40546  if (extension[0] == '.') {
40547  extension += 1;
40548  lastOccurance = extension;
40549  }
40550 
40551  extension += 1;
40552  }
40553 
40554  return (lastOccurance != NULL) ? lastOccurance : extension;
40555 }
40556 
40557 
40558 static ma_bool32 ma_path_extension_equal(const char* path, const char* extension)
40559 {
40560  const char* ext1;
40561  const char* ext2;
40562 
40563  if (path == NULL || extension == NULL) {
40564  return MA_FALSE;
40565  }
40566 
40567  ext1 = extension;
40568  ext2 = ma_path_extension(path);
40569 
40570 #if defined(_MSC_VER) || defined(__DMC__)
40571  return _stricmp(ext1, ext2) == 0;
40572 #else
40573  return strcasecmp(ext1, ext2) == 0;
40574 #endif
40575 }
40576 
40577 static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* extension)
40578 {
40579  const wchar_t* ext1;
40580  const wchar_t* ext2;
40581 
40582  if (path == NULL || extension == NULL) {
40583  return MA_FALSE;
40584  }
40585 
40586  ext1 = extension;
40587  ext2 = ma_path_extension_w(path);
40588 
40589 #if defined(_MSC_VER) || defined(__DMC__)
40590  return _wcsicmp(ext1, ext2) == 0;
40591 #else
40592  /*
40593  I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This
40594  isn't the most efficient way to do it, but it should work OK.
40595  */
40596  {
40597  char ext1MB[4096];
40598  char ext2MB[4096];
40599  const wchar_t* pext1 = ext1;
40600  const wchar_t* pext2 = ext2;
40601  mbstate_t mbs1;
40602  mbstate_t mbs2;
40603 
40604  MA_ZERO_OBJECT(&mbs1);
40605  MA_ZERO_OBJECT(&mbs2);
40606 
40607  if (wcsrtombs(ext1MB, &pext1, sizeof(ext1MB), &mbs1) == (size_t)-1) {
40608  return MA_FALSE;
40609  }
40610  if (wcsrtombs(ext2MB, &pext2, sizeof(ext2MB), &mbs2) == (size_t)-1) {
40611  return MA_FALSE;
40612  }
40613 
40614  return strcasecmp(ext1MB, ext2MB) == 0;
40615  }
40616 #endif
40617 }
40618 
40619 
40620 static size_t ma_decoder__on_read_stdio(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead)
40621 {
40622  return fread(pBufferOut, 1, bytesToRead, (FILE*)pDecoder->pUserData);
40623 }
40624 
40625 static ma_bool32 ma_decoder__on_seek_stdio(ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin)
40626 {
40627  return fseek((FILE*)pDecoder->pUserData, byteOffset, (origin == ma_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
40628 }
40629 
40630 static ma_result ma_decoder__preinit_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40631 {
40632  ma_result result;
40633  FILE* pFile;
40634 
40635  if (pDecoder == NULL) {
40636  return MA_INVALID_ARGS;
40637  }
40638 
40639  MA_ZERO_OBJECT(pDecoder);
40640 
40641  if (pFilePath == NULL || pFilePath[0] == '\0') {
40642  return MA_INVALID_ARGS;
40643  }
40644 
40645  result = ma_decoder__init_allocation_callbacks(pConfig, pDecoder);
40646  if (result != MA_SUCCESS) {
40647  return result;
40648  }
40649 
40650  result = ma_fopen(&pFile, pFilePath, "rb");
40651  if (pFile == NULL) {
40652  return result;
40653  }
40654 
40655  /* We need to manually set the user data so the calls to ma_decoder__on_seek_stdio() succeed. */
40656  pDecoder->pUserData = pFile;
40657 
40658  return MA_SUCCESS;
40659 }
40660 
40661 static ma_result ma_decoder__preinit_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40662 {
40663  ma_result result;
40664  FILE* pFile;
40665 
40666  if (pDecoder == NULL) {
40667  return MA_INVALID_ARGS;
40668  }
40669 
40670  MA_ZERO_OBJECT(pDecoder);
40671 
40672  if (pFilePath == NULL || pFilePath[0] == '\0') {
40673  return MA_INVALID_ARGS;
40674  }
40675 
40676  result = ma_decoder__init_allocation_callbacks(pConfig, pDecoder);
40677  if (result != MA_SUCCESS) {
40678  return result;
40679  }
40680 
40681  result = ma_wfopen(&pFile, pFilePath, L"rb", &pDecoder->allocationCallbacks);
40682  if (pFile == NULL) {
40683  return result;
40684  }
40685 
40686  /* We need to manually set the user data so the calls to ma_decoder__on_seek_stdio() succeed. */
40687  pDecoder->pUserData = pFile;
40688 
40689  (void)pConfig;
40690  return MA_SUCCESS;
40691 }
40692 
40693 ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40694 {
40695  ma_result result = ma_decoder__preinit_file(pFilePath, pConfig, pDecoder); /* This sets pDecoder->pUserData to a FILE*. */
40696  if (result != MA_SUCCESS) {
40697  return result;
40698  }
40699 
40700  /* WAV */
40701  if (ma_path_extension_equal(pFilePath, "wav")) {
40702  result = ma_decoder_init_wav(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40703  if (result == MA_SUCCESS) {
40704  return MA_SUCCESS;
40705  }
40706 
40707  ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start);
40708  }
40709 
40710  /* FLAC */
40711  if (ma_path_extension_equal(pFilePath, "flac")) {
40712  result = ma_decoder_init_flac(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40713  if (result == MA_SUCCESS) {
40714  return MA_SUCCESS;
40715  }
40716 
40717  ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start);
40718  }
40719 
40720  /* MP3 */
40721  if (ma_path_extension_equal(pFilePath, "mp3")) {
40722  result = ma_decoder_init_mp3(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40723  if (result == MA_SUCCESS) {
40724  return MA_SUCCESS;
40725  }
40726 
40727  ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start);
40728  }
40729 
40730  /* Trial and error. */
40731  return ma_decoder_init(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40732 }
40733 
40734 ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40735 {
40736  ma_result result = ma_decoder__preinit_file(pFilePath, pConfig, pDecoder);
40737  if (result != MA_SUCCESS) {
40738  return result;
40739  }
40740 
40741  return ma_decoder_init_wav(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40742 }
40743 
40744 ma_result ma_decoder_init_file_flac(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40745 {
40746  ma_result result = ma_decoder__preinit_file(pFilePath, pConfig, pDecoder);
40747  if (result != MA_SUCCESS) {
40748  return result;
40749  }
40750 
40751  return ma_decoder_init_flac(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40752 }
40753 
40754 ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40755 {
40756  ma_result result = ma_decoder__preinit_file(pFilePath, pConfig, pDecoder);
40757  if (result != MA_SUCCESS) {
40758  return result;
40759  }
40760 
40761  return ma_decoder_init_vorbis(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40762 }
40763 
40764 ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40765 {
40766  ma_result result = ma_decoder__preinit_file(pFilePath, pConfig, pDecoder);
40767  if (result != MA_SUCCESS) {
40768  return result;
40769  }
40770 
40771  return ma_decoder_init_mp3(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40772 }
40773 
40774 
40775 ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40776 {
40777  ma_result result = ma_decoder__preinit_file_w(pFilePath, pConfig, pDecoder); /* This sets pDecoder->pUserData to a FILE*. */
40778  if (result != MA_SUCCESS) {
40779  return result;
40780  }
40781 
40782  /* WAV */
40783  if (ma_path_extension_equal_w(pFilePath, L"wav")) {
40784  result = ma_decoder_init_wav(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40785  if (result == MA_SUCCESS) {
40786  return MA_SUCCESS;
40787  }
40788 
40789  ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start);
40790  }
40791 
40792  /* FLAC */
40793  if (ma_path_extension_equal_w(pFilePath, L"flac")) {
40794  result = ma_decoder_init_flac(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40795  if (result == MA_SUCCESS) {
40796  return MA_SUCCESS;
40797  }
40798 
40799  ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start);
40800  }
40801 
40802  /* MP3 */
40803  if (ma_path_extension_equal_w(pFilePath, L"mp3")) {
40804  result = ma_decoder_init_mp3(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40805  if (result == MA_SUCCESS) {
40806  return MA_SUCCESS;
40807  }
40808 
40809  ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start);
40810  }
40811 
40812  /* Trial and error. */
40813  return ma_decoder_init(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40814 }
40815 
40816 ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40817 {
40818  ma_result result = ma_decoder__preinit_file_w(pFilePath, pConfig, pDecoder);
40819  if (result != MA_SUCCESS) {
40820  return result;
40821  }
40822 
40823  return ma_decoder_init_wav(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40824 }
40825 
40826 ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40827 {
40828  ma_result result = ma_decoder__preinit_file_w(pFilePath, pConfig, pDecoder);
40829  if (result != MA_SUCCESS) {
40830  return result;
40831  }
40832 
40833  return ma_decoder_init_flac(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40834 }
40835 
40836 ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40837 {
40838  ma_result result = ma_decoder__preinit_file_w(pFilePath, pConfig, pDecoder);
40839  if (result != MA_SUCCESS) {
40840  return result;
40841  }
40842 
40843  return ma_decoder_init_vorbis(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40844 }
40845 
40846 ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
40847 {
40848  ma_result result = ma_decoder__preinit_file_w(pFilePath, pConfig, pDecoder);
40849  if (result != MA_SUCCESS) {
40850  return result;
40851  }
40852 
40853  return ma_decoder_init_mp3(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder);
40854 }
40855 #endif /* MA_NO_STDIO */
40856 
40858 {
40859  if (pDecoder == NULL) {
40860  return MA_INVALID_ARGS;
40861  }
40862 
40863  if (pDecoder->onUninit) {
40864  pDecoder->onUninit(pDecoder);
40865  }
40866 
40867 #ifndef MA_NO_STDIO
40868  /* If we have a file handle, close it. */
40869  if (pDecoder->onRead == ma_decoder__on_read_stdio) {
40870  fclose((FILE*)pDecoder->pUserData);
40871  }
40872 #endif
40873 
40874  ma_data_converter_uninit(&pDecoder->converter);
40875 
40876  return MA_SUCCESS;
40877 }
40878 
40880 {
40881  if (pDecoder == NULL) {
40882  return 0;
40883  }
40884 
40885  if (pDecoder->onGetLengthInPCMFrames) {
40886  ma_uint64 nativeLengthInPCMFrames = pDecoder->onGetLengthInPCMFrames(pDecoder);
40887  if (pDecoder->internalSampleRate == pDecoder->outputSampleRate) {
40888  return nativeLengthInPCMFrames;
40889  } else {
40890  return ma_calculate_frame_count_after_resampling(pDecoder->outputSampleRate, pDecoder->internalSampleRate, nativeLengthInPCMFrames);
40891  }
40892  }
40893 
40894  return 0;
40895 }
40896 
40897 ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
40898 {
40899  ma_result result;
40900  ma_uint64 totalFramesReadOut;
40901  ma_uint64 totalFramesReadIn;
40902  void* pRunningFramesOut;
40903 
40904  if (pDecoder == NULL) {
40905  return 0;
40906  }
40907 
40908  if (pDecoder->onReadPCMFrames == NULL) {
40909  return 0;
40910  }
40911 
40912  /* Fast path. */
40913  if (pDecoder->converter.isPassthrough) {
40914  return pDecoder->onReadPCMFrames(pDecoder, pFramesOut, frameCount);
40915  }
40916 
40917  /* Getting here means we need to do data conversion. */
40918  totalFramesReadOut = 0;
40919  totalFramesReadIn = 0;
40920  pRunningFramesOut = pFramesOut;
40921 
40922  while (totalFramesReadOut < frameCount) {
40923  ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* In internal format. */
40924  ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels);
40925  ma_uint64 framesToReadThisIterationIn;
40926  ma_uint64 framesReadThisIterationIn;
40927  ma_uint64 framesToReadThisIterationOut;
40928  ma_uint64 framesReadThisIterationOut;
40929  ma_uint64 requiredInputFrameCount;
40930 
40931  framesToReadThisIterationOut = (frameCount - totalFramesReadOut);
40932  framesToReadThisIterationIn = framesToReadThisIterationOut;
40933  if (framesToReadThisIterationIn > intermediaryBufferCap) {
40934  framesToReadThisIterationIn = intermediaryBufferCap;
40935  }
40936 
40937  requiredInputFrameCount = ma_data_converter_get_required_input_frame_count(&pDecoder->converter, framesToReadThisIterationOut);
40938  if (framesToReadThisIterationIn > requiredInputFrameCount) {
40939  framesToReadThisIterationIn = requiredInputFrameCount;
40940  }
40941 
40942  if (requiredInputFrameCount > 0) {
40943  framesReadThisIterationIn = pDecoder->onReadPCMFrames(pDecoder, pIntermediaryBuffer, framesToReadThisIterationIn);
40944  totalFramesReadIn += framesReadThisIterationIn;
40945  }
40946 
40947  /*
40948  At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any
40949  input frames, we still want to try processing frames because there may some output frames generated from cached input data.
40950  */
40951  framesReadThisIterationOut = framesToReadThisIterationOut;
40952  result = ma_data_converter_process_pcm_frames(&pDecoder->converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut);
40953  if (result != MA_SUCCESS) {
40954  break;
40955  }
40956 
40957  totalFramesReadOut += framesReadThisIterationOut;
40958  pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels));
40959 
40960  if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) {
40961  break; /* We're done. */
40962  }
40963  }
40964 
40965  return totalFramesReadOut;
40966 }
40967 
40969 {
40970  if (pDecoder == NULL) {
40971  return 0;
40972  }
40973 
40974  if (pDecoder->onSeekToPCMFrame) {
40975  return pDecoder->onSeekToPCMFrame(pDecoder, frameIndex);
40976  }
40977 
40978  /* Should never get here, but if we do it means onSeekToPCMFrame was not set by the backend. */
40979  return MA_INVALID_ARGS;
40980 }
40981 
40982 
40983 static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_decoder_config* pConfigOut, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
40984 {
40985  ma_uint64 totalFrameCount;
40986  ma_uint64 bpf;
40987  ma_uint64 dataCapInFrames;
40988  void* pPCMFramesOut;
40989 
40990  MA_ASSERT(pDecoder != NULL);
40991 
40992  totalFrameCount = 0;
40993  bpf = ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels);
40994 
40995  /* The frame count is unknown until we try reading. Thus, we just run in a loop. */
40996  dataCapInFrames = 0;
40997  pPCMFramesOut = NULL;
40998  for (;;) {
40999  ma_uint64 frameCountToTryReading;
41000  ma_uint64 framesJustRead;
41001 
41002  /* Make room if there's not enough. */
41003  if (totalFrameCount == dataCapInFrames) {
41004  void* pNewPCMFramesOut;
41005  ma_uint64 oldDataCapInFrames = dataCapInFrames;
41006  ma_uint64 newDataCapInFrames = dataCapInFrames*2;
41007  if (newDataCapInFrames == 0) {
41008  newDataCapInFrames = 4096;
41009  }
41010 
41011  if ((newDataCapInFrames * bpf) > MA_SIZE_MAX) {
41012  ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks);
41013  return MA_TOO_BIG;
41014  }
41015 
41016 
41017  pNewPCMFramesOut = (void*)ma__realloc_from_callbacks(pPCMFramesOut, (size_t)(newDataCapInFrames * bpf), (size_t)(oldDataCapInFrames * bpf), &pDecoder->allocationCallbacks);
41018  if (pNewPCMFramesOut == NULL) {
41019  ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks);
41020  return MA_OUT_OF_MEMORY;
41021  }
41022 
41023  dataCapInFrames = newDataCapInFrames;
41024  pPCMFramesOut = pNewPCMFramesOut;
41025  }
41026 
41027  frameCountToTryReading = dataCapInFrames - totalFrameCount;
41028  MA_ASSERT(frameCountToTryReading > 0);
41029 
41030  framesJustRead = ma_decoder_read_pcm_frames(pDecoder, (ma_uint8*)pPCMFramesOut + (totalFrameCount * bpf), frameCountToTryReading);
41031  totalFrameCount += framesJustRead;
41032 
41033  if (framesJustRead < frameCountToTryReading) {
41034  break;
41035  }
41036  }
41037 
41038 
41039  if (pConfigOut != NULL) {
41040  pConfigOut->format = pDecoder->outputFormat;
41041  pConfigOut->channels = pDecoder->outputChannels;
41042  pConfigOut->sampleRate = pDecoder->outputSampleRate;
41043  ma_channel_map_copy(pConfigOut->channelMap, pDecoder->outputChannelMap, pDecoder->outputChannels);
41044  }
41045 
41046  if (ppPCMFramesOut != NULL) {
41047  *ppPCMFramesOut = pPCMFramesOut;
41048  } else {
41049  ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks);
41050  }
41051 
41052  if (pFrameCountOut != NULL) {
41053  *pFrameCountOut = totalFrameCount;
41054  }
41055 
41056  ma_decoder_uninit(pDecoder);
41057  return MA_SUCCESS;
41058 }
41059 
41060 #ifndef MA_NO_STDIO
41061 ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
41062 {
41065  ma_result result;
41066 
41067  if (pFrameCountOut != NULL) {
41068  *pFrameCountOut = 0;
41069  }
41070  if (ppPCMFramesOut != NULL) {
41071  *ppPCMFramesOut = NULL;
41072  }
41073 
41074  if (pFilePath == NULL) {
41075  return MA_INVALID_ARGS;
41076  }
41077 
41079 
41080  result = ma_decoder_init_file(pFilePath, &config, &decoder);
41081  if (result != MA_SUCCESS) {
41082  return result;
41083  }
41084 
41085  return ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut);
41086 }
41087 #endif
41088 
41089 ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
41090 {
41093  ma_result result;
41094 
41095  if (pFrameCountOut != NULL) {
41096  *pFrameCountOut = 0;
41097  }
41098  if (ppPCMFramesOut != NULL) {
41099  *ppPCMFramesOut = NULL;
41100  }
41101 
41102  if (pData == NULL || dataSize == 0) {
41103  return MA_INVALID_ARGS;
41104  }
41105 
41107 
41108  result = ma_decoder_init_memory(pData, dataSize, &config, &decoder);
41109  if (result != MA_SUCCESS) {
41110  return result;
41111  }
41112 
41113  return ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut);
41114 }
41115 #endif /* MA_NO_DECODING */
41116 
41117 
41118 #ifndef MA_NO_ENCODING
41119 
41120 #if defined(MA_HAS_WAV)
41121 size_t ma_encoder__internal_on_write_wav(void* pUserData, const void* pData, size_t bytesToWrite)
41122 {
41123  ma_encoder* pEncoder = (ma_encoder*)pUserData;
41124  MA_ASSERT(pEncoder != NULL);
41125 
41126  return pEncoder->onWrite(pEncoder, pData, bytesToWrite);
41127 }
41128 
41129 drwav_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, drwav_seek_origin origin)
41130 {
41131  ma_encoder* pEncoder = (ma_encoder*)pUserData;
41132  MA_ASSERT(pEncoder != NULL);
41133 
41134  return pEncoder->onSeek(pEncoder, offset, (origin == drwav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current);
41135 }
41136 
41138 {
41139  drwav_data_format wavFormat;
41140  drwav_allocation_callbacks allocationCallbacks;
41141  drwav* pWav;
41142 
41143  MA_ASSERT(pEncoder != NULL);
41144 
41145  pWav = (drwav*)ma__malloc_from_callbacks(sizeof(*pWav), &pEncoder->config.allocationCallbacks);
41146  if (pWav == NULL) {
41147  return MA_OUT_OF_MEMORY;
41148  }
41149 
41150  wavFormat.container = drwav_container_riff;
41151  wavFormat.channels = pEncoder->config.channels;
41152  wavFormat.sampleRate = pEncoder->config.sampleRate;
41153  wavFormat.bitsPerSample = ma_get_bytes_per_sample(pEncoder->config.format) * 8;
41154  if (pEncoder->config.format == ma_format_f32) {
41155  wavFormat.format = DR_WAVE_FORMAT_IEEE_FLOAT;
41156  } else {
41157  wavFormat.format = DR_WAVE_FORMAT_PCM;
41158  }
41159 
41160  allocationCallbacks.pUserData = pEncoder->config.allocationCallbacks.pUserData;
41161  allocationCallbacks.onMalloc = pEncoder->config.allocationCallbacks.onMalloc;
41162  allocationCallbacks.onRealloc = pEncoder->config.allocationCallbacks.onRealloc;
41163  allocationCallbacks.onFree = pEncoder->config.allocationCallbacks.onFree;
41164 
41165  if (!drwav_init_write(pWav, &wavFormat, ma_encoder__internal_on_write_wav, ma_encoder__internal_on_seek_wav, pEncoder, &allocationCallbacks)) {
41166  return MA_ERROR;
41167  }
41168 
41169  pEncoder->pInternalEncoder = pWav;
41170 
41171  return MA_SUCCESS;
41172 }
41173 
41174 void ma_encoder__on_uninit_wav(ma_encoder* pEncoder)
41175 {
41176  drwav* pWav;
41177 
41178  MA_ASSERT(pEncoder != NULL);
41179 
41180  pWav = (drwav*)pEncoder->pInternalEncoder;
41181  MA_ASSERT(pWav != NULL);
41182 
41183  drwav_uninit(pWav);
41185 }
41186 
41187 ma_uint64 ma_encoder__on_write_pcm_frames_wav(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount)
41188 {
41189  drwav* pWav;
41190 
41191  MA_ASSERT(pEncoder != NULL);
41192 
41193  pWav = (drwav*)pEncoder->pInternalEncoder;
41194  MA_ASSERT(pWav != NULL);
41195 
41196  return drwav_write_pcm_frames(pWav, frameCount, pFramesIn);
41197 }
41198 #endif
41199 
41200 ma_encoder_config ma_encoder_config_init(ma_resource_format resourceFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
41201 {
41203 
41205  config.resourceFormat = resourceFormat;
41206  config.format = format;
41207  config.channels = channels;
41208  config.sampleRate = sampleRate;
41209 
41210  return config;
41211 }
41212 
41213 ma_result ma_encoder_preinit(const ma_encoder_config* pConfig, ma_encoder* pEncoder)
41214 {
41215  ma_result result;
41216 
41217  if (pEncoder == NULL) {
41218  return MA_INVALID_ARGS;
41219  }
41220 
41221  MA_ZERO_OBJECT(pEncoder);
41222 
41223  if (pConfig == NULL) {
41224  return MA_INVALID_ARGS;
41225  }
41226 
41227  if (pConfig->format == ma_format_unknown || pConfig->channels == 0 || pConfig->sampleRate == 0) {
41228  return MA_INVALID_ARGS;
41229  }
41230 
41231  pEncoder->config = *pConfig;
41232 
41234  if (result != MA_SUCCESS) {
41235  return result;
41236  }
41237 
41238  return MA_SUCCESS;
41239 }
41240 
41242 {
41243  ma_result result = MA_SUCCESS;
41244 
41245  /* This assumes ma_encoder_preinit() has been called prior. */
41246  MA_ASSERT(pEncoder != NULL);
41247 
41248  if (onWrite == NULL || onSeek == NULL) {
41249  return MA_INVALID_ARGS;
41250  }
41251 
41252  pEncoder->onWrite = onWrite;
41253  pEncoder->onSeek = onSeek;
41254  pEncoder->pUserData = pUserData;
41255 
41256  switch (pEncoder->config.resourceFormat)
41257  {
41259  {
41260  #if defined(MA_HAS_WAV)
41261  pEncoder->onInit = ma_encoder__on_init_wav;
41262  pEncoder->onUninit = ma_encoder__on_uninit_wav;
41264  #else
41265  result = MA_NO_BACKEND;
41266  #endif
41267  } break;
41268 
41269  default:
41270  {
41271  result = MA_INVALID_ARGS;
41272  } break;
41273  }
41274 
41275  /* Getting here means we should have our backend callbacks set up. */
41276  if (result == MA_SUCCESS) {
41277  result = pEncoder->onInit(pEncoder);
41278  if (result != MA_SUCCESS) {
41279  return result;
41280  }
41281  }
41282 
41283  return MA_SUCCESS;
41284 }
41285 
41286 #ifndef MA_NO_STDIO
41287 size_t ma_encoder__on_write_stdio(ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite)
41288 {
41289  return fwrite(pBufferIn, 1, bytesToWrite, (FILE*)pEncoder->pFile);
41290 }
41291 
41292 ma_bool32 ma_encoder__on_seek_stdio(ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin)
41293 {
41294  return fseek((FILE*)pEncoder->pFile, byteOffset, (origin == ma_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
41295 }
41296 
41297 ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder)
41298 {
41299  ma_result result;
41300  FILE* pFile;
41301 
41302  result = ma_encoder_preinit(pConfig, pEncoder);
41303  if (result != MA_SUCCESS) {
41304  return result;
41305  }
41306 
41307  /* Now open the file. If this fails we don't need to uninitialize the encoder. */
41308  result = ma_fopen(&pFile, pFilePath, "wb");
41309  if (pFile == NULL) {
41310  return result;
41311  }
41312 
41313  pEncoder->pFile = pFile;
41314 
41316 }
41317 
41318 ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder)
41319 {
41320  ma_result result;
41321  FILE* pFile;
41322 
41323  result = ma_encoder_preinit(pConfig, pEncoder);
41324  if (result != MA_SUCCESS) {
41325  return result;
41326  }
41327 
41328  /* Now open the file. If this fails we don't need to uninitialize the encoder. */
41329  result = ma_wfopen(&pFile, pFilePath, L"wb", &pEncoder->config.allocationCallbacks);
41330  if (pFile != NULL) {
41331  return result;
41332  }
41333 
41334  pEncoder->pFile = pFile;
41335 
41337 }
41338 #endif
41339 
41340 ma_result ma_encoder_init(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void* pUserData, const ma_encoder_config* pConfig, ma_encoder* pEncoder)
41341 {
41342  ma_result result;
41343 
41344  result = ma_encoder_preinit(pConfig, pEncoder);
41345  if (result != MA_SUCCESS) {
41346  return result;
41347  }
41348 
41349  return ma_encoder_init__internal(onWrite, onSeek, pUserData, pEncoder);
41350 }
41351 
41352 
41353 void ma_encoder_uninit(ma_encoder* pEncoder)
41354 {
41355  if (pEncoder == NULL) {
41356  return;
41357  }
41358 
41359  if (pEncoder->onUninit) {
41360  pEncoder->onUninit(pEncoder);
41361  }
41362 
41363 #ifndef MA_NO_STDIO
41364  /* If we have a file handle, close it. */
41365  if (pEncoder->onWrite == ma_encoder__on_write_stdio) {
41366  fclose((FILE*)pEncoder->pFile);
41367  }
41368 #endif
41369 }
41370 
41371 
41372 ma_uint64 ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount)
41373 {
41374  if (pEncoder == NULL || pFramesIn == NULL) {
41375  return 0;
41376  }
41377 
41378  return pEncoder->onWritePCMFrames(pEncoder, pFramesIn, frameCount);
41379 }
41380 #endif /* MA_NO_ENCODING */
41381 
41382 
41383 
41384 /**************************************************************************************************************************************************************
41385 
41386 Generation
41387 
41388 **************************************************************************************************************************************************************/
41389 ma_waveform_config ma_waveform_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_waveform_type type, double amplitude, double frequency)
41390 {
41392 
41394  config.format = format;
41395  config.channels = channels;
41396  config.sampleRate = sampleRate;
41397  config.type = type;
41398  config.amplitude = amplitude;
41399  config.frequency = frequency;
41400 
41401  return config;
41402 }
41403 
41404 ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform)
41405 {
41406  if (pWaveform == NULL) {
41407  return MA_INVALID_ARGS;
41408  }
41409 
41410  MA_ZERO_OBJECT(pWaveform);
41411  pWaveform->config = *pConfig;
41412  pWaveform->advance = 1.0 / pWaveform->config.sampleRate;
41413  pWaveform->time = 0;
41414 
41415  return MA_SUCCESS;
41416 }
41417 
41418 ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude)
41419 {
41420  if (pWaveform == NULL) {
41421  return MA_INVALID_ARGS;
41422  }
41423 
41424  pWaveform->config.amplitude = amplitude;
41425  return MA_SUCCESS;
41426 }
41427 
41428 ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency)
41429 {
41430  if (pWaveform == NULL) {
41431  return MA_INVALID_ARGS;
41432  }
41433 
41434  pWaveform->config.frequency = frequency;
41435  return MA_SUCCESS;
41436 }
41437 
41439 {
41440  if (pWaveform == NULL) {
41441  return MA_INVALID_ARGS;
41442  }
41443 
41444  pWaveform->advance = 1.0 / sampleRate;
41445  return MA_SUCCESS;
41446 }
41447 
41448 static float ma_waveform_sine_f32(double time, double frequency, double amplitude)
41449 {
41450  return (float)(ma_sin(MA_TAU_D * time * frequency) * amplitude);
41451 }
41452 
41453 static ma_int16 ma_waveform_sine_s16(double time, double frequency, double amplitude)
41454 {
41455  return ma_pcm_sample_f32_to_s16(ma_waveform_sine_f32(time, frequency, amplitude));
41456 }
41457 
41458 static float ma_waveform_square_f32(double time, double frequency, double amplitude)
41459 {
41460  double t = time * frequency;
41461  double f = t - (ma_uint64)t;
41462  double r;
41463 
41464  if (f < 0.5) {
41465  r = amplitude;
41466  } else {
41467  r = -amplitude;
41468  }
41469 
41470  return (float)r;
41471 }
41472 
41473 static ma_int16 ma_waveform_square_s16(double time, double frequency, double amplitude)
41474 {
41475  return ma_pcm_sample_f32_to_s16(ma_waveform_square_f32(time, frequency, amplitude));
41476 }
41477 
41478 static float ma_waveform_triangle_f32(double time, double frequency, double amplitude)
41479 {
41480  double t = time * frequency;
41481  double f = t - (ma_uint64)t;
41482  double r;
41483 
41484  r = 2 * ma_abs(2 * (f - 0.5)) - 1;
41485 
41486  return (float)(r * amplitude);
41487 }
41488 
41489 static ma_int16 ma_waveform_triangle_s16(double time, double frequency, double amplitude)
41490 {
41491  return ma_pcm_sample_f32_to_s16(ma_waveform_triangle_f32(time, frequency, amplitude));
41492 }
41493 
41494 static float ma_waveform_sawtooth_f32(double time, double frequency, double amplitude)
41495 {
41496  double t = time * frequency;
41497  double f = t - (ma_uint64)t;
41498  double r;
41499 
41500  r = 2 * (f - 0.5);
41501 
41502  return (float)(r * amplitude);
41503 }
41504 
41505 static ma_int16 ma_waveform_sawtooth_s16(double time, double frequency, double amplitude)
41506 {
41507  return ma_pcm_sample_f32_to_s16(ma_waveform_sawtooth_f32(time, frequency, amplitude));
41508 }
41509 
41510 static void ma_waveform_read_pcm_frames__sine(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
41511 {
41512  ma_uint64 iFrame;
41513  ma_uint64 iChannel;
41514  ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
41515  ma_uint32 bpf = bps * pWaveform->config.channels;
41516 
41517  MA_ASSERT(pWaveform != NULL);
41518  MA_ASSERT(pFramesOut != NULL);
41519 
41520  if (pWaveform->config.format == ma_format_f32) {
41521  float* pFramesOutF32 = (float*)pFramesOut;
41522  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41523  float s = ma_waveform_sine_f32(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41524  pWaveform->time += pWaveform->advance;
41525 
41526  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41527  pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
41528  }
41529  }
41530  } else if (pWaveform->config.format == ma_format_s16) {
41531  ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
41532  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41533  ma_int16 s = ma_waveform_sine_s16(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41534  pWaveform->time += pWaveform->advance;
41535 
41536  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41537  pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
41538  }
41539  }
41540  } else {
41541  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41542  float s = ma_waveform_sine_f32(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41543  pWaveform->time += pWaveform->advance;
41544 
41545  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41546  ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
41547  }
41548  }
41549  }
41550 }
41551 
41552 static void ma_waveform_read_pcm_frames__square(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
41553 {
41554  ma_uint64 iFrame;
41555  ma_uint64 iChannel;
41556  ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
41557  ma_uint32 bpf = bps * pWaveform->config.channels;
41558 
41559  MA_ASSERT(pWaveform != NULL);
41560  MA_ASSERT(pFramesOut != NULL);
41561 
41562  if (pWaveform->config.format == ma_format_f32) {
41563  float* pFramesOutF32 = (float*)pFramesOut;
41564  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41565  float s = ma_waveform_square_f32(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41566  pWaveform->time += pWaveform->advance;
41567 
41568  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41569  pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
41570  }
41571  }
41572  } else if (pWaveform->config.format == ma_format_s16) {
41573  ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
41574  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41575  ma_int16 s = ma_waveform_square_s16(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41576  pWaveform->time += pWaveform->advance;
41577 
41578  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41579  pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
41580  }
41581  }
41582  } else {
41583  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41584  float s = ma_waveform_square_f32(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41585  pWaveform->time += pWaveform->advance;
41586 
41587  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41588  ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
41589  }
41590  }
41591  }
41592 }
41593 
41594 static void ma_waveform_read_pcm_frames__triangle(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
41595 {
41596  ma_uint64 iFrame;
41597  ma_uint64 iChannel;
41598  ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
41599  ma_uint32 bpf = bps * pWaveform->config.channels;
41600 
41601  MA_ASSERT(pWaveform != NULL);
41602  MA_ASSERT(pFramesOut != NULL);
41603 
41604  if (pWaveform->config.format == ma_format_f32) {
41605  float* pFramesOutF32 = (float*)pFramesOut;
41606  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41607  float s = ma_waveform_triangle_f32(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41608  pWaveform->time += pWaveform->advance;
41609 
41610  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41611  pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
41612  }
41613  }
41614  } else if (pWaveform->config.format == ma_format_s16) {
41615  ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
41616  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41617  ma_int16 s = ma_waveform_triangle_s16(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41618  pWaveform->time += pWaveform->advance;
41619 
41620  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41621  pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
41622  }
41623  }
41624  } else {
41625  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41626  float s = ma_waveform_triangle_f32(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41627  pWaveform->time += pWaveform->advance;
41628 
41629  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41630  ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
41631  }
41632  }
41633  }
41634 }
41635 
41636 static void ma_waveform_read_pcm_frames__sawtooth(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
41637 {
41638  ma_uint64 iFrame;
41639  ma_uint64 iChannel;
41640  ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
41641  ma_uint32 bpf = bps * pWaveform->config.channels;
41642 
41643  MA_ASSERT(pWaveform != NULL);
41644  MA_ASSERT(pFramesOut != NULL);
41645 
41646  if (pWaveform->config.format == ma_format_f32) {
41647  float* pFramesOutF32 = (float*)pFramesOut;
41648  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41649  float s = ma_waveform_sawtooth_f32(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41650  pWaveform->time += pWaveform->advance;
41651 
41652  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41653  pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
41654  }
41655  }
41656  } else if (pWaveform->config.format == ma_format_s16) {
41657  ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
41658  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41659  ma_int16 s = ma_waveform_sawtooth_s16(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41660  pWaveform->time += pWaveform->advance;
41661 
41662  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41663  pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
41664  }
41665  }
41666  } else {
41667  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41668  float s = ma_waveform_sawtooth_f32(pWaveform->time, pWaveform->config.frequency, pWaveform->config.amplitude);
41669  pWaveform->time += pWaveform->advance;
41670 
41671  for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
41672  ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
41673  }
41674  }
41675  }
41676 }
41677 
41678 ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
41679 {
41680  if (pWaveform == NULL) {
41681  return 0;
41682  }
41683 
41684  if (pFramesOut != NULL) {
41685  switch (pWaveform->config.type)
41686  {
41687  case ma_waveform_type_sine:
41688  {
41689  ma_waveform_read_pcm_frames__sine(pWaveform, pFramesOut, frameCount);
41690  } break;
41691 
41693  {
41694  ma_waveform_read_pcm_frames__square(pWaveform, pFramesOut, frameCount);
41695  } break;
41696 
41698  {
41699  ma_waveform_read_pcm_frames__triangle(pWaveform, pFramesOut, frameCount);
41700  } break;
41701 
41703  {
41704  ma_waveform_read_pcm_frames__sawtooth(pWaveform, pFramesOut, frameCount);
41705  } break;
41706 
41707  default: return 0;
41708  }
41709  } else {
41710  pWaveform->time += pWaveform->advance * (ma_int64)frameCount; /* Cast to int64 required for VC6. Won't affect anything in practice. */
41711  }
41712 
41713  return frameCount;
41714 }
41715 
41716 
41717 ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels, ma_noise_type type, ma_int32 seed, double amplitude)
41718 {
41721 
41722  config.format = format;
41723  config.channels = channels;
41724  config.type = type;
41725  config.seed = seed;
41726  config.amplitude = amplitude;
41727 
41728  if (config.seed == 0) {
41729  config.seed = MA_DEFAULT_LCG_SEED;
41730  }
41731 
41732  return config;
41733 }
41734 
41735 ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise)
41736 {
41737  if (pNoise == NULL) {
41738  return MA_INVALID_ARGS;
41739  }
41740 
41741  MA_ZERO_OBJECT(pNoise);
41742 
41743  if (pConfig == NULL) {
41744  return MA_INVALID_ARGS;
41745  }
41746 
41747  pNoise->config = *pConfig;
41748  ma_lcg_seed(&pNoise->lcg, pConfig->seed);
41749 
41750  if (pNoise->config.type == ma_noise_type_pink) {
41751  ma_uint32 iChannel;
41752  for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) {
41753  pNoise->state.pink.accumulation[iChannel] = 0;
41754  pNoise->state.pink.counter[iChannel] = 1;
41755  }
41756  }
41757 
41758  if (pNoise->config.type == ma_noise_type_brownian) {
41759  ma_uint32 iChannel;
41760  for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) {
41761  pNoise->state.brownian.accumulation[iChannel] = 0;
41762  }
41763  }
41764 
41765  return MA_SUCCESS;
41766 }
41767 
41768 static MA_INLINE float ma_noise_f32_white(ma_noise* pNoise)
41769 {
41770  return (float)(ma_lcg_rand_f64(&pNoise->lcg) * pNoise->config.amplitude);
41771 }
41772 
41774 {
41776 }
41777 
41778 static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
41779 {
41780  ma_uint64 iFrame;
41781  ma_uint32 iChannel;
41782 
41783  if (pNoise->config.format == ma_format_f32) {
41784  float* pFramesOutF32 = (float*)pFramesOut;
41785  if (pNoise->config.duplicateChannels) {
41786  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41787  float s = ma_noise_f32_white(pNoise);
41788  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41789  pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s;
41790  }
41791  }
41792  } else {
41793  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41794  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41795  pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_white(pNoise);
41796  }
41797  }
41798  }
41799  } else if (pNoise->config.format == ma_format_s16) {
41800  ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
41801  if (pNoise->config.duplicateChannels) {
41802  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41803  ma_int16 s = ma_noise_s16_white(pNoise);
41804  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41805  pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s;
41806  }
41807  }
41808  } else {
41809  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41810  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41811  pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = ma_noise_s16_white(pNoise);
41812  }
41813  }
41814  }
41815  } else {
41817  ma_uint32 bpf = bps * pNoise->config.channels;
41818 
41819  if (pNoise->config.duplicateChannels) {
41820  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41821  float s = ma_noise_f32_white(pNoise);
41822  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41823  ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
41824  }
41825  }
41826  } else {
41827  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41828  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41829  float s = ma_noise_f32_white(pNoise);
41830  ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
41831  }
41832  }
41833  }
41834  }
41835 
41836  return frameCount;
41837 }
41838 
41839 
41840 static MA_INLINE unsigned int ma_tzcnt32(unsigned int x)
41841 {
41842  unsigned int n;
41843 
41844  /* Special case for odd numbers since they should happen about half the time. */
41845  if (x & 0x1) {
41846  return 0;
41847  }
41848 
41849  if (x == 0) {
41850  return sizeof(x) << 3;
41851  }
41852 
41853  n = 1;
41854  if ((x & 0x0000FFFF) == 0) { x >>= 16; n += 16; }
41855  if ((x & 0x000000FF) == 0) { x >>= 8; n += 8; }
41856  if ((x & 0x0000000F) == 0) { x >>= 4; n += 4; }
41857  if ((x & 0x00000003) == 0) { x >>= 2; n += 2; }
41858  n -= x & 0x00000001;
41859 
41860  return n;
41861 }
41862 
41863 /*
41864 Pink noise generation based on Tonic (public domain) with modifications. https://github.com/TonicAudio/Tonic/blob/master/src/Tonic/Noise.h
41865 
41866 This is basically _the_ reference for pink noise from what I've found: http://www.firstpr.com.au/dsp/pink-noise/
41867 */
41868 static MA_INLINE float ma_noise_f32_pink(ma_noise* pNoise, ma_uint32 iChannel)
41869 {
41870  double result;
41871  double binPrev;
41872  double binNext;
41873  unsigned int ibin;
41874 
41875  ibin = ma_tzcnt32(pNoise->state.pink.counter[iChannel]) & (ma_countof(pNoise->state.pink.bin[0]) - 1);
41876 
41877  binPrev = pNoise->state.pink.bin[iChannel][ibin];
41878  binNext = ma_lcg_rand_f64(&pNoise->lcg);
41879  pNoise->state.pink.bin[iChannel][ibin] = binNext;
41880 
41881  pNoise->state.pink.accumulation[iChannel] += (binNext - binPrev);
41882  pNoise->state.pink.counter[iChannel] += 1;
41883 
41884  result = (ma_lcg_rand_f64(&pNoise->lcg) + pNoise->state.pink.accumulation[iChannel]);
41885  result /= 10;
41886 
41887  return (float)(result * pNoise->config.amplitude);
41888 }
41889 
41890 static MA_INLINE ma_int16 ma_noise_s16_pink(ma_noise* pNoise, ma_uint32 iChannel)
41891 {
41892  return ma_pcm_sample_f32_to_s16(ma_noise_f32_pink(pNoise, iChannel));
41893 }
41894 
41895 static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
41896 {
41897  ma_uint64 iFrame;
41898  ma_uint32 iChannel;
41899 
41900  if (pNoise->config.format == ma_format_f32) {
41901  float* pFramesOutF32 = (float*)pFramesOut;
41902  if (pNoise->config.duplicateChannels) {
41903  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41904  float s = ma_noise_f32_pink(pNoise, 0);
41905  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41906  pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s;
41907  }
41908  }
41909  } else {
41910  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41911  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41912  pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_pink(pNoise, iChannel);
41913  }
41914  }
41915  }
41916  } else if (pNoise->config.format == ma_format_s16) {
41917  ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
41918  if (pNoise->config.duplicateChannels) {
41919  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41920  ma_int16 s = ma_noise_s16_pink(pNoise, 0);
41921  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41922  pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s;
41923  }
41924  }
41925  } else {
41926  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41927  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41928  pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = ma_noise_s16_pink(pNoise, iChannel);
41929  }
41930  }
41931  }
41932  } else {
41934  ma_uint32 bpf = bps * pNoise->config.channels;
41935 
41936  if (pNoise->config.duplicateChannels) {
41937  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41938  float s = ma_noise_f32_pink(pNoise, 0);
41939  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41940  ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
41941  }
41942  }
41943  } else {
41944  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41945  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41946  float s = ma_noise_f32_pink(pNoise, iChannel);
41947  ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
41948  }
41949  }
41950  }
41951  }
41952 
41953  return frameCount;
41954 }
41955 
41956 
41957 static MA_INLINE float ma_noise_f32_brownian(ma_noise* pNoise, ma_uint32 iChannel)
41958 {
41959  double result;
41960 
41961  result = (ma_lcg_rand_f64(&pNoise->lcg) + pNoise->state.brownian.accumulation[iChannel]);
41962  result /= 1.005; /* Don't escape the -1..1 range on average. */
41963 
41964  pNoise->state.brownian.accumulation[iChannel] = result;
41965  result /= 20;
41966 
41967  return (float)(result * pNoise->config.amplitude);
41968 }
41969 
41970 static MA_INLINE ma_int16 ma_noise_s16_brownian(ma_noise* pNoise, ma_uint32 iChannel)
41971 {
41972  return ma_pcm_sample_f32_to_s16(ma_noise_f32_brownian(pNoise, iChannel));
41973 }
41974 
41975 static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
41976 {
41977  ma_uint64 iFrame;
41978  ma_uint32 iChannel;
41979 
41980  if (pNoise->config.format == ma_format_f32) {
41981  float* pFramesOutF32 = (float*)pFramesOut;
41982  if (pNoise->config.duplicateChannels) {
41983  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41984  float s = ma_noise_f32_brownian(pNoise, 0);
41985  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41986  pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = s;
41987  }
41988  }
41989  } else {
41990  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41991  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
41992  pFramesOutF32[iFrame*pNoise->config.channels + iChannel] = ma_noise_f32_brownian(pNoise, iChannel);
41993  }
41994  }
41995  }
41996  } else if (pNoise->config.format == ma_format_s16) {
41997  ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
41998  if (pNoise->config.duplicateChannels) {
41999  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
42000  ma_int16 s = ma_noise_s16_brownian(pNoise, 0);
42001  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
42002  pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = s;
42003  }
42004  }
42005  } else {
42006  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
42007  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
42008  pFramesOutS16[iFrame*pNoise->config.channels + iChannel] = ma_noise_s16_brownian(pNoise, iChannel);
42009  }
42010  }
42011  }
42012  } else {
42014  ma_uint32 bpf = bps * pNoise->config.channels;
42015 
42016  if (pNoise->config.duplicateChannels) {
42017  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
42018  float s = ma_noise_f32_brownian(pNoise, 0);
42019  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
42020  ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
42021  }
42022  }
42023  } else {
42024  for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
42025  for (iChannel = 0; iChannel < pNoise->config.channels; iChannel += 1) {
42026  float s = ma_noise_f32_brownian(pNoise, iChannel);
42027  ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
42028  }
42029  }
42030  }
42031  }
42032 
42033  return frameCount;
42034 }
42035 
42036 ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
42037 {
42038  if (pNoise == NULL) {
42039  return 0;
42040  }
42041 
42042  if (pNoise->config.type == ma_noise_type_white) {
42043  return ma_noise_read_pcm_frames__white(pNoise, pFramesOut, frameCount);
42044  }
42045 
42046  if (pNoise->config.type == ma_noise_type_pink) {
42047  return ma_noise_read_pcm_frames__pink(pNoise, pFramesOut, frameCount);
42048  }
42049 
42050  if (pNoise->config.type == ma_noise_type_brownian) {
42051  return ma_noise_read_pcm_frames__brownian(pNoise, pFramesOut, frameCount);
42052  }
42053 
42054  /* Should never get here. */
42056  return 0;
42057 }
42058 
42059 /* End globally disabled warnings. */
42060 #if defined(_MSC_VER)
42061  #pragma warning(pop)
42062 #endif
42063 
42064 #endif /* MINIAUDIO_IMPLEMENTATION */
42065 
42066 /*
42067 MAJOR CHANGES IN VERSION 0.9
42068 ============================
42069 Version 0.9 includes major API changes, centered mostly around full-duplex and the rebrand to "miniaudio". Before I go into
42070 detail about the major changes I would like to apologize. I know it's annoying dealing with breaking API changes, but I think
42071 it's best to get these changes out of the way now while the library is still relatively young and unknown.
42072 
42073 There's been a lot of refactoring with this release so there's a good chance a few bugs have been introduced. I apologize in
42074 advance for this. You may want to hold off on upgrading for the short term if you're worried. If mini_al v0.8.14 works for
42075 you, and you don't need full-duplex support, you can avoid upgrading (though you won't be getting future bug fixes).
42076 
42077 
42078 Rebranding to "miniaudio"
42079 -------------------------
42080 The decision was made to rename mini_al to miniaudio. Don't worry, it's the same project. The reason for this is simple:
42081 
42082 1) Having the word "audio" in the title makes it immediately clear that the library is related to audio; and
42083 2) I don't like the look of the underscore.
42084 
42085 This rebrand has necessitated a change in namespace from "mal" to "ma". I know this is annoying, and I apologize, but it's
42086 better to get this out of the road now rather than later. Also, since there are necessary API changes for full-duplex support
42087 I think it's better to just get the namespace change over and done with at the same time as the full-duplex changes. I'm hoping
42088 this will be the last of the major API changes. Fingers crossed!
42089 
42090 The implementation define is now "#define MINIAUDIO_IMPLEMENTATION". You can also use "#define MA_IMPLEMENTATION" if that's
42091 your preference.
42092 
42093 
42094 Full-Duplex Support
42095 -------------------
42096 The major feature added to version 0.9 is full-duplex. This has necessitated a few API changes.
42097 
42098 1) The data callback has now changed. Previously there was one type of callback for playback and another for capture. I wanted
42099  to avoid a third callback just for full-duplex so the decision was made to break this API and unify the callbacks. Now,
42100  there is just one callback which is the same for all three modes (playback, capture, duplex). The new callback looks like
42101  the following:
42102 
42103  void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
42104 
42105  This callback allows you to move data straight out of the input buffer and into the output buffer in full-duplex mode. In
42106  playback-only mode, pInput will be null. Likewise, pOutput will be null in capture-only mode. The sample count is no longer
42107  returned from the callback since it's not necessary for miniaudio anymore.
42108 
42109 2) The device config needed to change in order to support full-duplex. Full-duplex requires the ability to allow the client
42110  to choose a different PCM format for the playback and capture sides. The old ma_device_config object simply did not allow
42111  this and needed to change. With these changes you now specify the device ID, format, channels, channel map and share mode
42112  on a per-playback and per-capture basis (see example below). The sample rate must be the same for playback and capture.
42113 
42114  Since the device config API has changed I have also decided to take the opportunity to simplify device initialization. Now,
42115  the device ID, device type and callback user data are set in the config. ma_device_init() is now simplified down to taking
42116  just the context, device config and a pointer to the device object being initialized. The rationale for this change is that
42117  it just makes more sense to me that these are set as part of the config like everything else.
42118 
42119  Example device initialization:
42120 
42121  ma_device_config config = ma_device_config_init(ma_device_type_duplex); // Or ma_device_type_playback or ma_device_type_capture.
42122  config.playback.pDeviceID = &myPlaybackDeviceID; // Or NULL for the default playback device.
42123  config.playback.format = ma_format_f32;
42124  config.playback.channels = 2;
42125  config.capture.pDeviceID = &myCaptureDeviceID; // Or NULL for the default capture device.
42126  config.capture.format = ma_format_s16;
42127  config.capture.channels = 1;
42128  config.sampleRate = 44100;
42129  config.dataCallback = data_callback;
42130  config.pUserData = &myUserData;
42131 
42132  result = ma_device_init(&myContext, &config, &device);
42133  if (result != MA_SUCCESS) {
42134  ... handle error ...
42135  }
42136 
42137  Note that the "onDataCallback" member of ma_device_config has been renamed to "dataCallback". Also, "onStopCallback" has
42138  been renamed to "stopCallback".
42139 
42140 This is the first pass for full-duplex and there is a known bug. You will hear crackling on the following backends when sample
42141 rate conversion is required for the playback device:
42142  - Core Audio
42143  - JACK
42144  - AAudio
42145  - OpenSL
42146  - WebAudio
42147 
42148 In addition to the above, not all platforms have been absolutely thoroughly tested simply because I lack the hardware for such
42149 thorough testing. If you experience a bug, an issue report on GitHub or an email would be greatly appreciated (and a sample
42150 program that reproduces the issue if possible).
42151 
42152 
42153 Other API Changes
42154 -----------------
42155 In addition to the above, the following API changes have been made:
42156 
42157 - The log callback is no longer passed to ma_context_config_init(). Instead you need to set it manually after initialization.
42158 - The onLogCallback member of ma_context_config has been renamed to "logCallback".
42159 - The log callback now takes a logLevel parameter. The new callback looks like: void log_callback(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
42160  - You can use ma_log_level_to_string() to convert the logLevel to human readable text if you want to log it.
42161 - Some APIs have been renamed:
42162  - mal_decoder_read() -> ma_decoder_read_pcm_frames()
42163  - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame()
42164  - mal_sine_wave_read() -> ma_sine_wave_read_f32()
42165  - mal_sine_wave_read_ex() -> ma_sine_wave_read_f32_ex()
42166 - Some APIs have been removed:
42167  - mal_device_get_buffer_size_in_bytes()
42168  - mal_device_set_recv_callback()
42169  - mal_device_set_send_callback()
42170  - mal_src_set_input_sample_rate()
42171  - mal_src_set_output_sample_rate()
42172 - Error codes have been rearranged. If you're a binding maintainer you will need to update.
42173 - The ma_backend enums have been rearranged to priority order. The rationale for this is to simplify automatic backend selection
42174  and to make it easier to see the priority. If you're a binding maintainer you will need to update.
42175 - ma_dsp has been renamed to ma_pcm_converter. The rationale for this change is that I'm expecting "ma_dsp" to conflict with
42176  some future planned high-level APIs.
42177 - For functions that take a pointer/count combo, such as ma_decoder_read_pcm_frames(), the parameter order has changed so that
42178  the pointer comes before the count. The rationale for this is to keep it consistent with things like memcpy().
42179 
42180 
42181 Miscellaneous Changes
42182 ---------------------
42183 The following miscellaneous changes have also been made.
42184 
42185 - The AAudio backend has been added for Android 8 and above. This is Android's new "High-Performance Audio" API. (For the
42186  record, this is one of the nicest audio APIs out there, just behind the BSD audio APIs).
42187 - The WebAudio backend has been added. This is based on ScriptProcessorNode. This removes the need for SDL.
42188 - The SDL and OpenAL backends have been removed. These were originally implemented to add support for platforms for which miniaudio
42189  was not explicitly supported. These are no longer needed and have therefore been removed.
42190 - Device initialization now fails if the requested share mode is not supported. If you ask for exclusive mode, you either get an
42191  exclusive mode device, or an error. The rationale for this change is to give the client more control over how to handle cases
42192  when the desired shared mode is unavailable.
42193 - A lock-free ring buffer API has been added. There are two varients of this. "ma_rb" operates on bytes, whereas "ma_pcm_rb"
42194  operates on PCM frames.
42195 - The library is now licensed as a choice of Public Domain (Unlicense) _or_ MIT-0 (No Attribution) which is the same as MIT, but
42196  removes the attribution requirement. The rationale for this is to support countries that don't recognize public domain.
42197 */
42198 
42199 /*
42200 REVISION HISTORY
42201 ================
42202 v0.10.0 - 2020-03-07
42203  - API CHANGE: Refactor data conversion APIs
42204  - ma_format_converter has been removed. Use ma_convert_pcm_frames_format() instead.
42205  - ma_channel_router has been replaced with ma_channel_converter.
42206  - ma_src has been replaced with ma_resampler
42207  - ma_pcm_converter has been replaced with ma_data_converter
42208  - API CHANGE: Add support for custom memory allocation callbacks. The following APIs have been updated to take an extra parameter for the allocation
42209  callbacks:
42210  - ma_malloc()
42211  - ma_realloc()
42212  - ma_free()
42213  - ma_aligned_malloc()
42214  - ma_aligned_free()
42215  - ma_rb_init() / ma_rb_init_ex()
42216  - ma_pcm_rb_init() / ma_pcm_rb_init_ex()
42217  - API CHANGE: Simplify latency specification in device configurations. The bufferSizeInFrames and bufferSizeInMilliseconds parameters have been replaced with
42218  periodSizeInFrames and periodSizeInMilliseconds respectively. The previous variables defined the size of the entire buffer, whereas the new ones define the
42219  size of a period. The following APIs have been removed since they are no longer relevant:
42220  - ma_get_default_buffer_size_in_milliseconds()
42221  - ma_get_default_buffer_size_in_frames()
42222  - API CHANGE: ma_device_set_stop_callback() has been removed. If you require a stop callback, you must now set it via the device config just like the data
42223  callback.
42224  - API CHANGE: The ma_sine_wave API has been replaced with ma_waveform. The following APIs have been removed:
42225  - ma_sine_wave_init()
42226  - ma_sine_wave_read_f32()
42227  - ma_sine_wave_read_f32_ex()
42228  - API CHANGE: ma_convert_frames() has been updated to take an extra parameter which is the size of the output buffer in PCM frames. Parameters have also been
42229  reordered.
42230  - API CHANGE: ma_convert_frames_ex() has been changed to take a pointer to a ma_data_converter_config object to specify the input and output formats to
42231  convert between.
42232  - API CHANGE: ma_calculate_frame_count_after_src() has been renamed to ma_calculate_frame_count_after_resampling().
42233  - Add support for the following filters:
42234  - Biquad (ma_biquad)
42235  - First order low-pass (ma_lpf1)
42236  - Second order low-pass (ma_lpf2)
42237  - Low-pass with configurable order (ma_lpf)
42238  - First order high-pass (ma_hpf1)
42239  - Second order high-pass (ma_hpf2)
42240  - High-pass with configurable order (ma_hpf)
42241  - Second order band-pass (ma_bpf2)
42242  - Band-pass with configurable order (ma_bpf)
42243  - Second order peaking EQ (ma_peak2)
42244  - Second order notching (ma_notch2)
42245  - Second order low shelf (ma_loshelf2)
42246  - Second order high shelf (ma_hishelf2)
42247  - Add waveform generation API (ma_waveform) with support for the following:
42248  - Sine
42249  - Square
42250  - Triangle
42251  - Sawtooth
42252  - Add noise generation API (ma_noise) with support for the following:
42253  - White
42254  - Pink
42255  - Brownian
42256  - Add encoding API (ma_encoder). This only supports outputting to WAV files via dr_wav.
42257  - Add ma_result_description() which is used to retrieve a human readable description of a given result code.
42258  - Result codes have been changed. Binding maintainers will need to update their result code constants.
42259  - More meaningful result codes are now returned when a file fails to open.
42260  - Internal functions have all been made static where possible.
42261  - Fix potential crash when ma_device object's are not aligned to MA_SIMD_ALIGNMENT.
42262  - Fix a bug in ma_decoder_get_length_in_pcm_frames() where it was returning the length based on the internal sample rate rather than the output sample rate.
42263  - Fix bugs in some backends where the device is not drained properly in ma_device_stop().
42264  - Improvements to documentation.
42265 
42266 v0.9.10 - 2020-01-15
42267  - Fix compilation errors due to #if/#endif mismatches.
42268  - WASAPI: Fix a bug where automatic stream routing is being performed for devices that are initialized with an explicit device ID.
42269  - iOS: Fix a crash on device uninitialization.
42270 
42271 v0.9.9 - 2020-01-09
42272  - Fix compilation errors with MinGW.
42273  - Fix compilation errors when compiling on Apple platforms.
42274  - WASAPI: Add support for disabling hardware offloading.
42275  - WASAPI: Add support for disabling automatic stream routing.
42276  - Core Audio: Fix bugs in the case where the internal device uses deinterleaved buffers.
42277  - Core Audio: Add support for controlling the session category (AVAudioSessionCategory) and options (AVAudioSessionCategoryOptions).
42278  - JACK: Fix bug where incorrect ports are connected.
42279 
42280 v0.9.8 - 2019-10-07
42281  - WASAPI: Fix a potential deadlock when starting a full-duplex device.
42282  - WASAPI: Enable automatic resampling by default. Disable with config.wasapi.noAutoConvertSRC.
42283  - Core Audio: Fix bugs with automatic stream routing.
42284  - Add support for controlling whether or not the content of the output buffer passed in to the data callback is pre-initialized
42285  to zero. By default it will be initialized to zero, but this can be changed by setting noPreZeroedOutputBuffer in the device
42286  config. Setting noPreZeroedOutputBuffer to true will leave the contents undefined.
42287  - Add support for clipping samples after the data callback has returned. This only applies when the playback sample format is
42288  configured as ma_format_f32. If you are doing clipping yourself, you can disable this overhead by setting noClip to true in
42289  the device config.
42290  - Add support for master volume control for devices.
42291  - Use ma_device_set_master_volume() to set the volume to a factor between 0 and 1, where 0 is silence and 1 is full volume.
42292  - Use ma_device_set_master_gain_db() to set the volume in decibels where 0 is full volume and < 0 reduces the volume.
42293  - Fix warnings emitted by GCC when `__inline__` is undefined or defined as nothing.
42294 
42295 v0.9.7 - 2019-08-28
42296  - Add support for loopback mode (WASAPI only).
42297  - To use this, set the device type to ma_device_type_loopback, and then fill out the capture section of the device config.
42298  - If you need to capture from a specific output device, set the capture device ID to that of a playback device.
42299  - Fix a crash when an error is posted in ma_device_init().
42300  - Fix a compilation error when compiling for ARM architectures.
42301  - Fix a bug with the audio(4) backend where the device is incorrectly being opened in non-blocking mode.
42302  - Fix memory leaks in the Core Audio backend.
42303  - Minor refactoring to the WinMM, ALSA, PulseAudio, OSS, audio(4), sndio and null backends.
42304 
42305 v0.9.6 - 2019-08-04
42306  - Add support for loading decoders using a wchar_t string for file paths.
42307  - Don't trigger an assert when ma_device_start() is called on a device that is already started. This will now log a warning
42308  and return MA_INVALID_OPERATION. The same applies for ma_device_stop().
42309  - Try fixing an issue with PulseAudio taking a long time to start playback.
42310  - Fix a bug in ma_convert_frames() and ma_convert_frames_ex().
42311  - Fix memory leaks in the WASAPI backend.
42312  - Fix a compilation error with Visual Studio 2010.
42313 
42314 v0.9.5 - 2019-05-21
42315  - Add logging to ma_dlopen() and ma_dlsym().
42316  - Add ma_decoder_get_length_in_pcm_frames().
42317  - Fix a bug with capture on the OpenSL|ES backend.
42318  - Fix a bug with the ALSA backend where a device would not restart after being stopped.
42319 
42320 v0.9.4 - 2019-05-06
42321  - Add support for C89. With this change, miniaudio should compile clean with GCC/Clang with "-std=c89 -ansi -pedantic" and
42322  Microsoft compilers back to VC6. Other compilers should also work, but have not been tested.
42323 
42324 v0.9.3 - 2019-04-19
42325  - Fix compiler errors on GCC when compiling with -std=c99.
42326 
42327 v0.9.2 - 2019-04-08
42328  - Add support for per-context user data.
42329  - Fix a potential bug with context configs.
42330  - Fix some bugs with PulseAudio.
42331 
42332 v0.9.1 - 2019-03-17
42333  - Fix a bug where the output buffer is not getting zeroed out before calling the data callback. This happens when
42334  the device is running in passthrough mode (not doing any data conversion).
42335  - Fix an issue where the data callback is getting called too frequently on the WASAPI and DirectSound backends.
42336  - Fix error on the UWP build.
42337  - Fix a build error on Apple platforms.
42338 
42339 v0.9 - 2019-03-06
42340  - Rebranded to "miniaudio". All namespaces have been renamed from "mal" to "ma".
42341  - API CHANGE: ma_device_init() and ma_device_config_init() have changed significantly:
42342  - The device type, device ID and user data pointer have moved from ma_device_init() to the config.
42343  - All variations of ma_device_config_init_*() have been removed in favor of just ma_device_config_init().
42344  - ma_device_config_init() now takes only one parameter which is the device type. All other properties need
42345  to be set on the returned object directly.
42346  - The onDataCallback and onStopCallback members of ma_device_config have been renamed to "dataCallback"
42347  and "stopCallback".
42348  - The ID of the physical device is now split into two: one for the playback device and the other for the
42349  capture device. This is required for full-duplex. These are named "pPlaybackDeviceID" and "pCaptureDeviceID".
42350  - API CHANGE: The data callback has changed. It now uses a unified callback for all device types rather than
42351  being separate for each. It now takes two pointers - one containing input data and the other output data. This
42352  design in required for full-duplex. The return value is now void instead of the number of frames written. The
42353  new callback looks like the following:
42354  void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
42355  - API CHANGE: Remove the log callback parameter from ma_context_config_init(). With this change,
42356  ma_context_config_init() now takes no parameters and the log callback is set via the structure directly. The
42357  new policy for config initialization is that only mandatory settings are passed in to *_config_init(). The
42358  "onLog" member of ma_context_config has been renamed to "logCallback".
42359  - API CHANGE: Remove ma_device_get_buffer_size_in_bytes().
42360  - API CHANGE: Rename decoding APIs to "pcm_frames" convention.
42361  - mal_decoder_read() -> ma_decoder_read_pcm_frames()
42362  - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame()
42363  - API CHANGE: Rename sine wave reading APIs to f32 convention.
42364  - mal_sine_wave_read() -> ma_sine_wave_read_f32()
42365  - mal_sine_wave_read_ex() -> ma_sine_wave_read_f32_ex()
42366  - API CHANGE: Remove some deprecated APIs
42367  - mal_device_set_recv_callback()
42368  - mal_device_set_send_callback()
42369  - mal_src_set_input_sample_rate()
42370  - mal_src_set_output_sample_rate()
42371  - API CHANGE: Add log level to the log callback. New signature:
42372  - void on_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
42373  - API CHANGE: Changes to result codes. Constants have changed and unused codes have been removed. If you're
42374  a binding mainainer you will need to update your result code constants.
42375  - API CHANGE: Change the order of the ma_backend enums to priority order. If you are a binding maintainer, you
42376  will need to update.
42377  - API CHANGE: Rename mal_dsp to ma_pcm_converter. All functions have been renamed from mal_dsp_*() to
42378  ma_pcm_converter_*(). All structures have been renamed from mal_dsp* to ma_pcm_converter*.
42379  - API CHANGE: Reorder parameters of ma_decoder_read_pcm_frames() to be consistent with the new parameter order scheme.
42380  - The resampling algorithm has been changed from sinc to linear. The rationale for this is that the sinc implementation
42381  is too inefficient right now. This will hopefully be improved at a later date.
42382  - Device initialization will no longer fall back to shared mode if exclusive mode is requested but is unusable.
42383  With this change, if you request an device in exclusive mode, but exclusive mode is not supported, it will not
42384  automatically fall back to shared mode. The client will need to reinitialize the device in shared mode if that's
42385  what they want.
42386  - Add ring buffer API. This is ma_rb and ma_pcm_rb, the difference being that ma_rb operates on bytes and
42387  ma_pcm_rb operates on PCM frames.
42388  - Add Web Audio backend. This is used when compiling with Emscripten. The SDL backend, which was previously
42389  used for web support, will be removed in a future version.
42390  - Add AAudio backend (Android Audio). This is the new priority backend for Android. Support for AAudio starts
42391  with Android 8. OpenSL|ES is used as a fallback for older versions of Android.
42392  - Remove OpenAL and SDL backends.
42393  - Fix a possible deadlock when rapidly stopping the device after it has started.
42394  - Update documentation.
42395  - Change licensing to a choice of public domain _or_ MIT-0 (No Attribution).
42396 
42397 v0.8.14 - 2018-12-16
42398  - Core Audio: Fix a bug where the device state is not set correctly after stopping.
42399  - Add support for custom weights to the channel router.
42400  - Update decoders to use updated APIs in dr_flac, dr_mp3 and dr_wav.
42401 
42402 v0.8.13 - 2018-12-04
42403  - Core Audio: Fix a bug with channel mapping.
42404  - Fix a bug with channel routing where the back/left and back/right channels have the wrong weight.
42405 
42406 v0.8.12 - 2018-11-27
42407  - Drop support for SDL 1.2. The Emscripten build now requires "-s USE_SDL=2".
42408  - Fix a linking error with ALSA.
42409  - Fix a bug on iOS where the device name is not set correctly.
42410 
42411 v0.8.11 - 2018-11-21
42412  - iOS bug fixes.
42413  - Minor tweaks to PulseAudio.
42414 
42415 v0.8.10 - 2018-10-21
42416  - Core Audio: Fix a hang when uninitializing a device.
42417  - Fix a bug where an incorrect value is returned from mal_device_stop().
42418 
42419 v0.8.9 - 2018-09-28
42420  - Fix a bug with the SDL backend where device initialization fails.
42421 
42422 v0.8.8 - 2018-09-14
42423  - Fix Linux build with the ALSA backend.
42424  - Minor documentation fix.
42425 
42426 v0.8.7 - 2018-09-12
42427  - Fix a bug with UWP detection.
42428 
42429 v0.8.6 - 2018-08-26
42430  - Automatically switch the internal device when the default device is unplugged. Note that this is still in the
42431  early stages and not all backends handle this the same way. As of this version, this will not detect a default
42432  device switch when changed from the operating system's audio preferences (unless the backend itself handles
42433  this automatically). This is not supported in exclusive mode.
42434  - WASAPI and Core Audio: Add support for stream routing. When the application is using a default device and the
42435  user switches the default device via the operating system's audio preferences, miniaudio will automatically switch
42436  the internal device to the new default. This is not supported in exclusive mode.
42437  - WASAPI: Add support for hardware offloading via IAudioClient2. Only supported on Windows 8 and newer.
42438  - WASAPI: Add support for low-latency shared mode via IAudioClient3. Only supported on Windows 10 and newer.
42439  - Add support for compiling the UWP build as C.
42440  - mal_device_set_recv_callback() and mal_device_set_send_callback() have been deprecated. You must now set this
42441  when the device is initialized with mal_device_init*(). These will be removed in version 0.9.0.
42442 
42443 v0.8.5 - 2018-08-12
42444  - Add support for specifying the size of a device's buffer in milliseconds. You can still set the buffer size in
42445  frames if that suits you. When bufferSizeInFrames is 0, bufferSizeInMilliseconds will be used. If both are non-0
42446  then bufferSizeInFrames will take priority. If both are set to 0 the default buffer size is used.
42447  - Add support for the audio(4) backend to OpenBSD.
42448  - Fix a bug with the ALSA backend that was causing problems on Raspberry Pi. This significantly improves the
42449  Raspberry Pi experience.
42450  - Fix a bug where an incorrect number of samples is returned from sinc resampling.
42451  - Add support for setting the value to be passed to internal calls to CoInitializeEx().
42452  - WASAPI and WinMM: Stop the device when it is unplugged.
42453 
42454 v0.8.4 - 2018-08-06
42455  - Add sndio backend for OpenBSD.
42456  - Add audio(4) backend for NetBSD.
42457  - Drop support for the OSS backend on everything except FreeBSD and DragonFly BSD.
42458  - Formats are now native-endian (were previously little-endian).
42459  - Mark some APIs as deprecated:
42460  - mal_src_set_input_sample_rate() and mal_src_set_output_sample_rate() are replaced with mal_src_set_sample_rate().
42461  - mal_dsp_set_input_sample_rate() and mal_dsp_set_output_sample_rate() are replaced with mal_dsp_set_sample_rate().
42462  - Fix a bug when capturing using the WASAPI backend.
42463  - Fix some aliasing issues with resampling, specifically when increasing the sample rate.
42464  - Fix warnings.
42465 
42466 v0.8.3 - 2018-07-15
42467  - Fix a crackling bug when resampling in capture mode.
42468  - Core Audio: Fix a bug where capture does not work.
42469  - ALSA: Fix a bug where the worker thread can get stuck in an infinite loop.
42470  - PulseAudio: Fix a bug where mal_context_init() succeeds when PulseAudio is unusable.
42471  - JACK: Fix a bug where mal_context_init() succeeds when JACK is unusable.
42472 
42473 v0.8.2 - 2018-07-07
42474  - Fix a bug on macOS with Core Audio where the internal callback is not called.
42475 
42476 v0.8.1 - 2018-07-06
42477  - Fix compilation errors and warnings.
42478 
42479 v0.8 - 2018-07-05
42480  - Changed MAL_IMPLEMENTATION to MINI_AL_IMPLEMENTATION for consistency with other libraries. The old
42481  way is still supported for now, but you should update as it may be removed in the future.
42482  - API CHANGE: Replace device enumeration APIs. mal_enumerate_devices() has been replaced with
42483  mal_context_get_devices(). An additional low-level device enumration API has been introduced called
42484  mal_context_enumerate_devices() which uses a callback to report devices.
42485  - API CHANGE: Rename mal_get_sample_size_in_bytes() to mal_get_bytes_per_sample() and add
42486  mal_get_bytes_per_frame().
42487  - API CHANGE: Replace mal_device_config.preferExclusiveMode with mal_device_config.shareMode.
42488  - This new config can be set to mal_share_mode_shared (default) or mal_share_mode_exclusive.
42489  - API CHANGE: Remove excludeNullDevice from mal_context_config.alsa.
42490  - API CHANGE: Rename MAL_MAX_SAMPLE_SIZE_IN_BYTES to MAL_MAX_PCM_SAMPLE_SIZE_IN_BYTES.
42491  - API CHANGE: Change the default channel mapping to the standard Microsoft mapping.
42492  - API CHANGE: Remove backend-specific result codes.
42493  - API CHANGE: Changes to the format conversion APIs (mal_pcm_f32_to_s16(), etc.)
42494  - Add support for Core Audio (Apple).
42495  - Add support for PulseAudio.
42496  - This is the highest priority backend on Linux (higher priority than ALSA) since it is commonly
42497  installed by default on many of the popular distros and offer's more seamless integration on
42498  platforms where PulseAudio is used. In addition, if PulseAudio is installed and running (which
42499  is extremely common), it's better to just use PulseAudio directly rather than going through the
42500  "pulse" ALSA plugin (which is what the "default" ALSA device is likely set to).
42501  - Add support for JACK.
42502  - Remove dependency on asound.h for the ALSA backend. This means the ALSA development packages are no
42503  longer required to build miniaudio.
42504  - Remove dependency on dsound.h for the DirectSound backend. This fixes build issues with some
42505  distributions of MinGW.
42506  - Remove dependency on audioclient.h for the WASAPI backend. This fixes build issues with some
42507  distributions of MinGW.
42508  - Add support for dithering to format conversion.
42509  - Add support for configuring the priority of the worker thread.
42510  - Add a sine wave generator.
42511  - Improve efficiency of sample rate conversion.
42512  - Introduce the notion of standard channel maps. Use mal_get_standard_channel_map().
42513  - Introduce the notion of default device configurations. A default config uses the same configuration
42514  as the backend's internal device, and as such results in a pass-through data transmission pipeline.
42515  - Add support for passing in NULL for the device config in mal_device_init(), which uses a default
42516  config. This requires manually calling mal_device_set_send/recv_callback().
42517  - Add support for decoding from raw PCM data (mal_decoder_init_raw(), etc.)
42518  - Make mal_device_init_ex() more robust.
42519  - Make some APIs more const-correct.
42520  - Fix errors with SDL detection on Apple platforms.
42521  - Fix errors with OpenAL detection.
42522  - Fix some memory leaks.
42523  - Fix a bug with opening decoders from memory.
42524  - Early work on SSE2, AVX2 and NEON optimizations.
42525  - Miscellaneous bug fixes.
42526  - Documentation updates.
42527 
42528 v0.7 - 2018-02-25
42529  - API CHANGE: Change mal_src_read_frames() and mal_dsp_read_frames() to use 64-bit sample counts.
42530  - Add decoder APIs for loading WAV, FLAC, Vorbis and MP3 files.
42531  - Allow opening of devices without a context.
42532  - In this case the context is created and managed internally by the device.
42533  - Change the default channel mapping to the same as that used by FLAC.
42534  - Fix build errors with macOS.
42535 
42536 v0.6c - 2018-02-12
42537  - Fix build errors with BSD/OSS.
42538 
42539 v0.6b - 2018-02-03
42540  - Fix some warnings when compiling with Visual C++.
42541 
42542 v0.6a - 2018-01-26
42543  - Fix errors with channel mixing when increasing the channel count.
42544  - Improvements to the build system for the OpenAL backend.
42545  - Documentation fixes.
42546 
42547 v0.6 - 2017-12-08
42548  - API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll
42549  need to update.
42550  - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively.
42551  - API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent.
42552  - Add support for SDL and Emscripten.
42553  - Simplify the build system further for when development packages for various backends are not installed.
42554  With this change, when the compiler supports __has_include, backends without the relevant development
42555  packages installed will be ignored. This fixes the build for old versions of MinGW.
42556  - Fixes to the Android build.
42557  - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of
42558  audio data to a different format.
42559  - Improvements to f32 -> u8/s16/s24/s32 conversion routines.
42560  - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL backend.
42561  - Fixes and improvements for Raspberry Pi.
42562  - Warning fixes.
42563 
42564 v0.5 - 2017-11-11
42565  - API CHANGE: The mal_context_init() function now takes a pointer to a mal_context_config object for
42566  configuring the context. The works in the same kind of way as the device config. The rationale for this
42567  change is to give applications better control over context-level properties, add support for backend-
42568  specific configurations, and support extensibility without breaking the API.
42569  - API CHANGE: The alsa.preferPlugHW device config variable has been removed since it's not really useful for
42570  anything anymore.
42571  - ALSA: By default, device enumeration will now only enumerate over unique card/device pairs. Applications
42572  can enable verbose device enumeration by setting the alsa.useVerboseDeviceEnumeration context config
42573  variable.
42574  - ALSA: When opening a device in shared mode (the default), the dmix/dsnoop plugin will be prioritized. If
42575  this fails it will fall back to the hw plugin. With this change the preferExclusiveMode config is now
42576  honored. Note that this does not happen when alsa.useVerboseDeviceEnumeration is set to true (see above)
42577  which is by design.
42578  - ALSA: Add support for excluding the "null" device using the alsa.excludeNullDevice context config variable.
42579  - ALSA: Fix a bug with channel mapping which causes an assertion to fail.
42580  - Fix errors with enumeration when pInfo is set to NULL.
42581  - OSS: Fix a bug when starting a device when the client sends 0 samples for the initial buffer fill.
42582 
42583 v0.4 - 2017-11-05
42584  - API CHANGE: The log callback is now per-context rather than per-device and as is thus now passed to
42585  mal_context_init(). The rationale for this change is that it allows applications to capture diagnostic
42586  messages at the context level. Previously this was only available at the device level.
42587  - API CHANGE: The device config passed to mal_device_init() is now const.
42588  - Added support for OSS which enables support on BSD platforms.
42589  - Added support for WinMM (waveOut/waveIn).
42590  - Added support for UWP (Universal Windows Platform) applications. Currently C++ only.
42591  - Added support for exclusive mode for selected backends. Currently supported on WASAPI.
42592  - POSIX builds no longer require explicit linking to libpthread (-lpthread).
42593  - ALSA: Explicit linking to libasound (-lasound) is no longer required.
42594  - ALSA: Latency improvements.
42595  - ALSA: Use MMAP mode where available. This can be disabled with the alsa.noMMap config.
42596  - ALSA: Use "hw" devices instead of "plughw" devices by default. This can be disabled with the
42597  alsa.preferPlugHW config.
42598  - WASAPI is now the highest priority backend on Windows platforms.
42599  - Fixed an error with sample rate conversion which was causing crackling when capturing.
42600  - Improved error handling.
42601  - Improved compiler support.
42602  - Miscellaneous bug fixes.
42603 
42604 v0.3 - 2017-06-19
42605  - API CHANGE: Introduced the notion of a context. The context is the highest level object and is required for
42606  enumerating and creating devices. Now, applications must first create a context, and then use that to
42607  enumerate and create devices. The reason for this change is to ensure device enumeration and creation is
42608  tied to the same backend. In addition, some backends are better suited to this design.
42609  - API CHANGE: Removed the rewinding APIs because they're too inconsistent across the different backends, hard
42610  to test and maintain, and just generally unreliable.
42611  - Added helper APIs for initializing mal_device_config objects.
42612  - Null Backend: Fixed a crash when recording.
42613  - Fixed build for UWP.
42614  - Added support for f32 formats to the OpenSL|ES backend.
42615  - Added initial implementation of the WASAPI backend.
42616  - Added initial implementation of the OpenAL backend.
42617  - Added support for low quality linear sample rate conversion.
42618  - Added early support for basic channel mapping.
42619 
42620 v0.2 - 2016-10-28
42621  - API CHANGE: Add user data pointer as the last parameter to mal_device_init(). The rationale for this
42622  change is to ensure the logging callback has access to the user data during initialization.
42623  - API CHANGE: Have device configuration properties be passed to mal_device_init() via a structure. Rationale:
42624  1) The number of parameters is just getting too much.
42625  2) It makes it a bit easier to add new configuration properties in the future. In particular, there's a
42626  chance there will be support added for backend-specific properties.
42627  - Dropped support for f64, A-law and Mu-law formats since they just aren't common enough to justify the
42628  added maintenance cost.
42629  - DirectSound: Increased the default buffer size for capture devices.
42630  - Added initial implementation of the OpenSL|ES backend.
42631 
42632 v0.1 - 2016-10-21
42633  - Initial versioned release.
42634 */
42635 
42636 
42637 /*
42638 This software is available as a choice of the following licenses. Choose
42639 whichever you prefer.
42640 
42641 ===============================================================================
42642 ALTERNATIVE 1 - Public Domain (www.unlicense.org)
42643 ===============================================================================
42644 This is free and unencumbered software released into the public domain.
42645 
42646 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
42647 software, either in source code form or as a compiled binary, for any purpose,
42648 commercial or non-commercial, and by any means.
42649 
42650 In jurisdictions that recognize copyright laws, the author or authors of this
42651 software dedicate any and all copyright interest in the software to the public
42652 domain. We make this dedication for the benefit of the public at large and to
42653 the detriment of our heirs and successors. We intend this dedication to be an
42654 overt act of relinquishment in perpetuity of all present and future rights to
42655 this software under copyright law.
42656 
42657 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42658 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42659 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42660 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
42661 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
42662 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42663 
42664 For more information, please refer to <http://unlicense.org/>
42665 
42666 ===============================================================================
42667 ALTERNATIVE 2 - MIT No Attribution
42668 ===============================================================================
42669 Copyright 2020 David Reid
42670 
42671 Permission is hereby granted, free of charge, to any person obtaining a copy of
42672 this software and associated documentation files (the "Software"), to deal in
42673 the Software without restriction, including without limitation the rights to
42674 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
42675 of the Software, and to permit persons to whom the Software is furnished to do
42676 so.
42677 
42678 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42679 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42680 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42681 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42682 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42683 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
42684 SOFTWARE.
42685 */
ma_int64
int64_t ma_int64
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1504
ma__realloc_from_callbacks
static void * ma__realloc_from_callbacks(void *p, size_t szNew, size_t szOld, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1860
ma_encoder::config
ma_encoder_config config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5326
drwav_seek_origin
drwav_seek_origin
Definition: porcupine/demo/c/dr_libs/dr_wav.h:268
drmp3_uninit
DRMP3_API void drmp3_uninit(drmp3 *pMP3)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:61946
ma_backend_audio4
@ ma_backend_audio4
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2800
ma_hpf2_config
struct ma_hpf1_config ma_hpf2_config
ma_uint64
uint64_t ma_uint64
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1505
MA_FAILED_TO_STOP_BACKEND_DEVICE
#define MA_FAILED_TO_STOP_BACKEND_DEVICE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1733
ma_get_bytes_per_frame
static MA_INLINE ma_uint32 ma_get_bytes_per_frame(ma_format format, ma_uint32 channels)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2673
ma_device_init_ex
ma_result ma_device_init_ex(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config *pContextConfig, const ma_device_config *pConfig, ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27362
ma_bpf::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2052
ma_device::speex
struct ma_device::@114::@120 speex
ma_resampler_process_pcm_frames__read
static ma_result ma_resampler_process_pcm_frames__read(ma_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33246
ma_device_config::pDeviceID
ma_device_id * pDeviceID
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3127
ma_hishelf2_config_init
ma_hishelf2_config ma_hishelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32308
MA_CHANNEL_AUX_12
#define MA_CHANNEL_AUX_12
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1633
ma_noise_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5400
ma_data_converter_process_pcm_frames__channels_only
static ma_result ma_data_converter_process_pcm_frames__channels_only(ma_data_converter *pConverter, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34898
NAME
string NAME
ma_bpf2_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2024
MA_STATE_STARTED
#define MA_STATE_STARTED
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:1627
ma_device_config::shareMode
ma_share_mode shareMode
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3131
ma_device_config::noClip
ma_bool32 noClip
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3109
ma_standard_channel_map_rfc3551
@ ma_standard_channel_map_rfc3551
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1807
ma_device::operationEvent
ma_event operationEvent
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3837
ma_biquad_process_pcm_frame_s16
static MA_INLINE void ma_biquad_process_pcm_frame_s16(ma_biquad *pBQ, ma_int16 *pY, const ma_int16 *pX)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30565
ma_get_backend_name
const char * ma_get_backend_name(ma_backend backend)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5055
ma_mix_f32_fast
static MA_INLINE float ma_mix_f32_fast(float x, float y, float a)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2350
drwav::bitsPerSample
drwav_uint16 bitsPerSample
Definition: porcupine/demo/c/dr_libs/dr_wav.h:837
ma_strappend
MA_API int ma_strappend(char *dst, size_t dstSize, const char *srcA, const char *srcB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1139
ma_strncpy_s
MA_API int ma_strncpy_s(char *dst, size_t dstSizeInBytes, const char *src, size_t count)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:925
ma_lcg_rand_u32
static MA_INLINE ma_uint32 ma_lcg_rand_u32(ma_lcg *pLCG)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2449
drmp3::channels
drmp3_uint32 channels
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:344
ma_channel_converter_config::channelMapOut
ma_channel channelMapOut[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2364
ma_context::playbackDeviceInfoCount
ma_uint32 playbackDeviceInfoCount
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3220
ma_notch2_process_pcm_frame_s16
static MA_INLINE void ma_notch2_process_pcm_frame_s16(ma_notch2 *pFilter, ma_int16 *pFrameOut, const ma_int16 *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32019
MA_LCG_C
#define MA_LCG_C
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2433
ma_decoder_init_wav
ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void *pUserData, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43687
ma_lpf_process_pcm_frames
ma_result ma_lpf_process_pcm_frames(ma_lpf *pLPF, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31060
ma_channel_mix_mode_planar_blend
@ ma_channel_mix_mode_planar_blend
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1799
ma_channel_converter_uninit
void ma_channel_converter_uninit(ma_channel_converter *pConverter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34088
MA_FALSE
#define MA_FALSE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1531
ma_apply_volume_factor_pcm_frames_f32
void ma_apply_volume_factor_pcm_frames_f32(float *pFrames, ma_uint32 frameCount, ma_uint32 channels, float factor)
ma_device_type_loopback
@ ma_device_type_loopback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3015
ma_rb_available_read
ma_uint32 ma_rb_available_read(ma_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36740
MA_DEVICE_TYPE_NOT_SUPPORTED
#define MA_DEVICE_TYPE_NOT_SUPPORTED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1716
ma_event_uninit
MA_API void ma_event_uninit(ma_event *pEvent)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4872
MA_CHANNEL_AUX_17
#define MA_CHANNEL_AUX_17
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1638
ma_channel_map_blank
ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS])
ma_lpf2::bq
ma_biquad bq
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1908
ma_convert_frames
ma_uint64 ma_convert_frames(void *pOut, ma_uint64 frameCountOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, const void *pIn, ma_uint64 frameCountIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36289
MA_FAILED_TO_INIT_BACKEND
#define MA_FAILED_TO_INIT_BACKEND
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1730
ma_device::resampling
struct ma_device::@114 resampling
UINT32_MAX
#define UINT32_MAX
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:96
ma_data_converter_get_required_input_frame_count
ma_uint64 ma_data_converter_get_required_input_frame_count(ma_data_converter *pConverter, ma_uint64 outputFrameCount)
MA_ACCESS_DENIED
#define MA_ACCESS_DENIED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1665
ma_hpf1_process_pcm_frames
ma_result ma_hpf1_process_pcm_frames(ma_hpf1 *pHPF, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31261
ma_encoder::onWritePCMFrames
ma_encoder_write_pcm_frames_proc onWritePCMFrames
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5331
ma_apply_volume_factor_s16
void ma_apply_volume_factor_s16(ma_int16 *pSamples, ma_uint32 sampleCount, float factor)
MA_SAMPLE_RATE_22050
#define MA_SAMPLE_RATE_22050
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1740
ma_gain_db_to_factor
float ma_gain_db_to_factor(float gain)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28000
ma_hishelf2_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2152
ma_bpf_config_init
ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31747
ma_stream_layout_deinterleaved
@ ma_stream_layout_deinterleaved
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1769
ma_get_standard_channel_map_sound4
static void ma_get_standard_channel_map_sound4(ma_uint32 channels, ma_channel *pChannelMap)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:35996
ma_lpf2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1906
ma_thread
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2824
ma_linear_resampler_get_output_latency
ma_uint64 ma_linear_resampler_get_output_latency(ma_linear_resampler *pResampler)
ma_channel_converter
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2367
MA_NO_ADDRESS
#define MA_NO_ADDRESS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1697
ma_pcm_interleave_s16__optimized
static MA_INLINE void ma_pcm_interleave_s16__optimized(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28716
ma_rb::subbufferStrideInBytes
ma_uint32 subbufferStrideInBytes
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2570
ma_bpf2_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2025
ma_pcm_u8_to_f32
void ma_pcm_u8_to_f32(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28308
ma_encoder_init_file_w
ma_result ma_encoder_init_file_w(const wchar_t *pFilePath, const ma_encoder_config *pConfig, ma_encoder *pEncoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45300
ma_device_id::dsound
ma_uint8 dsound[16]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3058
ma_data_converter_process_pcm_frames__passthrough
static ma_result ma_data_converter_process_pcm_frames__passthrough(ma_data_converter *pConverter, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34682
ma_pcm_rb_seek_write
ma_result ma_pcm_rb_seek_write(ma_pcm_rb *pRB, ma_uint32 offsetInFrames)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36931
ma_pcm_deinterleave_s16__optimized
static MA_INLINE void ma_pcm_deinterleave_s16__optimized(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28745
MA_CHANNEL_AUX_10
#define MA_CHANNEL_AUX_10
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1631
ma_rb_init_ex
ma_result ma_rb_init_ex(size_t subbufferSizeInBytes, size_t subbufferCount, size_t subbufferStrideInBytes, void *pOptionalPreallocatedBuffer, const ma_allocation_callbacks *pAllocationCallbacks, ma_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36371
ma_allocation_callbacks::onMalloc
void *(* onMalloc)(size_t sz, void *pUserData)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1826
ma_lpf_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1920
MA_CHANNEL_NONE
#define MA_CHANNEL_NONE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1601
drwav_bool32
drwav_uint32 drwav_bool32
Definition: porcupine/demo/c/dr_libs/dr_wav.h:163
ma_pcm_s24_to_s32__optimized
static MA_INLINE void ma_pcm_s24_to_s32__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28941
ma_decoder_get_length_in_pcm_frames
ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44780
ma_ios_session_category_option_allow_air_play
@ ma_ios_session_category_option_allow_air_play
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3046
ma_device::null_device
struct ma_device::@117::@121 null_device
ma_lpf::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1931
ma_lpf2_reinit
ma_result ma_lpf2_reinit(const ma_lpf2_config *pConfig, ma_lpf2 *pLPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30850
MA_NO_DEVICE
#define MA_NO_DEVICE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1719
ma_rb::subbufferCount
ma_uint32 subbufferCount
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2569
ma_hpf2_init
ma_result ma_hpf2_init(const ma_hpf2_config *pConfig, ma_hpf2 *pHPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31337
ma_hishelf2_process_pcm_frame_s16
static MA_INLINE void ma_hishelf2_process_pcm_frame_s16(ma_hishelf2 *pFilter, ma_int16 *pFrameOut, const ma_int16 *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32400
ma_pcm_s16_to_f32__reference
static MA_INLINE void ma_pcm_s16_to_f32__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28628
ma_decoder_init_memory_vorbis
ma_result ma_decoder_init_memory_vorbis(const void *pData, size_t dataSize, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44046
ma_context_uninit_backend_apis__nix
static ma_result ma_context_uninit_backend_apis__nix(ma_context *pContext)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26429
ma_waveform_set_frequency
ma_result ma_waveform_set_frequency(ma_waveform *pWaveform, double frequency)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45490
ma_linear_resampler::inAdvanceInt
ma_uint32 inAdvanceInt
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2207
ma_device_config::noAutoConvertSRC
ma_bool32 noAutoConvertSRC
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3144
ma_rand_range_s32
static MA_INLINE ma_int32 ma_rand_range_s32(ma_int32 lo, ma_int32 hi)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2515
ma_pcm_f32_to_s24__optimized
static MA_INLINE void ma_pcm_f32_to_s24__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30044
ma_bpf_init
ma_result ma_bpf_init(const ma_bpf_config *pConfig, ma_bpf *pBPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31833
MA_CHANNEL_TOP_BACK_LEFT
#define MA_CHANNEL_TOP_BACK_LEFT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1618
ma_noise_config::amplitude
double amplitude
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5406
MA_CHANNEL_BACK_RIGHT
#define MA_CHANNEL_BACK_RIGHT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1608
ma_hpf::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1999
MA_INVALID_ARGS
#define MA_INVALID_ARGS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1661
ma_pcm_u8_to_s16__reference
static MA_INLINE void ma_pcm_u8_to_s16__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28070
MA_CHANNEL_AUX_31
#define MA_CHANNEL_AUX_31
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1652
stb_vorbis_get_info
stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:4280
MA_CHANNEL_FRONT_RIGHT
#define MA_CHANNEL_FRONT_RIGHT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1604
drflac_read_pcm_frames_f32
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac *pFlac, drflac_uint64 framesToRead, float *pBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:58850
ma_uint8
uint8_t ma_uint8
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1499
ma_biquad_init
ma_result ma_biquad_init(const ma_biquad_config *pConfig, ma_biquad *pBQ)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30440
ma_copy_string
MA_API char * ma_copy_string(const char *src, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1156
ma_device_uninit
void ma_device_uninit(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27425
ma_lpf2_config_init
ma_lpf2_config ma_lpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30635
ma_channel_converter_process_pcm_frames__simple_mono_expansion
static ma_result ma_channel_converter_process_pcm_frames__simple_mono_expansion(ma_channel_converter *pConverter, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34201
ma_pcm_f32_to_s16__optimized
static MA_INLINE void ma_pcm_f32_to_s16__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29601
ma_channel_map_equal
ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel channelMapA[MA_MAX_CHANNELS], const ma_channel channelMapB[MA_MAX_CHANNELS])
ma_dlsym
MA_API ma_proc ma_dlsym(ma_context *pContext, ma_handle handle, const char *symbol)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5625
ma_timer::counter
ma_int64 counter
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3051
ma_min
#define ma_min(x, y)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:778
ma_hpf1::a
ma_biquad_coefficient a
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1965
ma_rb_init
ma_result ma_rb_init(size_t bufferSizeInBytes, void *pOptionalPreallocatedBuffer, const ma_allocation_callbacks *pAllocationCallbacks, ma_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36424
ma_rb_reset
void ma_rb_reset(ma_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36440
drflac_allocation_callbacks::onMalloc
void *(* onMalloc)(size_t sz, void *pUserData)
Definition: porcupine/demo/c/dr_libs/dr_flac.h:567
ma_device_info::_private
struct ma_device_info::@95 _private
ma_context::onDeviceUninit
void(* onDeviceUninit)(ma_device *pDevice)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3230
MA_API_NOT_FOUND
#define MA_API_NOT_FOUND
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1720
ma_noise
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5412
ma_pcm_s16_to_s16
MA_API void ma_pcm_s16_to_s16(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28495
ma_decoder_init_file_wav
ma_result ma_decoder_init_file_wav(const char *pFilePath, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44692
ma_bpf2_process_pcm_frames
ma_result ma_bpf2_process_pcm_frames(ma_bpf2 *pBPF, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31728
ma_device_id::aaudio
ma_int32 aaudio
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3067
MA_CHANNEL_BACK_LEFT
#define MA_CHANNEL_BACK_LEFT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1607
ma_device::masterVolumeFactor
volatile float masterVolumeFactor
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3605
drwav_read_pcm_frames_f32
DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav *pWav, drwav_uint64 framesToRead, float *pBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:50305
ma_device_start
ma_result ma_device_start(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27485
ma_channel_mix_mode_custom_weights
@ ma_channel_mix_mode_custom_weights
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1798
ma_encoder_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5313
ma_decoder_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5174
ma_pcm_deinterleave_u8
MA_API void ma_pcm_deinterleave_u8(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28402
ma_lpf::lpf2Count
ma_uint32 lpf2Count
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1933
ma_resampler_config::quality
int quality
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2254
ma_context::pthread_attr_setschedparam
ma_proc pthread_attr_setschedparam
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3577
ma_pcm_rb_available_write
ma_uint32 ma_pcm_rb_available_write(ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36958
ma_device::internalChannels
ma_uint32 internalChannels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3629
ma_lpf_get_latency
ma_uint32 ma_lpf_get_latency(ma_lpf *pLPF)
ma_decoder_config_init_copy
MA_API ma_decoder_config ma_decoder_config_init_copy(const ma_decoder_config *pConfig)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:40668
drmp3_init
DRMP3_API drmp3_bool32 drmp3_init(drmp3 *pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void *pUserData, const drmp3_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:61339
ma_apply_volume_factor_pcm_frames_s16
void ma_apply_volume_factor_pcm_frames_s16(ma_int16 *pFrames, ma_uint32 frameCount, ma_uint32 channels, float factor)
MA_DEFAULT_CHANNELS
#define MA_DEFAULT_CHANNELS
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:601
ma_biquad::a1
ma_biquad_coefficient a1
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1864
ma_encoder__on_init_wav
static ma_result ma_encoder__on_init_wav(ma_encoder *pEncoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45120
ma_decoder_init_file_mp3_w
ma_result ma_decoder_init_file_mp3_w(const wchar_t *pFilePath, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44729
MA_CHANNEL_TOP_BACK_CENTER
#define MA_CHANNEL_TOP_BACK_CENTER
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1619
ma_lpf_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1921
ma_noise_type_brownian
@ ma_noise_type_brownian
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5397
ma_thread
pthread_t ma_thread
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:505
MA_CHANNEL_AUX_0
#define MA_CHANNEL_AUX_0
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1621
ma_biquad::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1860
ma_hpf2_get_latency
ma_uint32 ma_hpf2_get_latency(ma_hpf2 *pHPF)
MA_CANCELLED
#define MA_CANCELLED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1710
ma_strcmp
MA_API int ma_strcmp(const char *str1, const char *str2)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1116
ma_device_id::pulse
char pulse[256]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3061
ma_pcm_s32_to_u8__reference
static MA_INLINE void ma_pcm_s32_to_u8__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29128
MA_CHANNEL_TOP_CENTER
#define MA_CHANNEL_TOP_CENTER
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1614
ma_backend_wasapi
@ ma_backend_wasapi
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2795
ma_hpf::hpf2Count
ma_uint32 hpf2Count
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2001
ma_semaphore::_unused
int _unused
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2910
ma_noise_read_pcm_frames__pink
static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise *pNoise, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:46082
ma_peak2_process_pcm_frame_f32
static MA_INLINE void ma_peak2_process_pcm_frame_f32(ma_peak2 *pFilter, float *pFrameOut, const float *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32153
MA_CONNECTION_REFUSED
#define MA_CONNECTION_REFUSED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1707
ma_dither_mode_triangle
@ ma_dither_mode_triangle
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1776
ma_data_converter_config::channelMapIn
ma_channel channelMapIn[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2409
MA_CHANNEL_AUX_20
#define MA_CHANNEL_AUX_20
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1641
ma_proc
void(* ma_proc)(void)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1535
ma_biquad::r1
ma_biquad_coefficient r1[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1866
ma_channel_converter_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2354
ma_stop_proc
void(* ma_stop_proc)(ma_device *pDevice)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2974
ma_device::operationCompletionEvent
ma_event operationCompletionEvent
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3838
ma_hpf1_config_init
ma_hpf1_config ma_hpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31133
ma_pcm_f32_to_u8__optimized
static MA_INLINE void ma_pcm_f32_to_u8__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29519
ma_data_converter_config::sampleRateOut
ma_uint32 sampleRateOut
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2408
ma_thread_priority_realtime
@ ma_thread_priority_realtime
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2820
ma_hishelf2_init
ma_result ma_hishelf2_init(const ma_hishelf2_config *pConfig, ma_hishelf2 *pFilter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32358
ma_channel_converter::isSimpleMonoExpansion
ma_bool32 isSimpleMonoExpansion
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2382
ma_device_config::wasapi
struct ma_device_config::@99 wasapi
ma_data_converter_get_input_latency
ma_uint64 ma_data_converter_get_input_latency(ma_data_converter *pConverter)
drflac
Definition: porcupine/demo/c/dr_libs/dr_flac.h:688
ma_resource_format_wav
@ ma_resource_format_wav
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5147
ma_data_converter_get_output_latency
ma_uint64 ma_data_converter_get_output_latency(ma_data_converter *pConverter)
ma_format_count
@ ma_format_count
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1791
ma_thread_priority_normal
@ ma_thread_priority_normal
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2817
ma_device_type_capture
@ ma_device_type_capture
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3013
ma_notch2_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2076
ma_context::deviceInfoCapacity
ma_uint32 deviceInfoCapacity
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3219
ma_decoder__preinit
static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, ma_decoder_tell_proc onTell, void *pUserData, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43620
ma_decoder_uninit
ma_result ma_decoder_uninit(ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44739
drflac::channels
drflac_uint8 channels
Definition: porcupine/demo/c/dr_libs/dr_flac.h:707
ma_hpf_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1989
ma_hpf1_init
ma_result ma_hpf1_init(const ma_hpf1_config *pConfig, ma_hpf1 *pHPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31166
ma_notch2_reinit
ma_result ma_notch2_reinit(const ma_notch2_config *pConfig, ma_notch2 *pFilter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32001
ma_decoder_init
ma_result ma_decoder_init(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void *pUserData, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43870
ma_decoder_uninit_proc
ma_result(* ma_decoder_uninit_proc)(ma_decoder *pDecoder)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5167
ma_decoder_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5170
ma_device::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3626
ma_pcm_rb::rb
ma_rb rb
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2595
ma_lpf1_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1887
ma_device::currentPeriodFramesRemainingPlayback
ma_uint32 currentPeriodFramesRemainingPlayback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3843
ma_device_config::deviceType
ma_device_type deviceType
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3102
MA_DEFAULT_LCG_SEED
#define MA_DEFAULT_LCG_SEED
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2428
ma_device::lastProcessedFrameCapture
ma_uint32 lastProcessedFrameCapture
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3846
ma_channel_converter_config::channelsIn
ma_uint32 channelsIn
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2361
ma_resample_algorithm
ma_resample_algorithm
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2234
drwav_seek_origin_start
@ drwav_seek_origin_start
Definition: porcupine/demo/c/dr_libs/dr_wav.h:270
ma_bool32
ma_uint32 ma_bool32
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1529
ma_biquad_config::a0
double a0
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1850
ma_has_avx512f
static MA_INLINE ma_bool32 ma_has_avx512f(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:324
ma_calculate_channel_position_rectangular_weight
static float ma_calculate_channel_position_rectangular_weight(ma_channel channelPositionA, ma_channel channelPositionB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33691
ma_channel_converter::mixingMode
ma_channel_mix_mode mixingMode
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2374
drmp3_config
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:334
ma_noise_read_pcm_frames__brownian
static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise *pNoise, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:46164
ma_semaphore_uninit__posix
static void ma_semaphore_uninit__posix(ma_semaphore *pSemaphore)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4641
ma_pcm_s16_to_s32__optimized
static MA_INLINE void ma_pcm_s16_to_s32__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28579
ma_event_signal__posix
static ma_result ma_event_signal__posix(ma_event *pEvent)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4604
ma_bpf2_config::cutoffFrequency
double cutoffFrequency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2026
ma_strncat_s
MA_API int ma_strncat_s(char *dst, size_t dstSizeInBytes, const char *src, size_t count)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1001
MA_SAMPLE_RATE_384000
#define MA_SAMPLE_RATE_384000
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1750
ma_lcg_rand_s16
static MA_INLINE ma_int16 ma_lcg_rand_s16(ma_lcg *pLCG)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2454
ma_bpf2_reinit
ma_result ma_bpf2_reinit(const ma_bpf2_config *pConfig, ma_bpf2 *pBPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31700
ma_resampler_config::sampleRateOut
ma_uint32 sampleRateOut
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2245
ma_waveform_triangle_f32
static float ma_waveform_triangle_f32(double time, double amplitude)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45553
ma_pcm_deinterleave_s32
MA_API void ma_pcm_deinterleave_s32(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29483
ma_waveform_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5361
ma_hpf2_process_pcm_frame_s16
static MA_INLINE void ma_hpf2_process_pcm_frame_s16(ma_hpf2 *pHPF, ma_int16 *pFrameOut, const ma_int16 *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31379
MA_CHANNEL_AUX_21
#define MA_CHANNEL_AUX_21
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1642
errno
int errno
ma_waveform_set_amplitude
ma_result ma_waveform_set_amplitude(ma_waveform *pWaveform, double amplitude)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45480
ma_device::lock
ma_mutex lock
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3593
ma_decoder::onGetLengthInPCMFrames
ma_decoder_get_length_in_pcm_frames_proc onGetLengthInPCMFrames
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5212
ma_encoder::onUninit
ma_encoder_uninit_proc onUninit
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5330
MA_CHANNEL_AUX_7
#define MA_CHANNEL_AUX_7
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1628
ma_hpf::hpf1
ma_hpf1 hpf1[1]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2002
ma_waveform_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5364
ma_context::pthread_mutex_lock
ma_proc pthread_mutex_lock
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3567
ma_countof
#define ma_countof(x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:776
ma_bpf_process_pcm_frames
ma_result ma_bpf_process_pcm_frames(ma_bpf *pBPF, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31853
ma_format_f32
@ ma_format_f32
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1790
ma_linear_resampler::config
ma_linear_resampler_config config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2206
ma_device_config::noHardwareOffloading
ma_bool32 noHardwareOffloading
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3147
ma_context_is_loopback_supported
ma_bool32 ma_context_is_loopback_supported(ma_context *pContext)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27024
ma_biquad_config::b1
double b1
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1848
MA_LOG_LEVEL
#define MA_LOG_LEVEL
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1594
ma_decoder_config::resampling
struct ma_decoder_config::@122 resampling
ma_context::onEnumDevices
ma_result(* onEnumDevices)(ma_context *pContext, ma_enum_devices_callback_proc callback, void *pUserData)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3227
ma_hishelf2__get_biquad_config
static MA_INLINE ma_biquad_config ma_hishelf2__get_biquad_config(const ma_hishelf2_config *pConfig)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32324
ma_decoder::onUninit
ma_decoder_uninit_proc onUninit
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5211
s
XmlRpcServer s
ma_bpf2_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2023
ma_decoder_init_memory_wav
ma_result ma_decoder_init_memory_wav(const void *pData, size_t dataSize, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43992
_stricmp
DR_INLINE int _stricmp(const char *string1, const char *string2)
Definition: porcupine/demo/c/dr_libs/old/dr.h:178
ma_lpf1_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1888
ma_dither_mode_rectangle
@ ma_dither_mode_rectangle
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1775
MA_MALLOC
#define MA_MALLOC(sz)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:722
drwav_allocation_callbacks::onRealloc
void *(* onRealloc)(void *p, size_t sz, void *pUserData)
Definition: porcupine/demo/c/dr_libs/dr_wav.h:413
ma_resampler_set_rate_ratio
ma_result ma_resampler_set_rate_ratio(ma_resampler *pResampler, float ratio)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33454
ma_backend_opensl
@ ma_backend_opensl
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2806
ma_data_converter_config::ditherMode
ma_dither_mode ditherMode
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2411
ma_decoder::onRead
ma_decoder_read_proc onRead
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5195
MA_NOT_DIRECTORY
#define MA_NOT_DIRECTORY
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1673
ma_waveform_sine_f32
static float ma_waveform_sine_f32(double time, double amplitude)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45524
ma_pcm_rb_get_subbuffer_size
ma_uint32 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36967
MA_DATA_CONVERTER_STACK_BUFFER_SIZE
#define MA_DATA_CONVERTER_STACK_BUFFER_SIZE
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4226
ma_pcm_deinterleave_f32__reference
static void ma_pcm_deinterleave_f32__reference(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30205
ma_thread_priority_highest
@ ma_thread_priority_highest
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2819
ma_decoder_config::linear
struct ma_decoder_config::@122::@123 linear
ma_ios_session_category_option_mix_with_others
@ ma_ios_session_category_option_mix_with_others
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3040
MA_CHANNEL_TOP_FRONT_LEFT
#define MA_CHANNEL_TOP_FRONT_LEFT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1615
MA_NO_DATA_AVAILABLE
#define MA_NO_DATA_AVAILABLE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1691
ma_device::usingDefaultChannelMap
ma_bool32 usingDefaultChannelMap
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3624
MA_BUSY
#define MA_BUSY
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1678
ma_decoder::memory
struct ma_decoder::@125 memory
ma_biquad::b0
ma_biquad_coefficient b0
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1861
MA_FAILED_TO_OPEN_BACKEND_DEVICE
#define MA_FAILED_TO_OPEN_BACKEND_DEVICE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1731
speex_resampler_init
EXPORT SpeexResamplerState * speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:794
ma_decoder_config_init
ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:40646
ma_device_config::noAutoStreamRouting
ma_bool32 noAutoStreamRouting
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3146
stb_vorbis_info
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:124
MA_CHANNEL_TOP_FRONT_RIGHT
#define MA_CHANNEL_TOP_FRONT_RIGHT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1617
ma_format_s32
@ ma_format_s32
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1789
MA_INLINE
#define MA_INLINE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1569
ma_data_converter_config::channelsIn
ma_uint32 channelsIn
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2405
ma_log10f
static MA_INLINE float ma_log10f(float x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:833
MA_OUT_OF_RANGE
#define MA_OUT_OF_RANGE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1664
ma_pcm_s32_to_f32
void ma_pcm_s32_to_f32(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29410
ma_context_post_error
static ma_result ma_context_post_error(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel, const char *message, ma_result resultCode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5450
ma_copy_and_apply_volume_factor_pcm_frames_s32
void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32 *pPCMFramesOut, const ma_int32 *pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor)
ma_hpf_get_latency
ma_uint32 ma_hpf_get_latency(ma_hpf *pHPF)
ma_device_stop
ma_result ma_device_stop(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27544
RESAMPLER_ERR_ALLOC_FAILED
@ RESAMPLER_ERR_ALLOC_FAILED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/speex_resampler.h:105
ma_ios_session_category_option
ma_ios_session_category_option
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3038
ma_rb::subbufferSizeInBytes
ma_uint32 subbufferSizeInBytes
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2568
ma_lpf1_process_pcm_frames
ma_result ma_lpf1_process_pcm_frames(ma_lpf1 *pLPF, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30750
ma_noise_read_pcm_frames__white
static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise *pNoise, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45963
ma__malloc_from_callbacks
static void * ma__malloc_from_callbacks(size_t sz, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1842
ma_waveform_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5365
ma_pcm_rb_commit_read
ma_result ma_pcm_rb_commit_read(ma_pcm_rb *pRB, ma_uint32 sizeInFrames, void *pBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36884
FALSE
#define FALSE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:642
ma_context::pthread_mutex_init
ma_proc pthread_mutex_init
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3565
ma_pcm_f32_to_u8
void ma_pcm_f32_to_u8(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29543
ma_prev_power_of_2
static MA_INLINE unsigned int ma_prev_power_of_2(unsigned int x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1786
drwav_read_pcm_frames_s16
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav *pWav, drwav_uint64 framesToRead, drwav_int16 *pBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:50013
ma_device_get_master_volume
ma_result ma_device_get_master_volume(ma_device *pDevice, float *pVolume)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27632
MA_SOCKET_NOT_SUPPORTED
#define MA_SOCKET_NOT_SUPPORTED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1703
ma_int8
int8_t ma_int8
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1498
drwav_seek_to_pcm_frame
DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav *pWav, drwav_uint64 targetFrameIndex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:49385
ma_mutex_uninit__posix
static void ma_mutex_uninit__posix(ma_mutex *pMutex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4549
ma_peak2_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2104
ma_data_converter_config_init_default
ma_data_converter_config ma_data_converter_config_init_default(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34511
ma_uintptr
uintptr_t ma_uintptr
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1509
ma_device_config::alsa
struct ma_device_config::@100 alsa
ma_context_config::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3164
ma_dlclose
MA_API void ma_dlclose(ma_context *pContext, ma_handle handle)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5614
MA_CHANNEL_AUX_11
#define MA_CHANNEL_AUX_11
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1632
ma_int16
int16_t ma_int16
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1500
ma_hpf_reinit
ma_result ma_hpf_reinit(const ma_hpf_config *pConfig, ma_hpf *pHPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31530
drmp3_config::outputChannels
drmp3_uint32 outputChannels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/dr_mp3.h:316
ma_pcm_s32_to_s16__optimized
static MA_INLINE void ma_pcm_s32_to_s16__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29241
ma_allocation_callbacks::onFree
void(* onFree)(void *p, void *pUserData)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1828
ma_device_info::minChannels
ma_uint32 minChannels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3089
ma_hpf_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1985
ma_pcm_u8_to_s24__optimized
static MA_INLINE void ma_pcm_u8_to_s24__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28153
decoder
ma_decoder decoder
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/tests/test_deviceio/ma_test_deviceio.c:61
ma_device::timer
ma_timer timer
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3841
ma_semaphore_release
MA_API ma_result ma_semaphore_release(ma_semaphore *pSemaphore)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4974
ma_device_id::nullbackend
int nullbackend
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3070
ma_pcm_interleave_s32__reference
static MA_INLINE void ma_pcm_interleave_s32__reference(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29435
ma_allocation_callbacks_init_default
static ma_allocation_callbacks ma_allocation_callbacks_init_default(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1911
ma_device_config::stopCallback
ma_stop_proc stopCallback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3111
MA_SAMPLE_RATE_48000
#define MA_SAMPLE_RATE_48000
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1744
ma_device::usingDefaultFormat
ma_bool32 usingDefaultFormat
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3622
ma_resampler_process_pcm_frames__read__linear
static ma_result ma_resampler_process_pcm_frames__read__linear(ma_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33171
MA_DEFAULT_CAPTURE_DEVICE_NAME
#define MA_DEFAULT_CAPTURE_DEVICE_NAME
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5418
ma_ios_session_category_record
@ ma_ios_session_category_record
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3032
ma_pcm_s16_to_u8__reference
static MA_INLINE void ma_pcm_s16_to_u8__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28413
ma_waveform_sine_s16
static ma_int16 ma_waveform_sine_s16(double time, double amplitude)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45529
drmp3_seek_origin_start
@ drmp3_seek_origin_start
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:286
MA_INVALID_FILE
#define MA_INVALID_FILE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1669
ma_encoder_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5317
ma_decoder::readPointer
ma_uint64 readPointer
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5198
ma_context::null_backend
struct ma_context::@108::@112 null_backend
ma_device::internalPeriods
ma_uint32 internalPeriods
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3633
MA_SAMPLE_RATE_352800
#define MA_SAMPLE_RATE_352800
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1749
ma_semaphore_init
MA_API ma_result ma_semaphore_init(int initialValue, ma_semaphore *pSemaphore)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4929
ma_peak2_reinit
ma_result ma_peak2_reinit(const ma_peak2_config *pConfig, ma_peak2 *pFilter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32130
ma_device::channelMixMode
ma_channel_mix_mode channelMixMode
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:2653
BYTE
unsigned char BYTE
ma_notch2_process_pcm_frames
ma_result ma_notch2_process_pcm_frames(ma_notch2 *pFilter, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32029
ma_channel_converter::channelMapOut
ma_channel channelMapOut[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2373
ma_format
ma_format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1779
ma_standard_channel_map_flac
@ ma_standard_channel_map_flac
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1808
ma_semaphore
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2892
MA_BAD_ADDRESS
#define MA_BAD_ADDRESS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1683
ma_device::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3625
ma_dither_mode
ma_dither_mode
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1772
ma_device_id::webaudio
char webaudio[32]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3069
ma_data_converter_config::channelMixMode
ma_channel_mix_mode channelMixMode
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2412
ma_peak2_config::frequency
double frequency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2107
ma_context_config::threadPriority
ma_thread_priority threadPriority
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3163
MA_SAMPLE_RATE_24000
#define MA_SAMPLE_RATE_24000
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1741
ma_thread::_unused
int _unused
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2842
ma_decoder::allocationCallbacks
ma_allocation_callbacks allocationCallbacks
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5208
speex_resampler_destroy
EXPORT void speex_resampler_destroy(SpeexResamplerState *st)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:868
ma_sleep__posix
static void ma_sleep__posix(ma_uint32 milliseconds)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:501
MA_SAMPLE_RATE_44100
#define MA_SAMPLE_RATE_44100
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1743
ma_linear_resampler_config::sampleRateOut
ma_uint32 sampleRateOut
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2210
ma_deinterleave_pcm_frames
void ma_deinterleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void *pInterleavedPCMFrames, void **ppDeinterleavedPCMFrames)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30312
ma_pcm_rb_pointer_distance
ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36940
MA_CHANNEL_AUX_18
#define MA_CHANNEL_AUX_18
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1639
ma_device_type_playback
@ ma_device_type_playback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3012
ma_data_converter::hasPostFormatConversion
ma_bool32 hasPostFormatConversion
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2435
ma_waveform_read_pcm_frames__sine
static void ma_waveform_read_pcm_frames__sine(ma_waveform *pWaveform, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45583
ma_context_config::useVerboseDeviceEnumeration
ma_bool32 useVerboseDeviceEnumeration
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3168
ma_linear_resampler_get_required_input_frame_count
ma_uint64 ma_linear_resampler_get_required_input_frame_count(ma_linear_resampler *pResampler, ma_uint64 outputFrameCount)
ma_loshelf2_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2131
ma_pcm_u8_to_s32__reference
static MA_INLINE void ma_pcm_u8_to_s32__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28202
ma_lpf_init
ma_result ma_lpf_init(const ma_lpf_config *pConfig, ma_lpf *pLPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31004
ma_thread_create__posix
static ma_result ma_thread_create__posix(ma_thread *pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void *pData)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4453
ma_data_converter_process_pcm_frames
ma_result ma_data_converter_process_pcm_frames(ma_data_converter *pConverter, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:35303
ma_device_id::wasapi
wchar_t wasapi[64]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3057
drmp3_bool32
drmp3_uint32 drmp3_bool32
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:133
MA_NOT_CONNECTED
#define MA_NOT_CONNECTED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1706
MA_ADDRESS_FAMILY_NOT_SUPPORTED
#define MA_ADDRESS_FAMILY_NOT_SUPPORTED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1702
ma_lpf2_process_pcm_frames
ma_result ma_lpf2_process_pcm_frames(ma_lpf2 *pLPF, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30878
ma_resampler_set_rate
ma_result ma_resampler_set_rate(ma_resampler *pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33417
ma_seed
static MA_INLINE void ma_seed(ma_int32 seed)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2485
ma_allocation_callbacks
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1823
ma_biquad_process_pcm_frame_f32__direct_form_2_transposed
static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(ma_biquad *pBQ, float *pY, const float *pX)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30506
ma_device::converter
ma_data_converter converter
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3634
ma_context_uninit_backend_apis
static ma_result ma_context_uninit_backend_apis(ma_context *pContext)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26513
ma_hpf2_config_init
ma_hpf2_config ma_hpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31146
MA_REALLOC
#define MA_REALLOC(p, sz)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:730
ma_lpf1
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1893
ma_rb
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2561
ma_loshelf2_config_init
ma_loshelf2_config ma_loshelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32182
MA_TOO_BIG
#define MA_TOO_BIG
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1670
ma_context::backend
ma_backend backend
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3212
MA_DEFAULT_FORMAT
#define MA_DEFAULT_FORMAT
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:596
ma_resampler::speex
struct ma_resampler::@77::@78 speex
ma_lcg_rand_s32
static MA_INLINE ma_int32 ma_lcg_rand_s32(ma_lcg *pLCG)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2443
ma_context::pthread_cond_init
ma_proc pthread_cond_init
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3569
MA_TOO_MANY_LINKS
#define MA_TOO_MANY_LINKS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1687
ma_get_standard_channel_map_vorbis
static void ma_get_standard_channel_map_vorbis(ma_uint32 channels, ma_channel *pChannelMap)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:35908
MA_CHANNEL_AUX_16
#define MA_CHANNEL_AUX_16
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1637
ma_mix_f64
static MA_INLINE double ma_mix_f64(double x, double y, double a)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2384
ma_share_mode_exclusive
@ ma_share_mode_exclusive
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3021
ma_lpf_process_pcm_frame_s16
static MA_INLINE void ma_lpf_process_pcm_frame_s16(ma_lpf *pLPF, ma_int16 *pY, const ma_int16 *pX)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31042
ma_device_info::minSampleRate
ma_uint32 minSampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3091
ma_pcm_s16_to_s32__reference
static MA_INLINE void ma_pcm_s16_to_s32__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28566
ma_resampler_config::sampleRateIn
ma_uint32 sampleRateIn
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2244
MA_DEVICE_OP_NONE__NULL
#define MA_DEVICE_OP_NONE__NULL
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6218
g_maLCG
static ma_lcg g_maLCG
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2435
ma_lpf1_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1889
MA_DEFAULT_PLAYBACK_DEVICE_NAME
#define MA_DEFAULT_PLAYBACK_DEVICE_NAME
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5417
ma_rb__construct_offset
static MA_INLINE ma_uint32 ma_rb__construct_offset(ma_uint32 offsetInBytes, ma_uint32 offsetLoopFlag)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36356
ma_hpf1_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1949
ma_format_s24
@ ma_format_s24
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1788
ma_has_avx2
static MA_INLINE ma_bool32 ma_has_avx2(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:289
ma_linear_resampler::f32
float f32[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2213
ma_linear_resampler_config::sampleRateIn
ma_uint32 sampleRateIn
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2209
MA_CHANNEL_LFE
#define MA_CHANNEL_LFE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1606
ma_device_config::noMMap
ma_bool32 noMMap
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3151
ma_device_config::dataCallback
ma_device_callback_proc dataCallback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3110
ma_device_id::coreaudio
char coreaudio[256]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3063
ma_rb_pointer_distance
ma_int32 ma_rb_pointer_distance(ma_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36714
drmp3
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:340
ma_thread_priority_lowest
@ ma_thread_priority_lowest
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2815
ma_biquad_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1843
ma_apply_volume_factor_s32
void ma_apply_volume_factor_s32(ma_int32 *pSamples, ma_uint32 sampleCount, float factor)
ma_decoder::pData
const ma_uint8 * pData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5216
MA_UNAVAILABLE
#define MA_UNAVAILABLE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1681
ma_biquad_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1846
ma_seek_origin
ma_seek_origin
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5139
ma_device::noPreZeroedOutputBuffer
ma_bool32 noPreZeroedOutputBuffer
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3603
ma_pcm_s16_to_s24
void ma_pcm_s16_to_s24(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28541
ma_thread_result
void * ma_thread_result
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4266
ma_lpf_config::cutoffFrequency
double cutoffFrequency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1922
ma_rb_acquire_read
ma_result ma_rb_acquire_read(ma_rb *pRB, size_t *pSizeInBytes, void **ppBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36450
ma_peak2_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2102
ma_context::pthread_create
ma_proc pthread_create
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3563
ma__free_default
static void ma__free_default(void *p, void *pUserData)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1835
ma_device__read_frames_from_client
static void ma_device__read_frames_from_client(ma_device *pDevice, ma_uint32 frameCount, void *pFramesOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5736
ma_noise_read_pcm_frames
ma_uint64 ma_noise_read_pcm_frames(ma_noise *pNoise, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:46227
ma_bpf2_process_pcm_frame_f32
static MA_INLINE void ma_bpf2_process_pcm_frame_f32(ma_bpf2 *pBPF, float *pFrameOut, const float *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31723
ma_data_converter::isPassthrough
ma_bool32 isPassthrough
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2438
drwav_allocation_callbacks::onFree
void(* onFree)(void *p, void *pUserData)
Definition: porcupine/demo/c/dr_libs/dr_wav.h:414
ma_loshelf2::bq
ma_biquad bq
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2138
MA_DEFAULT_RESAMPLER_LPF_ORDER
#define MA_DEFAULT_RESAMPLER_LPF_ORDER
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:627
ma_dither_f32_triangle
static MA_INLINE float ma_dither_f32_triangle(float ditherMin, float ditherMax)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2526
ma_device::state
volatile ma_uint32 state
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3589
ma_rand_f32
static MA_INLINE float ma_rand_f32(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2505
ma_decoder_config::speex
struct ma_decoder_config::@122::@124 speex
ma_biquad_process_pcm_frame_s16__direct_form_2_transposed
static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(ma_biquad *pBQ, ma_int16 *pY, const ma_int16 *pX)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30538
ma_device_set_master_volume
ma_result ma_device_set_master_volume(ma_device *pDevice, float volume)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27617
ma_biquad::b1
ma_biquad_coefficient b1
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1862
ma_pcm_deinterleave_s16__reference
static MA_INLINE void ma_pcm_deinterleave_s16__reference(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28731
ma_device_config::noDefaultQualitySRC
ma_bool32 noDefaultQualitySRC
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3145
MA_CHANNEL_MONO
#define MA_CHANNEL_MONO
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1602
ma_encoder_init
ma_result ma_encoder_init(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void *pUserData, const ma_encoder_config *pConfig, ma_encoder *pEncoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45321
ma_device::deviceThread
ma_thread deviceThread
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3836
drwav::sampleRate
drwav_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/dr_wav.h:831
ma_decoder::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5197
ma_device_config::periodSizeInFrames
ma_uint32 periodSizeInFrames
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3104
ma_context::pthreadSO
ma_handle pthreadSO
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3562
ma_pcm_rb_acquire_write
ma_result ma_pcm_rb_acquire_write(ma_pcm_rb *pRB, ma_uint32 *pSizeInFrames, void **ppBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36893
ma_device::internalFormat
ma_format internalFormat
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3628
MA_INVALID_DEVICE_CONFIG
#define MA_INVALID_DEVICE_CONFIG
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1721
ma_decoder::outputFormat
ma_format outputFormat
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5203
drmp3_seek_to_pcm_frame
DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3 *pMP3, drmp3_uint64 frameIndex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:62199
MA_NO_MESSAGE
#define MA_NO_MESSAGE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1689
ma_lpf_reinit__internal
static ma_result ma_lpf_reinit__internal(const ma_lpf_config *pConfig, ma_lpf *pLPF, ma_bool32 isNew)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30911
ma_decoder::onSeekToPCMFrame
ma_decoder_seek_to_pcm_frame_proc onSeekToPCMFrame
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5210
MA_LCG_M
#define MA_LCG_M
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2431
ma_decoder_config::channelMixMode
ma_channel_mix_mode channelMixMode
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5176
ma_pcm_interleave_s24
MA_API void ma_pcm_interleave_s24(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29085
MA_COINIT_VALUE
#define MA_COINIT_VALUE
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:567
speex_resampler_set_rate
EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:1084
ma_stream_format
ma_stream_format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1761
ma_rb__deconstruct_offset
static MA_INLINE void ma_rb__deconstruct_offset(ma_uint32 encodedOffset, ma_uint32 *pOffsetInBytes, ma_uint32 *pOffsetLoopFlag)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36361
MA_CHANNEL_AUX_25
#define MA_CHANNEL_AUX_25
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1646
ma_decoder__on_seek_memory
static ma_bool32 ma_decoder__on_seek_memory(ma_decoder *pDecoder, ma_int64 byteOffset, ma_seek_origin origin)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43905
ma_linear_resampler::lpf
ma_lpf lpf
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2221
ma_channel_converter_process_pcm_frames__simple_shuffle
static ma_result ma_channel_converter_process_pcm_frames__simple_shuffle(ma_channel_converter *pConverter, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34105
ma_context_config::tryStartServer
ma_bool32 tryStartServer
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3184
ma_resampler_get_input_latency
ma_uint64 ma_resampler_get_input_latency(ma_resampler *pResampler)
ma_format_unknown
@ ma_format_unknown
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1785
ma_decoder_config::quality
int quality
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5187
ma_resampler_uninit
void ma_resampler_uninit(ma_resampler *pResampler)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33154
ma_context::allocationCallbacks
ma_allocation_callbacks allocationCallbacks
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3216
ma_device::noClip
ma_bool32 noClip
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3604
ma_lpf2_get_latency
ma_uint32 ma_lpf2_get_latency(ma_lpf2 *pLPF)
ma_semaphore::semaphore
sem_t semaphore
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2907
ma_dither_mode_none
@ ma_dither_mode_none
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1774
MA_PROTOCOL_FAMILY_NOT_SUPPORTED
#define MA_PROTOCOL_FAMILY_NOT_SUPPORTED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1701
ma_peak2_init
ma_result ma_peak2_init(const ma_peak2_config *pConfig, ma_peak2 *pFilter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32106
ma_peak2_process_pcm_frames
ma_result ma_peak2_process_pcm_frames(ma_peak2 *pFilter, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32158
ma_notch2_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2077
ma_pcm_rb::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2596
ma_decoder::onSeek
ma_decoder_seek_proc onSeek
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5196
ma_pcm_s24_to_f32
void ma_pcm_s24_to_f32(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29039
ma_noise::lcg
ma_lcg lcg
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5415
ma_device_info::formats
ma_format formats[ma_format_count]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3088
ma_get_standard_channel_map_rfc3551
static void ma_get_standard_channel_map_rfc3551(ma_uint32 channels, ma_channel *pChannelMap)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:35758
ma_rb::allocationCallbacks
ma_allocation_callbacks allocationCallbacks
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2575
ma_noise_config::duplicateChannels
ma_bool32 duplicateChannels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5407
ma_lpf2_process_pcm_frame_s16
static MA_INLINE void ma_lpf2_process_pcm_frame_s16(ma_lpf2 *pLPF, ma_int16 *pFrameOut, const ma_int16 *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30868
DR_WAVE_FORMAT_PCM
#define DR_WAVE_FORMAT_PCM
Definition: porcupine/demo/c/dr_libs/dr_wav.h:254
ma_loshelf2__get_biquad_config
static MA_INLINE ma_biquad_config ma_loshelf2__get_biquad_config(const ma_loshelf2_config *pConfig)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32198
ma_peak2_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2096
ma_lpf1::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1895
ma_standard_channel_map_sound4
@ ma_standard_channel_map_sound4
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1810
ma_data_converter_set_rate_ratio
ma_result ma_data_converter_set_rate_ratio(ma_data_converter *pConverter, float ratioInOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:35365
ma_standard_channel_map_alsa
@ ma_standard_channel_map_alsa
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1806
MA_CHANNEL_BACK_CENTER
#define MA_CHANNEL_BACK_CENTER
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1611
ma_decoder_init_file_vorbis
ma_result ma_decoder_init_file_vorbis(const char *pFilePath, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44707
ma_stream_format_pcm
@ ma_stream_format_pcm
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1763
ma_linear_resampler_mix_s16
static MA_INLINE ma_int16 ma_linear_resampler_mix_s16(ma_int16 x, ma_int16 y, ma_int32 a, const ma_int32 shift)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32567
ma_encoder_write_pcm_frames
ma_uint64 ma_encoder_write_pcm_frames(ma_encoder *pEncoder, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45351
ma_rand_range_f32
static MA_INLINE float ma_rand_range_f32(float lo, float hi)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2510
device
ma_device device
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/tests/test_deviceio/ma_test_deviceio.c:57
ma_apply_volume_factor_pcm_frames
void ma_apply_volume_factor_pcm_frames(void *pFrames, ma_uint32 frameCount, ma_format format, ma_uint32 channels, float factor)
MA_CHANNEL_AUX_3
#define MA_CHANNEL_AUX_3
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1624
f
f
ma_lpf1_config::cutoffFrequency
double cutoffFrequency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1890
ma_event::posix
struct ma_event::@89::@91 posix
ma_channel_mix_mode_simple
@ ma_channel_mix_mode_simple
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1797
ma_copy_and_apply_volume_factor_s24
void ma_copy_and_apply_volume_factor_s24(void *pSamplesOut, const void *pSamplesIn, ma_uint32 sampleCount, float factor)
ma_rb_get_subbuffer_offset
size_t ma_rb_get_subbuffer_offset(ma_rb *pRB, size_t subbufferIndex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36787
ma_decode_file
ma_result ma_decode_file(const char *pFilePath, ma_decoder_config *pConfig, ma_uint64 *pFrameCountOut, void **ppDataOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45067
MA_CHANNEL_SIDE_RIGHT
#define MA_CHANNEL_SIDE_RIGHT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1613
ma_pcm_interleave_f32__reference
static void ma_pcm_interleave_f32__reference(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30176
ma_is_spatial_channel_position
static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33758
MA_PI_D
#define MA_PI_D
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:584
MA_INTERRUPT
#define MA_INTERRUPT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1680
ma_calculate_frame_count_after_resampling
MA_API ma_uint64 ma_calculate_frame_count_after_resampling(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 frameCountIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4201
ma_lpf1::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1896
ma_hpf2::bq
ma_biquad bq
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1976
ma_peak2_config::gainDB
double gainDB
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2105
ma_copy_and_apply_volume_factor_s32
void ma_copy_and_apply_volume_factor_s32(ma_int32 *pSamplesOut, const ma_int32 *pSamplesIn, ma_uint32 sampleCount, float factor)
ma_scale_to_range_f32
static MA_INLINE float ma_scale_to_range_f32(float x, float lo, float hi)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2393
ma_event::_unused
int _unused
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2888
ma_rb__extract_offset_loop_flag
static MA_INLINE ma_uint32 ma_rb__extract_offset_loop_flag(ma_uint32 encodedOffset)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36339
ma_hpf1_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1957
ma_hpf_init
ma_result ma_hpf_init(const ma_hpf_config *pConfig, ma_hpf *pHPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31515
ma_device::currentPeriodFramesRemainingCapture
ma_uint32 currentPeriodFramesRemainingCapture
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3844
ma_pcm_deinterleave_f32__optimized
static void ma_pcm_deinterleave_f32__optimized(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30219
ma_decoder_seek_to_pcm_frame
ma_result ma_decoder_seek_to_pcm_frame(ma_decoder *pDecoder, ma_uint64 frameIndex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44902
ma_enum_devices_callback_proc
ma_bool32(* ma_enum_devices_callback_proc)(ma_context *pContext, ma_device_type deviceType, const ma_device_info *pInfo, void *pUserData)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3208
ma_loshelf2_reinit
ma_result ma_loshelf2_reinit(const ma_loshelf2_config *pConfig, ma_loshelf2 *pFilter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32256
ma_resampler_process_pcm_frames
ma_result ma_resampler_process_pcm_frames(ma_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33398
g_maFormatPriorities
static ma_format g_maFormatPriorities[]
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:676
MA_SAMPLE_RATE_8000
#define MA_SAMPLE_RATE_8000
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1737
ma_device::operationResult
ma_result operationResult
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3840
ma_loshelf2_config::gainDB
double gainDB
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2133
ma_speex_resampler_get_expected_output_frame_count
int ma_speex_resampler_get_expected_output_frame_count(SpeexResamplerState *st, spx_uint64_t in_len, spx_uint64_t *out_len)
ma_device::startEvent
ma_event startEvent
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3595
ma_lpf_reinit
ma_result ma_lpf_reinit(const ma_lpf_config *pConfig, ma_lpf *pLPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31019
ma_waveform::advance
double advance
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5376
ma_result_description
const char * ma_result_description(ma_result result)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37039
ma_bpf::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2053
ma_context_config::sessionCategoryOptions
ma_uint32 sessionCategoryOptions
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3179
ma_stream_layout
ma_stream_layout
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1766
ma_hpf_config_init
ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31408
ma_channel_converter_process_pcm_frames
ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter *pConverter, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34477
ma_waveform_type_sawtooth
@ ma_waveform_type_sawtooth
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5362
ma_decoder::outputChannelMap
ma_channel outputChannelMap[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5206
ma_resampler_get_output_latency
ma_uint64 ma_resampler_get_output_latency(ma_resampler *pResampler)
drwav_allocation_callbacks::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/dr_wav.h:411
ma_semaphore_init__posix
static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore *pSemaphore)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4617
ma_allocation_callbacks::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1825
ma_linear_resampler_process_pcm_frames_f32_upsample
static ma_result ma_linear_resampler_process_pcm_frames_f32_upsample(ma_linear_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32854
ma_peak2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2108
ma_lcg_rand_range_f32
static MA_INLINE float ma_lcg_rand_range_f32(ma_lcg *pLCG, float lo, float hi)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2469
MA_CHANNEL_AUX_13
#define MA_CHANNEL_AUX_13
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1634
ma_context::onDeviceStop
ma_result(* onDeviceStop)(ma_device *pDevice)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3232
ma_channel_converter_process_pcm_frames__weights
static ma_result ma_channel_converter_process_pcm_frames__weights(ma_channel_converter *pConverter, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34371
ma_context::pthread_mutex_destroy
ma_proc pthread_mutex_destroy
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3566
ma_max
#define ma_max(x, y)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:777
ma_next_power_of_2
static MA_INLINE unsigned int ma_next_power_of_2(unsigned int x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1773
MA_FAILED_TO_START_BACKEND_DEVICE
#define MA_FAILED_TO_START_BACKEND_DEVICE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1732
drwav_int32
signed int drwav_int32
Definition: porcupine/demo/c/dr_libs/dr_wav.h:138
MA_NO_NETWORK
#define MA_NO_NETWORK
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1694
ma_standard_channel_map_vorbis
@ ma_standard_channel_map_vorbis
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1809
MA_BAD_PROTOCOL
#define MA_BAD_PROTOCOL
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1698
ma_context_get_device_info
ma_result ma_context_get_device_info(ma_context *pContext, ma_device_type deviceType, const ma_device_id *pDeviceID, ma_share_mode shareMode, ma_device_info *pDeviceInfo)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26916
ma_resampler
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2260
ma_timer_get_time_in_seconds
static double ma_timer_get_time_in_seconds(ma_timer *pTimer)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5558
ma_decoder_init_flac
ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void *pUserData, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43706
ma_decoder_init_wav__internal
static ma_result ma_decoder_init_wav__internal(const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:41489
ma_lpf_config_init
ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30897
ma_path_file_name
static const char * ma_path_file_name(const char *path)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44075
ma_device_config::capture
struct ma_device_config::@98 capture
ma_thread::pContext
ma_context * pContext
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2826
MA_LOG_LEVEL_INFO
#define MA_LOG_LEVEL_INFO
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1589
ma_decoder_get_length_in_pcm_frames_proc
ma_uint64(* ma_decoder_get_length_in_pcm_frames_proc)(ma_decoder *pDecoder)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5168
ma_thread_priority
ma_thread_priority
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2812
ma_device_config::performanceProfile
ma_performance_profile performanceProfile
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3107
ma_lpf::lpf2
ma_lpf2 lpf2[MA_MAX_FILTER_ORDER/2]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1935
MA_PATH_TOO_LONG
#define MA_PATH_TOO_LONG
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1671
ma_resampler::config
ma_resampler_config config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2262
ma_noise_s16_brownian
static MA_INLINE ma_int16 ma_noise_s16_brownian(ma_noise *pNoise, ma_uint32 iChannel)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:46159
ma_path_extension
static const char * ma_path_extension(const char *path)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44130
ma_decoder__on_read_memory
static size_t ma_decoder__on_read_memory(ma_decoder *pDecoder, void *pBufferOut, size_t bytesToRead)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43886
ma_biquad_coefficient::f32
float f32
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1843
ma_lpf1::a
ma_biquad_coefficient a
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1897
ma_linear_resampler_set_rate_internal
static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler *pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_bool32 isResamplerAlreadyInitialized)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32467
ma_device::shareMode
ma_share_mode shareMode
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3621
MA_COPY_MEMORY
#define MA_COPY_MEMORY(dst, src, sz)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:754
ma_bpf_reinit
ma_result ma_bpf_reinit(const ma_bpf_config *pConfig, ma_bpf *pBPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31848
drmp3::sampleRate
drmp3_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:345
ma_decoder_init_file_vorbis_w
ma_result ma_decoder_init_file_vorbis_w(const wchar_t *pFilePath, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44734
ma_factor_to_gain_db
float ma_factor_to_gain_db(float factor)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27995
MA_CHANNEL_AUX_1
#define MA_CHANNEL_AUX_1
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1622
ma_hishelf2_get_latency
ma_uint32 ma_hishelf2_get_latency(ma_hishelf2 *pFilter)
python.setup.name
name
Definition: porcupine/binding/python/setup.py:69
ma_noise_type_pink
@ ma_noise_type_pink
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5396
ma_bpf2_config::q
double q
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2027
ma_linear_resampler_uninit
void ma_linear_resampler_uninit(ma_linear_resampler *pResampler)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32560
ma_resampler_config::linear
struct ma_resampler_config::@75 linear
ma_hpf1_config::q
double q
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1959
ma_lcg_rand_range_s32
static MA_INLINE ma_int32 ma_lcg_rand_range_s32(ma_lcg *pLCG, ma_int32 lo, ma_int32 hi)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2474
ma_context::onUninit
ma_result(* onUninit)(ma_context *pContext)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3225
ma_path_extension_w
static const wchar_t * ma_path_extension_w(const wchar_t *path)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44155
ma_encoder_init__internal
MA_API ma_result ma_encoder_init__internal(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void *pUserData, ma_encoder *pEncoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45224
ma_decoder::dataSize
size_t dataSize
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5217
ma_resampler_config_init
ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_resample_algorithm algorithm)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33078
ma_context::onDeviceMainLoop
ma_result(* onDeviceMainLoop)(ma_device *pDevice)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3233
ma_backend_dsound
@ ma_backend_dsound
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2796
ma_notch2_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2075
ma_stream_layout_interleaved
@ ma_stream_layout_interleaved
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1768
ma_context_uninit
ma_result ma_context_uninit(ma_context *pContext)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26757
MA_CHANNEL_AUX_27
#define MA_CHANNEL_AUX_27
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1648
ma_hishelf2_reinit
ma_result ma_hishelf2_reinit(const ma_hishelf2_config *pConfig, ma_hishelf2 *pFilter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32382
ma_linear_resampler::inAdvanceFrac
ma_uint32 inAdvanceFrac
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2208
ma_device_info::maxChannels
ma_uint32 maxChannels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3090
ma_pcm_rb_available_read
ma_uint32 ma_pcm_rb_available_read(ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36949
MA_MEMORY_ALREADY_MAPPED
#define MA_MEMORY_ALREADY_MAPPED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1711
ma_pcm_s16_to_u8
void ma_pcm_s16_to_u8(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28470
ma_channel_converter::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2369
ma_hpf2_process_pcm_frame_f32
static MA_INLINE void ma_hpf2_process_pcm_frame_f32(ma_hpf2 *pHPF, float *pFrameOut, const float *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31384
ma_aligned_free
void ma_aligned_free(void *p, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37171
ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others
@ ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3044
ma_mutex_unlock__posix
static void ma_mutex_unlock__posix(ma_mutex *pMutex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4559
ma_linear_resampler_config::lpfOrder
ma_uint32 lpfOrder
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2211
MA_CHANNEL_AUX_23
#define MA_CHANNEL_AUX_23
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1644
ma_linear_resampler
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2204
ma_path_file_name_w
static const wchar_t * ma_path_file_name_w(const wchar_t *path)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44102
ma_pcm_rb_commit_write
ma_result ma_pcm_rb_commit_write(ma_pcm_rb *pRB, ma_uint32 sizeInFrames, void *pBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36913
ma_encoder__on_write_pcm_frames_wav
static ma_uint64 ma_encoder__on_write_pcm_frames_wav(ma_encoder *pEncoder, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45170
ma_result
int ma_result
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1658
ma_device__on_data
static void ma_device__on_data(ma_device *pDevice, void *pFramesOut, const void *pFramesIn, ma_uint32 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5685
MA_CHANNEL_LEFT
#define MA_CHANNEL_LEFT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1653
ma_loshelf2_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2132
ma_device_config::noPreZeroedOutputBuffer
ma_bool32 noPreZeroedOutputBuffer
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3108
ma_lpf2_process_pcm_frame_f32
static MA_INLINE void ma_lpf2_process_pcm_frame_f32(ma_lpf2 *pLPF, float *pFrameOut, const float *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30873
ma_lcg_seed
static MA_INLINE void ma_lcg_seed(ma_lcg *pLCG, ma_int32 seed)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2437
drflac_int16
signed short drflac_int16
Definition: porcupine/demo/c/dr_libs/dr_flac.h:243
ma_pcm_s24_to_u8
void ma_pcm_s24_to_u8(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28815
ma_data_converter::hasChannelConverter
ma_bool32 hasChannelConverter
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2436
ma_context_config_init
ma_context_config ma_context_config_init(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26542
ma_decoder__preinit_memory
static ma_result ma_decoder__preinit_memory(const void *pData, size_t dataSize, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43958
ma_device_info::id
ma_device_id id
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3076
MA_CHANNEL_AUX_19
#define MA_CHANNEL_AUX_19
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1640
ma_pcm_rb_get_bpf
static MA_INLINE ma_uint32 ma_pcm_rb_get_bpf(ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36807
ma_lcg::state
ma_int32 state
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5390
ma_copy_and_apply_volume_factor_pcm_frames_s24
void ma_copy_and_apply_volume_factor_pcm_frames_s24(void *pPCMFramesOut, const void *pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor)
ma_biquad
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1857
drflac_open
DRFLAC_API drflac * drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void *pUserData, const drflac_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:56747
ma_decoder_init_mp3__internal
static ma_result ma_decoder_init_mp3__internal(const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:42753
ma_noise_config_init
ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels, ma_noise_type type, ma_int32 seed, double amplitude)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45801
ma_worker_thread
static ma_thread_result MA_THREADCALL ma_worker_thread(void *pData)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26273
ma_context::pthread_attr_setschedpolicy
ma_proc pthread_attr_setschedpolicy
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3575
MA_SAMPLE_RATE_16000
#define MA_SAMPLE_RATE_16000
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1739
ma_zero_pcm_frames
void ma_zero_pcm_frames(void *p, ma_uint32 frameCount, ma_format format, ma_uint32 channels)
ma_linear_resampler_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2208
ma_encoder__internal_on_write_wav
static size_t ma_encoder__internal_on_write_wav(void *pUserData, const void *pData, size_t bytesToWrite)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45104
ma_blend_f32
void ma_blend_f32(float *pOut, float *pInA, float *pInB, float factor, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37190
MA_BAD_PIPE
#define MA_BAD_PIPE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1685
ma_channel_converter::isPassthrough
ma_bool32 isPassthrough
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2380
MA_DEVICE_NOT_INITIALIZED
#define MA_DEVICE_NOT_INITIALIZED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1724
drflac_seek_origin
drflac_seek_origin
Definition: porcupine/demo/c/dr_libs/dr_flac.h:380
ma_data_converter_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2397
drflac_allocation_callbacks::onRealloc
void *(* onRealloc)(void *p, size_t sz, void *pUserData)
Definition: porcupine/demo/c/dr_libs/dr_flac.h:568
ma_event_init__posix
static ma_result ma_event_init__posix(ma_event *pEvent)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4565
ma_device_info::formatCount
ma_uint32 formatCount
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3087
ma_dither_s32
static MA_INLINE ma_int32 ma_dither_s32(ma_dither_mode ditherMode, ma_int32 ditherMin, ma_int32 ditherMax)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2545
ma_offset_ptr
#define ma_offset_ptr(p, offset)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:781
MA_IN_PROGRESS
#define MA_IN_PROGRESS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1709
ma_device::linear
struct ma_device::@114::@119 linear
ma_device_id::oss
char oss[64]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3066
ma_device_id::alsa
char alsa[256]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3060
drwav_data_format::format
drwav_uint32 format
Definition: porcupine/demo/c/dr_libs/dr_wav.h:438
ma_mutex_uninit
void ma_mutex_uninit(ma_mutex *pMutex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4784
ma_decoder_init_memory_raw
ma_result ma_decoder_init_memory_raw(const void *pData, size_t dataSize, const ma_decoder_config *pConfigIn, const ma_decoder_config *pConfigOut, ma_decoder *pDecoder)
ma_pcm_rb_reset
void ma_pcm_rb_reset(ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36855
ma_context::onDeviceInit
ma_result(* onDeviceInit)(ma_context *pContext, const ma_device_config *pConfig, ma_device *pDevice)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3229
MA_THREADCALL
#define MA_THREADCALL
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4265
ma_event_wait
MA_API ma_result ma_event_wait(ma_event *pEvent)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4898
ma_semaphore_wait__posix
static ma_result ma_semaphore_wait__posix(ma_semaphore *pSemaphore)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4651
TRUE
#define TRUE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:641
ma_context_config::alsa
struct ma_context_config::@104 alsa
ma_pcm_f32_to_u8__reference
static MA_INLINE void ma_pcm_f32_to_u8__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29494
ma_hpf1::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1963
ma_mutex_lock__posix
static void ma_mutex_lock__posix(ma_mutex *pMutex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4554
ma_lpf1_process_pcm_frame_f32
static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1 *pLPF, float *pY, const float *pX)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30710
ma_thread_entry_proc
ma_thread_result(MA_THREADCALL * ma_thread_entry_proc)(void *pData)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4268
ma_pcm_s24_to_f32__reference
static MA_INLINE void ma_pcm_s24_to_f32__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28990
drwav_data_format::channels
drwav_uint32 channels
Definition: porcupine/demo/c/dr_libs/dr_wav.h:439
ma_notch2_get_latency
ma_uint32 ma_notch2_get_latency(ma_notch2 *pFilter)
ma_standard_channel_map_microsoft
@ ma_standard_channel_map_microsoft
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1805
ma_result_from_errno
static ma_result ma_result_from_errno(int e)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1184
ma_encoder::pInternalEncoder
void * pInternalEncoder
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5333
ma_backend_winmm
@ ma_backend_winmm
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2797
ma_decoder_seek_proc
ma_bool32(* ma_decoder_seek_proc)(ma_decoder *pDecoder, int byteOffset, ma_seek_origin origin)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5164
MA_CHANNEL_AUX_4
#define MA_CHANNEL_AUX_4
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1625
ma_pcm_interleave_s32__optimized
static MA_INLINE void ma_pcm_interleave_s32__optimized(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29449
drflac_seek_origin_start
@ drflac_seek_origin_start
Definition: porcupine/demo/c/dr_libs/dr_flac.h:382
MA_DIRECTORY_NOT_EMPTY
#define MA_DIRECTORY_NOT_EMPTY
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1675
ma_dither_f32
static MA_INLINE float ma_dither_f32(ma_dither_mode ditherMode, float ditherMin, float ditherMax)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2533
ma_event_init
MA_API ma_result ma_event_init(ma_event *pEvent)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4829
ma_waveform_config::amplitude
double amplitude
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5367
ma_realloc
void * ma_realloc(void *p, size_t sz, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37126
ma_pcm_rb_get_subbuffer_stride
ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36976
MA_STATE_UNINITIALIZED
#define MA_STATE_UNINITIALIZED
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:1625
ma_device::lastProcessedFramePlayback
ma_uint64 lastProcessedFramePlayback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3845
ma_waveform_init
ma_result ma_waveform_init(const ma_waveform_config *pConfig, ma_waveform *pWaveform)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45445
drflac_read_pcm_frames_s16
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac *pFlac, drflac_uint64 framesToRead, drflac_int16 *pBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:58123
python.util.log
log
Definition: porcupine/binding/python/util.py:18
drflac_allocation_callbacks::onFree
void(* onFree)(void *p, void *pUserData)
Definition: porcupine/demo/c/dr_libs/dr_flac.h:569
ma_context_config::pApplicationName
const char * pApplicationName
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3172
ma_decoder::pInternalDecoder
void * pInternalDecoder
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5213
ma_channel_map_valid
ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS])
ma_ios_session_category_option_allow_bluetooth
@ ma_ios_session_category_option_allow_bluetooth
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3042
ma_share_mode_shared
@ ma_share_mode_shared
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3020
ma_clip_f32
static MA_INLINE float ma_clip_f32(float x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2339
ma_device_config
struct ma_device_config ma_device_config
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:1898
RESAMPLER_ERR_PTR_OVERLAP
@ RESAMPLER_ERR_PTR_OVERLAP
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/speex_resampler.h:108
ma_resampler_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2243
MA_CHANNEL_TOP_BACK_RIGHT
#define MA_CHANNEL_TOP_BACK_RIGHT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1620
ma_resampler_process_pcm_frames__seek
static ma_result ma_resampler_process_pcm_frames__seek(ma_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33369
ma_device__send_frames_to_client
static void ma_device__send_frames_to_client(ma_device *pDevice, ma_uint32 frameCountInDeviceFormat, const void *pFramesInDeviceFormat)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5801
ma_biquad_reinit
ma_result ma_biquad_reinit(const ma_biquad_config *pConfig, ma_biquad *pBQ)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30459
ma_hpf::hpf1Count
ma_uint32 hpf1Count
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2000
SpeexResamplerState_
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:116
ma_device_info::maxSampleRate
ma_uint32 maxSampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3092
ma_context::threadPriority
ma_thread_priority threadPriority
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3214
ma_hpf1_config::cutoffFrequency
double cutoffFrequency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1958
ma_copy_and_apply_volume_factor_u8
void ma_copy_and_apply_volume_factor_u8(ma_uint8 *pSamplesOut, const ma_uint8 *pSamplesIn, ma_uint32 sampleCount, float factor)
MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY
#define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:616
ma_waveform_config::frequency
double frequency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5368
ma_noise_f32_white
static MA_INLINE float ma_noise_f32_white(ma_noise *pNoise)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45953
ma_context_init_backend_apis__nix
static ma_result ma_context_init_backend_apis__nix(ma_context *pContext)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26440
ma_dlopen
MA_API ma_handle ma_dlopen(ma_context *pContext, const char *filename)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5580
ma_rb_available_write
ma_uint32 ma_rb_available_write(ma_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36756
ma__free_from_callbacks
static void ma__free_from_callbacks(void *p, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1900
ma_waveform_square_f32
static float ma_waveform_square_f32(double time, double amplitude)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45534
ma_channel_converter_config::channelsOut
ma_uint32 channelsOut
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2362
ma_hishelf2::bq
ma_biquad bq
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2166
ma_linear_resampler_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2192
ma_strcat_s
MA_API int ma_strcat_s(char *dst, size_t dstSizeInBytes, const char *src)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:959
ma_post_log_message
static void ma_post_log_message(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel, const char *message)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5422
ma_mix_f32
static MA_INLINE float ma_mix_f32(float x, float y, float a)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2346
MA_CHANNEL_FRONT_RIGHT_CENTER
#define MA_CHANNEL_FRONT_RIGHT_CENTER
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1610
ma_waveform_triangle_s16
static ma_int16 ma_waveform_triangle_s16(double time, double amplitude)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45563
ma_noise_config::type
ma_noise_type type
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5404
ma_encoder::pFile
void * pFile
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5334
ma_pcm_interleave_f32__optimized
static void ma_pcm_interleave_f32__optimized(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30190
ma_encoder_write_pcm_frames_proc
ma_uint64(* ma_encoder_write_pcm_frames_proc)(ma_encoder *pEncoder, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5311
ma_encoder_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5318
ma_decoder_config::ditherMode
ma_dither_mode ditherMode
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5177
MA_CHANNEL_TOP_FRONT_CENTER
#define MA_CHANNEL_TOP_FRONT_CENTER
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1616
ma_backend_coreaudio
@ ma_backend_coreaudio
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2798
ma_noise_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5403
drwav_init
DRWAV_API drwav_bool32 drwav_init(drwav *pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void *pUserData, const drwav_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:47795
MA_TIMEOUT
#define MA_TIMEOUT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1693
speex_resampler_process_interleaved_float
EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:1038
ma_device_config::lpfOrder
ma_uint32 lpfOrder
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3118
ma_get_bytes_per_sample
ma_uint32 ma_get_bytes_per_sample(ma_format format)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37199
ma_decoder_init_memory
ma_result ma_decoder_init_memory(const void *pData, size_t dataSize, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43977
ma_peak2__get_biquad_config
static MA_INLINE ma_biquad_config ma_peak2__get_biquad_config(const ma_peak2_config *pConfig)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32074
ma_context_enumerate_devices__null
static ma_result ma_context_enumerate_devices__null(ma_context *pContext, ma_enum_devices_callback_proc callback, void *pUserData)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6333
MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE
#define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:621
ma_bpf_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2043
ma_device_config::pStreamNamePlayback
const char * pStreamNamePlayback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3155
ma_peak2_config_init
ma_peak2_config ma_peak2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32054
ma_hpf1_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1955
ma_noise::config
ma_noise_config config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5414
ma_event::mutex
pthread_mutex_t mutex
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2883
MA_NAME_TOO_LONG
#define MA_NAME_TOO_LONG
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1672
count
size_t count
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/tests/test_common/ma_test_common.c:31
ma_hishelf2_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2158
ma_lpf_process_pcm_frame_f32
static MA_INLINE void ma_lpf_process_pcm_frame_f32(ma_lpf *pLPF, float *pY, const void *pX)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31024
ma_context::pthread_attr_getschedparam
ma_proc pthread_attr_getschedparam
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3576
ma_peak2_process_pcm_frame_s16
static MA_INLINE void ma_peak2_process_pcm_frame_s16(ma_peak2 *pFilter, ma_int16 *pFrameOut, const ma_int16 *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32148
ma_lpf::lpf1
ma_lpf1 lpf1[1]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1934
MA_CHANNEL_AUX_2
#define MA_CHANNEL_AUX_2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1623
ma_encoder_uninit
void ma_encoder_uninit(ma_encoder *pEncoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45334
ma_is_big_endian
static MA_INLINE ma_bool32 ma_is_big_endian(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:455
ma_waveform_type_triangle
@ ma_waveform_type_triangle
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5361
MA_CHANNEL_AUX_26
#define MA_CHANNEL_AUX_26
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1647
MA_LCG_A
#define MA_LCG_A
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2432
ma_bpf_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2042
ma_rb_seek_read
ma_result ma_rb_seek_read(ma_rb *pRB, size_t offsetInBytes)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36626
ma_lpf_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1917
ma_device_do_operation__null
static ma_result ma_device_do_operation__null(ma_device *pDevice, ma_uint32 operation)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6283
ma_noise_f32_pink
static MA_INLINE float ma_noise_f32_pink(ma_noise *pNoise, ma_uint32 iChannel)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:46055
ma_data_converter_get_expected_output_frame_count
ma_uint64 ma_data_converter_get_expected_output_frame_count(ma_data_converter *pConverter, ma_uint64 inputFrameCount)
MA_IS_DIRECTORY
#define MA_IS_DIRECTORY
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1674
ma_semaphore_uninit
MA_API void ma_semaphore_uninit(ma_semaphore *pSemaphore)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4944
ma_lpf_config::order
ma_uint32 order
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1923
ma_decoder::internalFormat
ma_format internalFormat
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5199
ma_device_get_total_run_time_in_frames__null
static ma_uint64 ma_device_get_total_run_time_in_frames__null(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6321
ma_biquad::b2
ma_biquad_coefficient b2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1863
drwav_read_pcm_frames_s32
DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav *pWav, drwav_uint64 framesToRead, drwav_int32 *pBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:50607
ma_linear_resampler_set_rate_ratio
ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler *pResampler, float ratioInOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32963
ma_device::usingDefaultSampleRate
ma_bool32 usingDefaultSampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3599
ma_noise_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5402
ma_data_converter_process_pcm_frames__resample_only
static ma_result ma_data_converter_process_pcm_frames__resample_only(ma_data_converter *pConverter, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34885
ma_thread::thread
pthread_t thread
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2839
ma_context::pthread_cond_wait
ma_proc pthread_cond_wait
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3571
ma_waveform::config
ma_waveform_config config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5375
ma_encoder
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5324
ma_loshelf2_process_pcm_frame_f32
static MA_INLINE void ma_loshelf2_process_pcm_frame_f32(ma_loshelf2 *pFilter, float *pFrameOut, const float *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32279
ma_biquad_process_pcm_frame_f32
static MA_INLINE void ma_biquad_process_pcm_frame_f32(ma_biquad *pBQ, float *pY, const float *pX)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30533
ma_strcpy_s
MA_API int ma_strcpy_s(char *dst, size_t dstSizeInBytes, const char *src)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:868
ma_format_s16
@ ma_format_s16
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1787
MA_PROTOCOL_UNAVAILABLE
#define MA_PROTOCOL_UNAVAILABLE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1699
ma_hpf_reinit__internal
static ma_result ma_hpf_reinit__internal(const ma_hpf_config *pConfig, ma_hpf *pHPF, ma_bool32 isNew)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31422
ma_thread_wait
static void ma_thread_wait(ma_thread *pThread)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4754
ma_rb_get_subbuffer_stride
size_t ma_rb_get_subbuffer_stride(ma_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36774
ma_decoder_init_memory_flac
ma_result ma_decoder_init_memory_flac(const void *pData, size_t dataSize, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44010
ma_device_id::sndio
char sndio[256]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3064
MA_CHANNEL_AUX_5
#define MA_CHANNEL_AUX_5
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1626
ma_notch2_config::frequency
double frequency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2079
ma_device_info
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3073
ma_device_set_master_gain_db
ma_result ma_device_set_master_gain_db(ma_device *pDevice, float gainDB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27648
ma_ios_session_category_play_and_record
@ ma_ios_session_category_play_and_record
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3033
ma_pcm_u8_to_u8
MA_API void ma_pcm_u8_to_u8(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28063
ma_device::operation
ma_uint32 operation
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3839
ma_noise_f32_brownian
static MA_INLINE float ma_noise_f32_brownian(ma_noise *pNoise, ma_uint32 iChannel)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:46146
ma_linear_resampler_process_pcm_frames_f32
static ma_result ma_linear_resampler_process_pcm_frames_f32(ma_linear_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32928
ma_noise_init
ma_result ma_noise_init(const ma_noise_config *pConfig, ma_noise *pNoise)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45865
ma_hpf_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1987
ma_channel_map_contains_channel_position
ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel channelMap[MA_MAX_CHANNELS], ma_channel channelPosition)
ma_hpf1_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1956
MA_LOG_LEVEL_WARNING
#define MA_LOG_LEVEL_WARNING
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1590
MA_DOES_NOT_EXIST
#define MA_DOES_NOT_EXIST
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1666
ma_hpf2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1974
ma_decoder_seek_to_pcm_frame_proc
ma_result(* ma_decoder_seek_to_pcm_frame_proc)(ma_decoder *pDecoder, ma_uint64 frameIndex)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5166
ma_device::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3592
ma_linear_resampler::x0
union ma_linear_resampler::@73 x0
ma_device::thread
ma_thread thread
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3597
ma_loshelf2_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2124
d
d
ma_bpf2__get_biquad_config
static MA_INLINE ma_biquad_config ma_bpf2__get_biquad_config(const ma_bpf2_config *pConfig)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31646
ma_encoder::onInit
ma_encoder_init_proc onInit
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5329
ma_encoder::onWrite
ma_encoder_write_proc onWrite
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5327
ma_data_converter_config::sampleRateIn
ma_uint32 sampleRateIn
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2407
ma_dither_f32_rectangle
static MA_INLINE float ma_dither_f32_rectangle(float ditherMin, float ditherMax)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2521
ma_device_id::opensl
ma_uint32 opensl
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3068
ma_rand_u32
static MA_INLINE ma_uint32 ma_rand_u32(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2495
ma_device_id
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3055
ma_bpf::bpf2
ma_bpf2 bpf2[MA_MAX_FILTER_ORDER/2]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2055
ma_decoder_read_pcm_frames_proc
ma_uint64(* ma_decoder_read_pcm_frames_proc)(ma_decoder *pDecoder, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5165
ma_resampler_config::lpfOrder
ma_uint32 lpfOrder
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2249
MA_SIMD_ALIGNMENT
#define MA_SIMD_ALIGNMENT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1584
ma_pcm_sample_f32_to_s16
static MA_INLINE ma_int16 ma_pcm_sample_f32_to_s16(float x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28012
ma_decoder::internalChannelMap
ma_channel internalChannelMap[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5202
ma_device_config::algorithm
ma_resample_algorithm algorithm
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3115
ma_data_converter::config
ma_data_converter_config config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2431
ma_device_get_master_gain_db
ma_result ma_device_get_master_gain_db(ma_device *pDevice, float *pGainDB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27657
ma_pcm_s24_to_s16__optimized
static MA_INLINE void ma_pcm_s24_to_s16__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28871
ma_device::onData
ma_device_callback_proc onData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3590
ma_mutex_init__posix
static ma_result ma_mutex_init__posix(ma_mutex *pMutex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4539
ma_mix_f64_fast
static MA_INLINE double ma_mix_f64_fast(double x, double y, double a)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2388
ma_encoder_uninit_proc
void(* ma_encoder_uninit_proc)(ma_encoder *pEncoder)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5310
ma_device::channelMap
ma_channel channelMap[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3627
python.setup.description
description
Definition: porcupine/binding/python/setup.py:73
ma_decoder_config::channelMap
ma_channel channelMap[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5175
ma_get_standard_channel_map
void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel channelMap[MA_MAX_CHANNELS])
ma_data_converter_config::channelWeights
float channelWeights[MA_MAX_CHANNELS][MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2413
MA_CHANNEL_AUX_14
#define MA_CHANNEL_AUX_14
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1635
ma_pcm_u8_to_s16__optimized
static MA_INLINE void ma_pcm_u8_to_s16__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28086
ma_ios_session_category_option_duck_others
@ ma_ios_session_category_option_duck_others
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3041
ma_gcf_u32
static MA_INLINE ma_uint32 ma_gcf_u32(ma_uint32 a, ma_uint32 b)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2402
ma_wfopen
MA_API ma_result ma_wfopen(FILE **ppFile, const wchar_t *pFilePath, const wchar_t *pOpenMode, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1648
MA_SHARE_MODE_NOT_SUPPORTED
#define MA_SHARE_MODE_NOT_SUPPORTED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1717
ma_notch2_config_init
ma_notch2_config ma_notch2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31928
ma_context_is_backend_asynchronous
static ma_bool32 ma_context_is_backend_asynchronous(ma_context *pContext)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26526
ma_pcm_interleave_s24__reference
static MA_INLINE void ma_pcm_interleave_s24__reference(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29064
ma_device_init__null
static ma_result ma_device_init__null(ma_device *pDevice, const ma_device_config *pConfig, ma_device_descriptor *pDescriptorPlayback, ma_device_descriptor *pDescriptorCapture)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6410
stb_vorbis_open_pushdata
stb_vorbis * stb_vorbis_open_pushdata(const unsigned char *datablock, int datablock_length_in_bytes, int *datablock_memory_consumed_in_bytes, int *error, const stb_vorbis_alloc *alloc_buffer)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:4489
drmp3_seek_origin
drmp3_seek_origin
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:284
ma_encoder__on_write_stdio
MA_API size_t ma_encoder__on_write_stdio(ma_encoder *pEncoder, const void *pBufferIn, size_t bytesToWrite)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45269
ma_pcm_s32_to_f32__reference
static MA_INLINE void ma_pcm_s32_to_f32__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29363
ma_encoder_config::resourceFormat
ma_resource_format resourceFormat
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5315
MA_DEVICE_ALREADY_INITIALIZED
#define MA_DEVICE_ALREADY_INITIALIZED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1725
ma_encoder_init_file
ma_result ma_encoder_init_file(const char *pFilePath, const ma_encoder_config *pConfig, ma_encoder *pEncoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45279
ma_pcm_u8_to_s24
void ma_pcm_u8_to_s24(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28177
ma_thread_priority_idle
@ ma_thread_priority_idle
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2814
ma_decoder::converter
ma_data_converter converter
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5207
ma_encoder_config_init
ma_encoder_config ma_encoder_config_init(ma_resource_format resourceFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45183
ma_timer_init
static void ma_timer_init(ma_timer *pTimer)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5550
ma_decoder_seek_bytes
static ma_result ma_decoder_seek_bytes(ma_decoder *pDecoder, ma_int64 byteOffset, ma_seek_origin origin)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:40609
MA_INVALID_OPERATION
#define MA_INVALID_OPERATION
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1662
ma_pcm_s32_to_s32
MA_API void ma_pcm_s32_to_s32(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29355
ma_decoder__init_data_converter
static ma_result ma_decoder__init_data_converter(ma_decoder *pDecoder, const ma_decoder_config *pConfig)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:40680
ma_lpf1::r1
ma_biquad_coefficient r1[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1898
ma_get_standard_channel_map_alsa
static void ma_get_standard_channel_map_alsa(ma_uint32 channels, ma_channel *pChannelMap)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:35671
ma_get_standard_channel_map_sndio
static void ma_get_standard_channel_map_sndio(ma_uint32 channels, ma_channel *pChannelMap)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36083
ma_decoder
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5193
ma_pcm_interleave_u8__optimized
static MA_INLINE void ma_pcm_interleave_u8__optimized(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28348
ma_decoder__full_decode_and_uninit
static ma_result ma_decoder__full_decode_and_uninit(ma_decoder *pDecoder, ma_decoder_config *pConfigOut, ma_uint64 *pFrameCountOut, void **ppPCMFramesOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44965
drflac_bool32
drflac_uint32 drflac_bool32
Definition: porcupine/demo/c/dr_libs/dr_flac.h:270
ma_device_write__null
static ma_result ma_device_write__null(ma_device *pDevice, const void *pPCMFrames, ma_uint32 frameCount, ma_uint32 *pFramesWritten)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6494
ma_scale_buffer_size
ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27755
drflac_allocation_callbacks
Definition: porcupine/demo/c/dr_libs/dr_flac.h:564
ma_get_standard_channel_map_flac
static void ma_get_standard_channel_map_flac(ma_uint32 channels, ma_channel *pChannelMap)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:35821
ma_decoder_init_vorbis
ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void *pUserData, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43744
ma_decoder_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5172
ma_copy_and_apply_volume_factor_s16
void ma_copy_and_apply_volume_factor_s16(ma_int16 *pSamplesOut, const ma_int16 *pSamplesIn, ma_uint32 sampleCount, float factor)
ma_noise::state
union ma_noise::@126 state
L
#define L
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:5102
ma_context::pthread_attr_destroy
ma_proc pthread_attr_destroy
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3574
MA_ASSERT
#define MA_ASSERT(condition)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:770
ma_pcm_convert
void ma_pcm_convert(void *pOut, ma_format formatOut, const void *pIn, ma_format formatIn, ma_uint64 sampleCount, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30234
ma_encoder__on_seek_stdio
MA_API ma_bool32 ma_encoder__on_seek_stdio(ma_encoder *pEncoder, int byteOffset, ma_seek_origin origin)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45274
ma_noise::pink
struct ma_noise::@126::@127 pink
ma_pcm_deinterleave_s24__reference
static MA_INLINE void ma_pcm_deinterleave_s24__reference(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29095
ma_decoder_init_mp3
ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void *pUserData, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43725
ma_apply_volume_factor_s24
void ma_apply_volume_factor_s24(void *pSamples, ma_uint32 sampleCount, float factor)
MA_MAX_SAMPLE_RATE
#define MA_MAX_SAMPLE_RATE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1755
ma_linear_resampler_get_input_latency
ma_uint64 ma_linear_resampler_get_input_latency(ma_linear_resampler *pResampler)
ma_bpf2_get_latency
ma_uint32 ma_bpf2_get_latency(ma_bpf2 *pBPF)
ma_resampler_get_required_input_frame_count
ma_uint64 ma_resampler_get_required_input_frame_count(ma_resampler *pResampler, ma_uint64 outputFrameCount)
ma_context::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3215
ma_ios_session_category
ma_ios_session_category
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3025
stb_vorbis
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:768
ma_decoder_read_proc
size_t(* ma_decoder_read_proc)(ma_decoder *pDecoder, void *pBufferOut, size_t bytesToRead)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5163
ma_data_converter_config::allowDynamicSampleRate
ma_bool32 allowDynamicSampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2417
ma_pcm_s32_to_s16__reference
static MA_INLINE void ma_pcm_s32_to_s16__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29210
drwav_data_format::container
drwav_container container
Definition: porcupine/demo/c/dr_libs/dr_wav.h:437
drwav_int16
signed short drwav_int16
Definition: porcupine/demo/c/dr_libs/dr_wav.h:136
ma_waveform_config_init
ma_waveform_config ma_waveform_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_waveform_type type, double amplitude, double frequency)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45369
ma_notch2_process_pcm_frame_f32
static MA_INLINE void ma_notch2_process_pcm_frame_f32(ma_notch2 *pFilter, float *pFrameOut, const float *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32024
ma_channel_converter_config::channelMapIn
ma_channel channelMapIn[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2363
ma_waveform_sawtooth_f32
static float ma_waveform_sawtooth_f32(double time, double amplitude)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45568
speex_resampler_process_interleaved_int
EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:1061
ma_channel_converter_process_pcm_frames__passthrough
static ma_result ma_channel_converter_process_pcm_frames__passthrough(ma_channel_converter *pConverter, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34095
ma_log
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:588
ma_pcm_deinterleave_u8__optimized
static MA_INLINE void ma_pcm_deinterleave_u8__optimized(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28397
ma_copy_and_apply_volume_factor_pcm_frames_u8
void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8 *pPCMFramesOut, const ma_uint8 *pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor)
ma_pcm_interleave_u8
MA_API void ma_pcm_interleave_u8(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28373
ma_decoder_init_file_mp3
ma_result ma_decoder_init_file_mp3(const char *pFilePath, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44702
drwav_container_riff
@ drwav_container_riff
Definition: porcupine/demo/c/dr_libs/dr_wav.h:276
ma_waveform_square_s16
static ma_int16 ma_waveform_square_s16(double time, double amplitude)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45548
ma_pcm_s24_to_s32
void ma_pcm_s24_to_s32(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28965
ma_device__set_state
static MA_INLINE void ma_device__set_state(ma_device *pDevice, ma_uint32 newState)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5981
ma_context::captureDeviceInfoCount
ma_uint32 captureDeviceInfoCount
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3221
MA_CHANNEL_RIGHT
#define MA_CHANNEL_RIGHT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1654
MA_ALREADY_IN_USE
#define MA_ALREADY_IN_USE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1682
ma_bpf_config::order
ma_uint32 order
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2045
ma_pcm_s24_to_u8__optimized
static MA_INLINE void ma_pcm_s24_to_u8__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28791
ma_device_info::name
char name[256]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3077
ma_int32
int32_t ma_int32
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1502
ma_linear_resampler_interpolate_frame_s16
static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler *pResampler, ma_int16 *MA_RESTRICT pFrameOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32582
ma_decoder::internalChannels
ma_uint32 internalChannels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5200
drmp3_allocation_callbacks::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:328
ma_linear_resampler_set_rate
ma_result ma_linear_resampler_set_rate(ma_linear_resampler *pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32958
ma_context::deviceEnumLock
ma_mutex deviceEnumLock
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3217
RESAMPLER_ERR_OVERFLOW
@ RESAMPLER_ERR_OVERFLOW
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/speex_resampler.h:109
ma_rb_acquire_write
ma_result ma_rb_acquire_write(ma_rb *pRB, size_t *pSizeInBytes, void **ppBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36535
MA_DEFAULT_PERIODS
#define MA_DEFAULT_PERIODS
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:611
MA_DEADLOCK
#define MA_DEADLOCK
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1686
MA_CHANNEL_FRONT_LEFT_CENTER
#define MA_CHANNEL_FRONT_LEFT_CENTER
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1609
ma_pcm_f32_to_s16
void ma_pcm_f32_to_s16(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29989
ma_event
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2868
ma_pcm_s16_to_s32
void ma_pcm_s16_to_s32(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28603
ma_pcm_f32_to_s24__reference
static MA_INLINE void ma_pcm_f32_to_s24__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30014
ma_data_converter_config::channelMapOut
ma_channel channelMapOut[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2410
MA_CHANNEL_AUX_22
#define MA_CHANNEL_AUX_22
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1643
ma_data_converter_config::algorithm
ma_resample_algorithm algorithm
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2416
MA_NOT_SOCKET
#define MA_NOT_SOCKET
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1696
ma_timer
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3049
ma_mutex_init
ma_result ma_mutex_init(ma_context *pContext, ma_mutex *pMutex)
MA_LOG_LEVEL_VERBOSE
#define MA_LOG_LEVEL_VERBOSE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1588
ma_waveform_read_pcm_frames__sawtooth
static void ma_waveform_read_pcm_frames__sawtooth(ma_waveform *pWaveform, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45709
ma_bpf_config::cutoffFrequency
double cutoffFrequency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2044
ma_context::logCallback
ma_log_proc logCallback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3213
ma_convert_frames_ex
ma_uint64 ma_convert_frames_ex(void *pOut, ma_uint64 frameCountOut, const void *pIn, ma_uint64 frameCountIn, const ma_data_converter_config *pConfig)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36301
ma_pcm_s24_to_s16__reference
static MA_INLINE void ma_pcm_s24_to_s16__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28840
ma_hishelf2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2164
MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT
#define MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33626
MA_NO_BACKEND
#define MA_NO_BACKEND
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1718
ma_pcm_rb_get_subbuffer_offset
ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb *pRB, ma_uint32 subbufferIndex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36985
ma_thread_priority_high
@ ma_thread_priority_high
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2818
MA_ALREADY_CONNECTED
#define MA_ALREADY_CONNECTED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1705
ma_context_get_devices
ma_result ma_context_get_devices(ma_context *pContext, ma_device_info **ppPlaybackDeviceInfos, ma_uint32 *pPlaybackDeviceCount, ma_device_info **ppCaptureDeviceInfos, ma_uint32 *pCaptureDeviceCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26866
ma_standard_channel_map_webaudio
@ ma_standard_channel_map_webaudio
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1812
ma_context::onDeviceStart
ma_result(* onDeviceStart)(ma_device *pDevice)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3231
ma_linear_resampler_process_pcm_frames_s16
static ma_result ma_linear_resampler_process_pcm_frames_s16(ma_linear_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32768
ma_device__is_initialized
static ma_bool32 ma_device__is_initialized(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26366
MA_AT_END
#define MA_AT_END
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1712
g_maChannelPlaneRatios
static float g_maChannelPlaneRatios[MA_CHANNEL_POSITION_COUNT][6]
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33636
ma_performance_profile
ma_performance_profile
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1816
ma_waveform_type_sine
@ ma_waveform_type_sine
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5359
ma_data_converter_set_rate
ma_result ma_data_converter_set_rate(ma_data_converter *pConverter, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:35352
ma_mutex
pthread_mutex_t ma_mutex
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:512
ma_ios_session_category_multi_route
@ ma_ios_session_category_multi_route
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3034
ma_device_callback_proc
void(* ma_device_callback_proc)(ma_device *pDevice, void *pOutput, const void *pInput, ma_uint32 frameCount)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2955
ma_rb_get_subbuffer_ptr
void * ma_rb_get_subbuffer_ptr(ma_rb *pRB, size_t subbufferIndex, void *pBuffer)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36796
ma_rb_seek_write
ma_result ma_rb_seek_write(ma_rb *pRB, size_t offsetInBytes)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36670
RESAMPLER_ERR_BAD_STATE
@ RESAMPLER_ERR_BAD_STATE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/speex_resampler.h:106
ma_data_converter_process_pcm_frames__resampling_first
static ma_result ma_data_converter_process_pcm_frames__resampling_first(ma_data_converter *pConverter, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:35017
ma_linear_resampler_config::lpfNyquistFactor
double lpfNyquistFactor
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2212
ma_pcm_f32_to_s24
void ma_pcm_f32_to_s24(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30068
ma_channel_map_copy
void ma_channel_map_copy(ma_channel *pOut, const ma_channel *pIn, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36190
ma_resampler_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2240
ai
ma_device::usingDefaultChannels
ma_bool32 usingDefaultChannels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3623
drmp3_config::outputSampleRate
drmp3_uint32 outputSampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/dr_mp3.h:317
ma_device_config::periodSizeInMilliseconds
ma_uint32 periodSizeInMilliseconds
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3105
ma_notch2_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2069
ma_pcm_deinterleave_s24
MA_API void ma_pcm_deinterleave_s24(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29116
MA_CHANNEL_AUX_28
#define MA_CHANNEL_AUX_28
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1649
MA_CHANNEL_AUX_8
#define MA_CHANNEL_AUX_8
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1629
ma_resampler_get_expected_output_frame_count
ma_uint64 ma_resampler_get_expected_output_frame_count(ma_resampler *pResampler, ma_uint64 inputFrameCount)
drwav_data_format::bitsPerSample
drwav_uint32 bitsPerSample
Definition: porcupine/demo/c/dr_libs/dr_wav.h:441
ma_bpf_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2039
ma_device_is_started
ma_bool32 ma_device_is_started(ma_device *pDevice)
drwav::channels
drwav_uint16 channels
Definition: porcupine/demo/c/dr_libs/dr_wav.h:834
ma_linear_resampler_process_pcm_frames_f32_downsample
static ma_result ma_linear_resampler_process_pcm_frames_f32_downsample(ma_linear_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32780
ma_semaphore_wait
MA_API ma_result ma_semaphore_wait(ma_semaphore *pSemaphore)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4959
MA_CONNECTION_RESET
#define MA_CONNECTION_RESET
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1704
ma_pcm_deinterleave_s24__optimized
static MA_INLINE void ma_pcm_deinterleave_s24__optimized(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29111
drwav_uninit
DRWAV_API drwav_result drwav_uninit(drwav *pWav)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:49216
ma_data_converter_config::speex
struct ma_data_converter_config::@80::@82 speex
ma_clamp
#define ma_clamp(x, lo, hi)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:780
ma_noise::brownian
struct ma_noise::@126::@128 brownian
python.pvrecorder.CALLBACK
CALLBACK
Definition: porcupine/demo/c/pvrecorder/sdk/python/pvrecorder.py:17
ma_context::posix
struct ma_context::@110::@113 posix
ppnrespeakerdemo.porcupine_demo.driver
driver
Definition: porcupine_demo.py:47
ma_standard_channel_map
ma_standard_channel_map
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1803
ma_device::internalSampleRate
ma_uint32 internalSampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3630
ma_bpf::bpf2Count
ma_uint32 bpf2Count
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2054
ma_backend_sndio
@ ma_backend_sndio
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2799
ma_hpf
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1996
ma_decoder__postinit
static ma_result ma_decoder__postinit(const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43659
ma_lpf_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1919
ma_rb::encodedWriteOffset
volatile ma_uint32 encodedWriteOffset
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2572
ma_device::name
char name[256]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3620
ma_device::quality
int quality
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3615
stb_vorbis_info::sample_rate
unsigned int sample_rate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:126
ma_decoder::currentReadPos
size_t currentReadPos
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5218
ma_pcm_s32_to_s24
void ma_pcm_s32_to_s24(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29330
DR_WAVE_FORMAT_DVI_ADPCM
#define DR_WAVE_FORMAT_DVI_ADPCM
Definition: porcupine/demo/c/dr_libs/dr_wav.h:259
ma_biquad::a2
ma_biquad_coefficient a2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1865
ma_context_enumerate_devices
ma_result ma_context_enumerate_devices(ma_context *pContext, ma_enum_devices_callback_proc callback, void *pUserData)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26795
ma_uint32
uint32_t ma_uint32
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1503
ma_rand_s32
static MA_INLINE ma_int32 ma_rand_s32(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2490
ma_hpf1_reinit
ma_result ma_hpf1_reinit(const ma_hpf1_config *pConfig, ma_hpf1 *pHPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31185
ma_encoder__on_uninit_wav
static void ma_encoder__on_uninit_wav(ma_encoder *pEncoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45157
ma_bpf
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2050
ma_pcm_interleave_f32
MA_API void ma_pcm_interleave_f32(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30195
ma_bpf2_process_pcm_frame_s16
static MA_INLINE void ma_bpf2_process_pcm_frame_s16(ma_bpf2 *pBPF, ma_int16 *pFrameOut, const ma_int16 *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31718
ma_log_proc
void(* ma_log_proc)(ma_context *pContext, ma_device *pDevice, ma_uint32 logLevel, const char *message)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3008
ma_bpf_reinit__internal
static ma_result ma_bpf_reinit__internal(const ma_bpf_config *pConfig, ma_bpf *pBPF, ma_bool32 isNew)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31761
ma_apply_volume_factor_u8
void ma_apply_volume_factor_u8(ma_uint8 *pSamples, ma_uint32 sampleCount, float factor)
ma_waveform
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5373
ma_context_config::logCallback
ma_log_proc logCallback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3162
drmp3_allocation_callbacks
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:326
MA_NO_HOST
#define MA_NO_HOST
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1708
ma_context_config::pServerName
const char * pServerName
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3173
ma_decoder__init_allocation_callbacks
static ma_result ma_decoder__init_allocation_callbacks(const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43547
ma_resampler_process_pcm_frames__seek__linear
static ma_result ma_resampler_process_pcm_frames__seek__linear(ma_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33286
ma_apply_volume_factor_f32
void ma_apply_volume_factor_f32(float *pSamples, ma_uint32 sampleCount, float factor)
ma_device::duplexRB
ma_duplex_rb duplexRB
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:2626
ma__realloc_default
static void * ma__realloc_default(void *p, size_t sz, void *pUserData)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1829
ma_encoder::onSeek
ma_encoder_seek_proc onSeek
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5328
ma_linear_resampler::inTimeFrac
ma_uint32 inTimeFrac
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2210
MA_STATE_STOPPED
#define MA_STATE_STOPPED
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:1626
ma_pcm_s24_to_f32__optimized
static MA_INLINE void ma_pcm_s24_to_f32__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29015
ma_waveform_sawtooth_s16
static ma_int16 ma_waveform_sawtooth_s16(double time, double amplitude)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45578
ma_context_uninit__null
static ma_result ma_context_uninit__null(ma_context *pContext)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6645
ma_device::priorRunTime
double priorRunTime
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3842
MA_SIZE_MAX
#define MA_SIZE_MAX
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1549
ma_pcm_f32_to_s32
void ma_pcm_f32_to_s32(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30143
ma_device_id::winmm
ma_uint32 winmm
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3059
ma_tzcnt32
static MA_INLINE unsigned int ma_tzcnt32(unsigned int x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:46027
ma__is_channel_map_valid
static ma_bool32 ma__is_channel_map_valid(const ma_channel *channelMap, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26141
ma_format_u8
@ ma_format_u8
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1786
ma_allocation_callbacks_init_copy
static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks *pDst, const ma_allocation_callbacks *pSrc)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1922
ma_bpf_get_latency
ma_uint32 ma_bpf_get_latency(ma_bpf *pBPF)
ma_channel_mix_mode_default
@ ma_channel_mix_mode_default
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1800
ma_loshelf2_config::frequency
double frequency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2135
ma_lcg_rand_f32
static MA_INLINE float ma_lcg_rand_f32(ma_lcg *pLCG)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2464
ma_device_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3128
ma_pcm_rb
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2593
drflac_read_pcm_frames_s32
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac *pFlac, drflac_uint64 framesToRead, drflac_int32 *pBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:57386
ma_decoder_read_pcm_frames
ma_uint64 ma_decoder_read_pcm_frames(ma_decoder *pDecoder, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44808
stb_vorbis_flush_pushdata
void stb_vorbis_flush_pushdata(stb_vorbis *f)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:4316
ma_loshelf2_process_pcm_frame_s16
static MA_INLINE void ma_loshelf2_process_pcm_frame_s16(ma_loshelf2 *pFilter, ma_int16 *pFrameOut, const ma_int16 *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32274
drwav_init_write
DRWAV_API drwav_bool32 drwav_init_write(drwav *pWav, const drwav_data_format *pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void *pUserData, const drwav_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:48378
ma_event::condition
pthread_cond_t condition
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2884
ma_lpf1_process_pcm_frame_s16
static MA_INLINE void ma_lpf1_process_pcm_frame_s16(ma_lpf1 *pLPF, ma_int16 *pY, const ma_int16 *pX)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30730
ma_round_to_power_of_2
static MA_INLINE unsigned int ma_round_to_power_of_2(unsigned int x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1791
MA_SAMPLE_RATE_192000
#define MA_SAMPLE_RATE_192000
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1748
ma_pcm_s16_to_s24__optimized
static MA_INLINE void ma_pcm_s16_to_s24__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28517
ma_device_config_init
ma_device_config ma_device_config_init(ma_device_type deviceType)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27034
ma_timer::counterD
double counterD
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3052
ma_bpf2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2028
ma_context_init_backend_apis
static ma_result ma_context_init_backend_apis(ma_context *pContext)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26501
ma__malloc_default
static void * ma__malloc_default(size_t sz, void *pUserData)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1823
ma_biquad_config_init
ma_biquad_config ma_biquad_config_init(ma_format format, ma_uint32 channels, double b0, double b1, double b2, double a0, double a1, double a2)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30423
ma_decoder_init__internal
static ma_result ma_decoder_init__internal(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void *pUserData, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:43765
ma_decoder_init_raw
ma_result ma_decoder_init_raw(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void *pUserData, const ma_decoder_config *pConfigIn, const ma_decoder_config *pConfigOut, ma_decoder *pDecoder)
ma_context_config::pClientName
const char * pClientName
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3183
ma_event::pContext
ma_context * pContext
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2870
ma_mutex::pContext
ma_context * pContext
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2848
ma_device::pContext
ma_context * pContext
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3586
ma_decoder::internalSampleRate
ma_uint32 internalSampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5201
ma_channel_converter::isSimpleShuffle
ma_bool32 isSimpleShuffle
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2381
ma_lpf
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1928
drwav_allocation_callbacks
Definition: porcupine/demo/c/dr_libs/dr_wav.h:409
ma_rb::ownsBuffer
ma_bool32 ownsBuffer
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2573
ma_hpf1_process_pcm_frame_s16
static MA_INLINE void ma_hpf1_process_pcm_frame_s16(ma_hpf1 *pHPF, ma_int16 *pY, const ma_int16 *pX)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31241
ma_path_extension_equal_w
static ma_bool32 ma_path_extension_equal_w(const wchar_t *path, const wchar_t *extension)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44200
ma_decoder_init_file_w
ma_result ma_decoder_init_file_w(const wchar_t *pFilePath, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44714
ma_encoder__internal_on_seek_wav
static drwav_bool32 ma_encoder__internal_on_seek_wav(void *pUserData, int offset, drwav_seek_origin origin)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45112
ma_copy_and_apply_volume_factor_pcm_frames_s16
void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16 *pPCMFramesOut, const ma_int16 *pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor)
ma_pcm_s32_to_u8
void ma_pcm_s32_to_u8(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29185
ma_aligned_malloc
void * ma_aligned_malloc(size_t sz, size_t alignment, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37148
ma_pcm_rb_get_subbuffer_ptr
void * ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb *pRB, ma_uint32 subbufferIndex, void *pBuffer)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36994
MA_DEVICE_OP_START__NULL
#define MA_DEVICE_OP_START__NULL
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6219
ma_context::_unused
int _unused
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3531
MA_DEVICE_NOT_STOPPED
#define MA_DEVICE_NOT_STOPPED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1727
ma_bpf2::bq
ma_biquad bq
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2030
ma_waveform_config::type
ma_waveform_type type
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5366
ma_pcm_interleave_s16
MA_API void ma_pcm_interleave_s16(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28721
ma_pcm_deinterleave_f32
MA_API void ma_pcm_deinterleave_f32(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30224
ma_notch2_init
ma_result ma_notch2_init(const ma_notch2_config *pConfig, ma_notch2 *pFilter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31977
ma_hpf1::r1
ma_biquad_coefficient r1[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1966
ma_pcm_deinterleave_s32__optimized
static MA_INLINE void ma_pcm_deinterleave_s32__optimized(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29478
ma_device_config::periods
ma_uint32 periods
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3106
ma_pcm_s16_to_u8__optimized
static MA_INLINE void ma_pcm_s16_to_u8__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28446
ma_channel_converter_process_pcm_frames__stereo_to_mono
static ma_result ma_channel_converter_process_pcm_frames__stereo_to_mono(ma_channel_converter *pConverter, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34301
ma_lpf1_reinit
ma_result ma_lpf1_reinit(const ma_lpf1_config *pConfig, ma_lpf1 *pLPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30674
MA_DEVICE_OP_SUSPEND__NULL
#define MA_DEVICE_OP_SUSPEND__NULL
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6220
drwav
Definition: porcupine/demo/c/dr_libs/dr_wav.h:805
ma_biquad_config::b2
double b2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1849
stb_vorbis_info::channels
int channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:127
ma_resampler_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2242
ma_standard_channel_map_default
@ ma_standard_channel_map_default
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1813
ma_context_get_device_info__null
static ma_result ma_context_get_device_info__null(ma_context *pContext, ma_device_type deviceType, const ma_device_id *pDeviceID, ma_device_info *pDeviceInfo)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6363
ma_pcm_u8_to_s24__reference
static MA_INLINE void ma_pcm_u8_to_s24__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28135
ma_rb__get_read_ptr
static MA_INLINE void * ma_rb__get_read_ptr(ma_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36344
ma_pcm_rb_acquire_read
ma_result ma_pcm_rb_acquire_read(ma_pcm_rb *pRB, ma_uint32 *pSizeInFrames, void **ppBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36864
ma_post_error
static ma_result ma_post_error(ma_device *pDevice, ma_uint32 logLevel, const char *message, ma_result resultCode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5456
ma_decoder_config::algorithm
ma_resample_algorithm algorithm
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5180
ma_backend_null
@ ma_backend_null
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2808
ma_performance_profile_low_latency
@ ma_performance_profile_low_latency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1818
ma_pcm_rb_init_ex
ma_result ma_pcm_rb_init_ex(ma_format format, ma_uint32 channels, ma_uint32 subbufferSizeInFrames, ma_uint32 subbufferCount, ma_uint32 subbufferStrideInFrames, void *pOptionalPreallocatedBuffer, const ma_allocation_callbacks *pAllocationCallbacks, ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36814
ma_clip_pcm_frames_f32
MA_INLINE void ma_clip_pcm_frames_f32(float *p, ma_uint32 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5091
ma_mutex
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2846
ma_notch2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2080
ma_pcm_rb_uninit
void ma_pcm_rb_uninit(ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36846
ma_decoder_init_flac__internal
static ma_result ma_decoder_init_flac__internal(const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:42121
ma_resample_algorithm_linear
@ ma_resample_algorithm_linear
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2236
ma_device::isOwnerOfContext
ma_bool32 isOwnerOfContext
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3602
ma_resampler::pSpeexResamplerState
void * pSpeexResamplerState
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2268
ma_semaphore::posix
struct ma_semaphore::@92::@94 posix
ma_rb_commit_read
ma_result ma_rb_commit_read(ma_rb *pRB, size_t sizeInBytes, void *pBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36493
ma_device_config::quality
int quality
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3122
stb_vorbis_decode_frame_pushdata
int stb_vorbis_decode_frame_pushdata(stb_vorbis *f, const unsigned char *datablock, int datablock_length_in_bytes, int *channels, float ***output, int *samples)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:4419
ma_hishelf2_process_pcm_frames
ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2 *pFilter, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32410
ma_channel_converter_config::mixingMode
ma_channel_mix_mode mixingMode
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2365
ma_rb::pBuffer
void * pBuffer
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2567
ma_decoder_read_bytes
static ma_result ma_decoder_read_bytes(ma_decoder *pDecoder, void *pBufferOut, size_t bytesToRead, size_t *pBytesRead)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:40588
ma_lpf1_config::q
double q
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1891
ma_mutex::posix
struct ma_mutex::@86::@88 posix
ma_lpf2__get_biquad_config
static MA_INLINE ma_biquad_config ma_lpf2__get_biquad_config(const ma_lpf2_config *pConfig)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30796
ma_biquad_coefficient::s32
ma_int32 s32
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1844
ma_pcm_interleave_s32
MA_API void ma_pcm_interleave_s32(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29454
ma_apply_volume_factor_pcm_frames_u8
void ma_apply_volume_factor_pcm_frames_u8(ma_uint8 *pFrames, ma_uint32 frameCount, ma_uint32 channels, float factor)
ma_peak2_config::q
double q
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2106
g_maStandardSampleRatePriorities
static ma_uint32 g_maStandardSampleRatePriorities[]
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:640
ma_pcm_u8_to_f32__optimized
static MA_INLINE void ma_pcm_u8_to_f32__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28284
MA_LOG_LEVEL_ERROR
#define MA_LOG_LEVEL_ERROR
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1591
ma_bpf2_init
ma_result ma_bpf2_init(const ma_bpf2_config *pConfig, ma_bpf2 *pBPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31676
ma_data_converter_process_pcm_frames__format_only
static ma_result ma_data_converter_process_pcm_frames__format_only(ma_data_converter *pConverter, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34720
ma_resource_format
ma_resource_format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5145
ma_device_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3129
ma_data_converter_process_pcm_frames__resample_with_format_conversion
static ma_result ma_data_converter_process_pcm_frames__resample_with_format_conversion(ma_data_converter *pConverter, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34759
ma_resampler_config::lpfNyquistFactor
double lpfNyquistFactor
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2250
ma_pcm_rb_seek_read
ma_result ma_pcm_rb_seek_read(ma_pcm_rb *pRB, ma_uint32 offsetInFrames)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36922
ma_decoder::outputChannels
ma_uint32 outputChannels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5204
ma_context::pthread_cond_destroy
ma_proc pthread_cond_destroy
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3570
MA_CHANNEL_AUX_6
#define MA_CHANNEL_AUX_6
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1627
ma_pcm_s16_to_s24__reference
static MA_INLINE void ma_pcm_s16_to_s24__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28502
MA_MIN_CHANNELS
#define MA_MIN_CHANNELS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1752
ma_hishelf2_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2160
ma_data_converter_config::linear
struct ma_data_converter_config::@80::@81 linear
ma_linear_resampler::s16
ma_int16 s16[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2214
ma_hpf1
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1961
ma_biquad_config::a2
double a2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1852
ma_pcm_f32_to_s32__reference
static MA_INLINE void ma_pcm_f32_to_s32__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30093
MA_CHANNEL_AUX_15
#define MA_CHANNEL_AUX_15
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1636
ma_waveform_read_pcm_frames
ma_uint64 ma_waveform_read_pcm_frames(ma_waveform *pWaveform, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45751
MA_ERROR
#define MA_ERROR
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1660
ma_device_id::jack
int jack
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3062
ma_device_config::pulse
struct ma_device_config::@101 pulse
ma_waveform_type
ma_waveform_type
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5353
MA_CHANNEL_AUX_30
#define MA_CHANNEL_AUX_30
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1651
ma_hpf::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1998
ma_decoder_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5173
ma_loshelf2_config::shelfSlope
double shelfSlope
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2134
ma_hpf_config::order
ma_uint32 order
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1991
ma_copy_memory_64
static MA_INLINE void ma_copy_memory_64(void *dst, const void *src, ma_uint64 sizeInBytes)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1732
ma_decoder_init_file
ma_result ma_decoder_init_file(const char *pFilePath, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44687
ma_data_converter_config::formatIn
ma_format formatIn
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2403
ma_thread_wait__posix
static void ma_thread_wait__posix(ma_thread *pThread)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4532
ma_data_converter_config_init
ma_data_converter_config ma_data_converter_config_init(ma_format formatIn, ma_format formatOut, ma_uint32 channelsIn, ma_uint32 channelsOut, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34530
MA_SAMPLE_RATE_88200
#define MA_SAMPLE_RATE_88200
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1745
ma_notch2::bq
ma_biquad bq
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2082
ma_hpf_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1988
ma_device::usingDefaultPeriods
ma_bool32 usingDefaultPeriods
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3601
MA_STATE_STOPPING
#define MA_STATE_STOPPING
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:1629
ma_itoa_s
MA_API int ma_itoa_s(int value, char *dst, size_t dstSizeInBytes, int radix)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1047
ma_context::onGetDeviceInfo
ma_result(* onGetDeviceInfo)(ma_context *pContext, ma_device_type deviceType, const ma_device_id *pDeviceID, ma_share_mode shareMode, ma_device_info *pDeviceInfo)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3228
drmp3_read_pcm_frames_f32
DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3 *pMP3, drmp3_uint64 framesToRead, float *pBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:62041
ma_thread_create
static ma_result ma_thread_create(ma_thread *pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void *pData, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4721
RESAMPLER_ERR_SUCCESS
@ RESAMPLER_ERR_SUCCESS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/speex_resampler.h:104
ma_noise_s16_white
static MA_INLINE ma_int16 ma_noise_s16_white(ma_noise *pNoise)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45958
MA_ALREADY_EXISTS
#define MA_ALREADY_EXISTS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1667
ma_linear_resampler_get_expected_output_frame_count
ma_uint64 ma_linear_resampler_get_expected_output_frame_count(ma_linear_resampler *pResampler, ma_uint64 inputFrameCount)
ma_mutex_unlock
void ma_mutex_unlock(ma_mutex *pMutex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4813
MA_NO_SPACE
#define MA_NO_SPACE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1677
ma_pcm_s32_to_f32__optimized
static MA_INLINE void ma_pcm_s32_to_f32__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29386
ma_device__handle_duplex_callback_playback
static ma_result ma_device__handle_duplex_callback_playback(ma_device *pDevice, ma_uint32 frameCount, void *pFramesInInternalFormat, ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5902
ma_has_sse2
static MA_INLINE ma_bool32 ma_has_sse2(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:229
stb_vorbis_close
void stb_vorbis_close(stb_vorbis *f)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:4246
ma_pcm_u8_to_s32
void ma_pcm_u8_to_s32(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28242
ma_ios_session_category_solo_ambient
@ ma_ios_session_category_solo_ambient
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3030
ma_pcm_s16_to_f32
void ma_pcm_s16_to_f32(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28677
ma_get_format_priority_index
MA_API ma_uint32 ma_get_format_priority_index(ma_format format)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5996
ma_data_converter_uninit
void ma_data_converter_uninit(ma_data_converter *pConverter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34671
ma_pcm_f32_to_s32__optimized
static MA_INLINE void ma_pcm_f32_to_s32__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30119
ma_hpf2_process_pcm_frames
ma_result ma_hpf2_process_pcm_frames(ma_hpf2 *pHPF, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31389
drmp3_allocation_callbacks::onFree
void(* onFree)(void *p, void *pUserData)
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:331
ma_context_config::pulse
struct ma_context_config::@105 pulse
ma_context
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3210
ma_lcg
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5388
ma_noise_s16_pink
static MA_INLINE ma_int16 ma_noise_s16_pink(ma_noise *pNoise, ma_uint32 iChannel)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:46077
ma_device::algorithm
ma_resample_algorithm algorithm
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3608
ma_rb::encodedReadOffset
volatile ma_uint32 encodedReadOffset
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2571
drwav_data_format::sampleRate
drwav_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/dr_wav.h:440
ma_calculate_buffer_size_in_milliseconds_from_frames
ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27760
ma_biquad_get_latency
ma_uint32 ma_biquad_get_latency(ma_biquad *pBQ)
ma_pcm_s32_to_u8__optimized
static MA_INLINE void ma_pcm_s32_to_u8__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29161
ma_rand_f64
static MA_INLINE double ma_rand_f64(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2500
ma_backend_pulseaudio
@ ma_backend_pulseaudio
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2802
RESAMPLER_ERR_INVALID_ARG
@ RESAMPLER_ERR_INVALID_ARG
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/speex_resampler.h:107
ma_device_init
ma_result ma_device_init(ma_context *pContext, const ma_device_config *pConfig, ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27048
ma_device
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3584
drwav_allocation_callbacks::onMalloc
void *(* onMalloc)(size_t sz, void *pUserData)
Definition: porcupine/demo/c/dr_libs/dr_wav.h:412
init
void init(const M_string &remappings)
error
static int error(vorb *f, enum STBVorbisError e)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:896
ma_data_converter::hasPreFormatConversion
ma_bool32 hasPreFormatConversion
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2434
ma_linear_resampler_config_init
ma_linear_resampler_config ma_linear_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32435
ma_thread_priority_low
@ ma_thread_priority_low
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2816
MA_BAD_SEEK
#define MA_BAD_SEEK
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1684
MA_SAMPLE_RATE_96000
#define MA_SAMPLE_RATE_96000
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1746
ma_resampler::linear
ma_linear_resampler linear
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2265
ma_allocation_callbacks::onRealloc
void *(* onRealloc)(void *p, size_t sz, void *pUserData)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1827
ma_context_init__null
static ma_result ma_context_init__null(ma_context *pContext, const ma_context_config *pConfig, ma_backend_callbacks *pCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6654
ma_semaphore::pContext
ma_context * pContext
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2894
ma_hishelf2_config::gainDB
double gainDB
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2161
ma_device_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3100
ma_hpf2_reinit
ma_result ma_hpf2_reinit(const ma_hpf2_config *pConfig, ma_hpf2 *pHPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31361
drflac_close
DRFLAC_API void drflac_close(drflac *pFlac)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:56763
ma_encoder_preinit
MA_API ma_result ma_encoder_preinit(const ma_encoder_config *pConfig, ma_encoder *pEncoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45196
param
T param(const std::string &param_name, const T &default_val)
ma_device__handle_duplex_callback_capture
static ma_result ma_device__handle_duplex_callback_capture(ma_device *pDevice, ma_uint32 frameCountInDeviceFormat, const void *pFramesInDeviceFormat, ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5845
ma_pcm_f32_to_f32
MA_API void ma_pcm_f32_to_f32(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30168
ma__calloc_from_callbacks
static MA_INLINE void * ma__calloc_from_callbacks(size_t sz, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1890
ma_device_config::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3103
ma_linear_resampler_process_pcm_frames_s16_downsample
static ma_result ma_linear_resampler_process_pcm_frames_s16_downsample(ma_linear_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32620
ma_decoder_init_file_flac
ma_result ma_decoder_init_file_flac(const char *pFilePath, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44697
MA_MAX_CHANNELS
#define MA_MAX_CHANNELS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1753
ma_biquad_config::a1
double a1
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1851
ma_mutex::mutex
pthread_mutex_t mutex
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2861
ma_hpf::hpf2
ma_hpf2 hpf2[MA_MAX_FILTER_ORDER/2]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2003
ma_waveform_type_square
@ ma_waveform_type_square
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5360
ma_lpf::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1930
ma_pcm_s24_to_s32__reference
static MA_INLINE void ma_pcm_s24_to_s32__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28928
ma_data_converter_config::channelsOut
ma_uint32 channelsOut
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2406
ma_device::sampleRate
ma_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3588
drmp3_get_pcm_frame_count
DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3 *pMP3)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:62253
ma_resampler::state
union ma_resampler::@77 state
ma_lpf2_config
struct ma_lpf1_config ma_lpf2_config
ma_device::capture
struct ma_device::@116 capture
ma_encoder_config::allocationCallbacks
ma_allocation_callbacks allocationCallbacks
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5319
ma_performance_profile_conservative
@ ma_performance_profile_conservative
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1819
ma_channel_mix_mode
ma_channel_mix_mode
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1794
ma_mutex_lock
void ma_mutex_lock(ma_mutex *pMutex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4798
MA_SAMPLE_RATE_11025
#define MA_SAMPLE_RATE_11025
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1738
ma_device_thread__null
static ma_thread_result MA_THREADCALL ma_device_thread__null(void *pData)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6223
MA_NOT_IMPLEMENTED
#define MA_NOT_IMPLEMENTED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1688
ma_lpf1_get_latency
ma_uint32 ma_lpf1_get_latency(ma_lpf1 *pLPF)
drflac::sampleRate
drflac_uint32 sampleRate
Definition: porcupine/demo/c/dr_libs/dr_flac.h:701
ma_resample_algorithm_speex
@ ma_resample_algorithm_speex
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2237
ma_seek_origin_current
@ ma_seek_origin_current
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5142
ma_device::onStop
ma_stop_proc onStop
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3591
ma_notch2__get_biquad_config
static MA_INLINE ma_biquad_config ma_notch2__get_biquad_config(const ma_notch2_config *pConfig)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31947
ma_device_type
ma_device_type
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3010
ma_hpf2__get_biquad_config
static MA_INLINE ma_biquad_config ma_hpf2__get_biquad_config(const ma_hpf2_config *pConfig)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31307
ma_apply_volume_factor_pcm_frames_s32
void ma_apply_volume_factor_pcm_frames_s32(ma_int32 *pFrames, ma_uint32 frameCount, ma_uint32 channels, float factor)
ma_context::pthread_attr_init
ma_proc pthread_attr_init
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3573
MA_CHANNEL_AUX_29
#define MA_CHANNEL_AUX_29
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1650
ma_ios_session_category_option_allow_bluetooth_a2dp
@ ma_ios_session_category_option_allow_bluetooth_a2dp
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3045
ma_loshelf2_get_latency
ma_uint32 ma_loshelf2_get_latency(ma_loshelf2 *pFilter)
ma_handle
void * ma_handle
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1533
MA_CHANNEL_FRONT_CENTER
#define MA_CHANNEL_FRONT_CENTER
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1605
DR_WAVE_FORMAT_IEEE_FLOAT
#define DR_WAVE_FORMAT_IEEE_FLOAT
Definition: porcupine/demo/c/dr_libs/dr_wav.h:256
ma_event_uninit__posix
static void ma_event_uninit__posix(ma_event *pEvent)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4584
ma_device::internalChannelMap
ma_channel internalChannelMap[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3631
ma_rb_commit_write
ma_result ma_rb_commit_write(ma_rb *pRB, size_t sizeInBytes, void *pBufferOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36584
MA_SAMPLE_RATE_176400
#define MA_SAMPLE_RATE_176400
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1747
MA_DEVICE_NOT_STARTED
#define MA_DEVICE_NOT_STARTED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1726
ma_decoder_config::lpfOrder
ma_uint32 lpfOrder
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5183
ma_context::onDeviceIDEqual
ma_bool32(* onDeviceIDEqual)(ma_context *pContext, const ma_device_id *pID0, const ma_device_id *pID1)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3226
ma_zero_memory_64
static MA_INLINE void ma_zero_memory_64(void *dst, ma_uint64 sizeInBytes)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1752
ma_linear_resampler_process_pcm_frames
ma_result ma_linear_resampler_process_pcm_frames(ma_linear_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32940
ma_context::pDeviceInfos
ma_device_info * pDeviceInfos
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3222
config
static sai_transceiver_t config
Definition: imxrt1050/imxrt1050-evkb/source/pv_audio_rec.c:75
ma_is_little_endian
static MA_INLINE ma_bool32 ma_is_little_endian(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:445
MA_TRUE
#define MA_TRUE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1530
ma_pcm_deinterleave_s32__reference
static MA_INLINE void ma_pcm_deinterleave_s32__reference(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29464
ma_context_init
ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config *pConfig, ma_context *pContext)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26550
ma_data_converter_config::formatOut
ma_format formatOut
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2404
ma_hpf1::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1964
ma_device::workResult
ma_result workResult
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3598
ma_pcm_s16_to_f32__optimized
static MA_INLINE void ma_pcm_s16_to_f32__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28653
ma_context::pthread_join
ma_proc pthread_join
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3564
ma_lpf1_config_init
ma_lpf1_config ma_lpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30621
ma_context_config::coreaudio
struct ma_context_config::@106 coreaudio
MA_DEVICE_OP_KILL__NULL
#define MA_DEVICE_OP_KILL__NULL
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6221
MA_CHANNEL_AUX_9
#define MA_CHANNEL_AUX_9
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1630
ma_context_config
struct ma_context_config ma_context_config
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:1897
ma_apply_volume_factor_pcm_frames_s24
void ma_apply_volume_factor_pcm_frames_s24(void *pFrames, ma_uint32 frameCount, ma_uint32 channels, float factor)
MA_BAD_MESSAGE
#define MA_BAD_MESSAGE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1690
MA_SUCCESS
#define MA_SUCCESS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1659
MA_END_OF_FILE
#define MA_END_OF_FILE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1676
ma_waveform_read_pcm_frames__triangle
static void ma_waveform_read_pcm_frames__triangle(ma_waveform *pWaveform, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45667
ma_abs
#define ma_abs(x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:779
ma_ios_session_category_ambient
@ ma_ios_session_category_ambient
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3029
ma_biquad::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1859
ma_waveform_set_sample_rate
ma_result ma_waveform_set_sample_rate(ma_waveform *pWaveform, ma_uint32 sampleRate)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45512
ma_decoder::onReadPCMFrames
ma_decoder_read_pcm_frames_proc onReadPCMFrames
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5209
ma_backend_oss
@ ma_backend_oss
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2801
ma_bpf_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2041
ma_device_config::pStreamNameCapture
const char * pStreamNameCapture
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3156
ma_lpf::lpf1Count
ma_uint32 lpf1Count
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1932
ma_linear_resampler::inTimeInt
ma_uint32 inTimeInt
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2209
ma_path_extension_equal
static ma_bool32 ma_path_extension_equal(const char *path, const char *extension)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44181
ma_copy_and_apply_volume_factor_f32
void ma_copy_and_apply_volume_factor_f32(float *pSamplesOut, const float *pSamplesIn, ma_uint32 sampleCount, float factor)
ma_data_converter_config::resampling
struct ma_data_converter_config::@80 resampling
ma_waveform_read_pcm_frames__square
static void ma_waveform_read_pcm_frames__square(ma_waveform *pWaveform, void *pFramesOut, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45625
ma_lcg_rand_f64
static MA_INLINE double ma_lcg_rand_f64(ma_lcg *pLCG)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:2459
ma_pcm_deinterleave_u8__reference
static MA_INLINE void ma_pcm_deinterleave_u8__reference(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28383
MA_MIN_SAMPLE_RATE
#define MA_MIN_SAMPLE_RATE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1754
ma_ios_session_category_option_default_to_speaker
@ ma_ios_session_category_option_default_to_speaker
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3043
ma_thread_priority_default
@ ma_thread_priority_default
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2821
ma_pcm_deinterleave_s16
MA_API void ma_pcm_deinterleave_s16(void **dst, const void *src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28750
ma_device_id::audio4
char audio4[256]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3065
ma_backend_jack
@ ma_backend_jack
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2804
ma_copy_and_apply_volume_factor_pcm_frames_f32
void ma_copy_and_apply_volume_factor_pcm_frames_f32(float *pPCMFramesOut, const float *pPCMFramesIn, ma_uint32 frameCount, ma_uint32 channels, float factor)
ma_pcm_s32_to_s24__optimized
static MA_INLINE void ma_pcm_s32_to_s24__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29306
ma_noise_config::seed
ma_int32 seed
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5405
ma_loshelf2_init
ma_result ma_loshelf2_init(const ma_loshelf2_config *pConfig, ma_loshelf2 *pFilter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32232
ma_loshelf2
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2136
ma_rb__get_write_ptr
static MA_INLINE void * ma_rb__get_write_ptr(ma_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36350
ma_notch2_config::q
double q
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2078
ma_hishelf2_config::shelfSlope
double shelfSlope
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2162
ma_loshelf2_process_pcm_frames
ma_result ma_loshelf2_process_pcm_frames(ma_loshelf2 *pFilter, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32284
ma_backend_alsa
@ ma_backend_alsa
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2803
ma_pcm_s24_to_u8__reference
static MA_INLINE void ma_pcm_s24_to_u8__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28761
ma_thread::posix
struct ma_thread::@83::@85 posix
ma_standard_channel_map_sndio
@ ma_standard_channel_map_sndio
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1811
ma_context_get_devices__enum_callback
static ma_bool32 ma_context_get_devices__enum_callback(ma_context *pContext, ma_device_type deviceType, const ma_device_info *pInfo, void *pUserData)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26817
assert.h
MA_STATE_STARTING
#define MA_STATE_STARTING
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:1628
MA_CHANNEL_FRONT_LEFT
#define MA_CHANNEL_FRONT_LEFT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1603
ma_context::pthread_cond_signal
ma_proc pthread_cond_signal
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3572
ma_pcm_rb::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2597
ma_rb_get_subbuffer_size
size_t ma_rb_get_subbuffer_size(ma_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36765
ma_pcm_u8_to_s32__optimized
static MA_INLINE void ma_pcm_u8_to_s32__optimized(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28218
ma_bpf2_config_init
ma_bpf2_config ma_bpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31626
ma_lpf2_init
ma_result ma_lpf2_init(const ma_lpf2_config *pConfig, ma_lpf2 *pLPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30826
ma_hpf1_get_latency
ma_uint32 ma_hpf1_get_latency(ma_hpf1 *pHPF)
ma_data_converter::resampler
ma_resampler resampler
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2433
ma_context::isBackendAsynchronous
ma_bool32 isBackendAsynchronous
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3223
ma_log_level_to_string
const char * ma_log_level_to_string(ma_uint32 logLevel)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1953
MA_NOT_UNIQUE
#define MA_NOT_UNIQUE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1695
ma_hpf_config::cutoffFrequency
double cutoffFrequency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1990
ma_fopen
MA_API ma_result ma_fopen(FILE **ppFile, const char *pFilePath, const char *pOpenMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1586
MA_ZERO_OBJECT
#define MA_ZERO_OBJECT(p)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:774
ma_lpf1_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1881
ma_encoder_seek_proc
ma_bool32(* ma_encoder_seek_proc)(ma_encoder *pEncoder, int byteOffset, ma_seek_origin origin)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5308
ma_encoder_write_proc
size_t(* ma_encoder_write_proc)(ma_encoder *pEncoder, const void *pBufferIn, size_t bytesToWrite)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5307
drmp3_allocation_callbacks::onMalloc
void *(* onMalloc)(size_t sz, void *pUserData)
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:329
drmp3_allocation_callbacks::onRealloc
void *(* onRealloc)(void *p, size_t sz, void *pUserData)
Definition: porcupine/demo/c/dr_libs/dr_mp3.h:330
ma_context::pthread_mutex_unlock
ma_proc pthread_mutex_unlock
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3568
ma_biquad::r2
ma_biquad_coefficient r2[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1867
ma_data_converter::channelConverter
ma_channel_converter channelConverter
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2432
ma_device::lpfOrder
ma_uint32 lpfOrder
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3611
ma_data_converter
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2429
ma_powf
static MA_INLINE float ma_powf(float x, float y)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:828
ma_biquad_config::b0
double b0
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1847
ma_decoder_init_file_flac_w
ma_result ma_decoder_init_file_flac_w(const wchar_t *pFilePath, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44724
drflac_seek_to_pcm_frame
DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac *pFlac, drflac_uint64 pcmFrameIndex)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:58917
ma_noise_type
ma_noise_type
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5393
ma_channel_mix_mode_rectangular
@ ma_channel_mix_mode_rectangular
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1796
ma_biquad_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1845
ma_decoder_config::allocationCallbacks
ma_allocation_callbacks allocationCallbacks
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5190
ma_pcm_s32_to_s16
void ma_pcm_s32_to_s16(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29265
ma_hishelf2_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2159
ma_hpf_process_pcm_frames
ma_result ma_hpf_process_pcm_frames(ma_hpf *pHPF, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31535
ma_peak2_get_latency
ma_uint32 ma_peak2_get_latency(ma_peak2 *pFilter)
MA_TOO_MANY_OPEN_FILES
#define MA_TOO_MANY_OPEN_FILES
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1668
ma_data_converter_process_pcm_frames__channels_first
static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_converter *pConverter, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:35158
ma_rb__extract_offset_in_bytes
static MA_INLINE ma_uint32 ma_rb__extract_offset_in_bytes(ma_uint32 encodedOffset)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36334
MA_SAMPLE_RATE_32000
#define MA_SAMPLE_RATE_32000
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1742
ma_speex_resampler_get_required_input_frame_count
int ma_speex_resampler_get_required_input_frame_count(SpeexResamplerState *st, spx_uint64_t out_len, spx_uint64_t *in_len)
ma_malloc
void * ma_malloc(size_t sz, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37117
ma_is_loopback_supported
ma_bool32 ma_is_loopback_supported(ma_backend backend)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:5215
ma_biquad_process_pcm_frames
ma_result ma_biquad_process_pcm_frames(ma_biquad *pBQ, void *pFramesOut, const void *pFramesIn, ma_uint64 frameCount)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30570
ma_device::stopEvent
ma_event stopEvent
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3596
ma_resampler_init
ma_result ma_resampler_init(const ma_resampler_config *pConfig, ma_resampler *pResampler)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33099
ma_context_config::allocationCallbacks
ma_allocation_callbacks allocationCallbacks
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3165
NULL
#define NULL
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1543
ma_has_neon
static MA_INLINE ma_bool32 ma_has_neon(void)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:359
ma_backend
ma_backend
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2793
ma_decoder_init_memory_mp3
ma_result ma_decoder_init_memory_mp3(const void *pData, size_t dataSize, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44028
ma_event::value
ma_uint32 value
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2885
ma_rb::clearOnWriteAcquire
ma_bool32 clearOnWriteAcquire
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2574
ma_linear_resampler_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2207
ma_data_converter::hasResampler
ma_bool32 hasResampler
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2437
ma_noise_type_white
@ ma_noise_type_white
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5395
ma_channel_converter::channelsIn
ma_uint32 channelsIn
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2370
ma_device_uninit__null
static ma_result ma_device_uninit__null(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6392
ma_hpf1_process_pcm_frame_f32
static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1 *pHPF, float *pY, const float *pX)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:31221
ma_ios_session_category_playback
@ ma_ios_session_category_playback
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3031
ma_device::wakeupEvent
ma_event wakeupEvent
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3594
ma_lpf1_init
ma_result ma_lpf1_init(const ma_lpf1_config *pConfig, ma_lpf1 *pLPF)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30655
DR_WAVE_FORMAT_MULAW
#define DR_WAVE_FORMAT_MULAW
Definition: porcupine/demo/c/dr_libs/dr_wav.h:258
drwav_data_format
Definition: porcupine/demo/c/dr_libs/dr_wav.h:435
drflac_int32
signed int drflac_int32
Definition: porcupine/demo/c/dr_libs/dr_flac.h:245
ma_linear_resampler_init
ma_result ma_linear_resampler_init(const ma_linear_resampler_config *pConfig, ma_linear_resampler *pResampler)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32528
MA_TAU_D
#define MA_TAU_D
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:590
ma_context_config::sessionCategory
ma_ios_session_category sessionCategory
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3178
ma_pcm_rb_init
ma_result ma_pcm_rb_init(ma_format format, ma_uint32 channels, ma_uint32 bufferSizeInFrames, void *pOptionalPreallocatedBuffer, const ma_allocation_callbacks *pAllocationCallbacks, ma_pcm_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36841
drwav_write_pcm_frames
DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav *pWav, drwav_uint64 framesToWrite, const void *pData)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:49558
VORBIS_need_more_data
@ VORBIS_need_more_data
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:367
drwav::translatedFormatTag
drwav_uint16 translatedFormatTag
Definition: porcupine/demo/c/dr_libs/dr_wav.h:840
MA_IO_ERROR
#define MA_IO_ERROR
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1679
ma_waveform_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5363
ma_hishelf2_config::frequency
double frequency
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2163
ma_device_info::isDefault
ma_bool32 isDefault
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3096
ma_backend_webaudio
@ ma_backend_webaudio
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2807
ma_count_set_bits
static MA_INLINE unsigned int ma_count_set_bits(unsigned int x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:1802
ma_context::deviceInfoLock
ma_mutex deviceInfoLock
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3218
ma_sleep
static void ma_sleep(ma_uint32 milliseconds)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:522
ma_context_config::jack
struct ma_context_config::@107 jack
ma_decode_memory
ma_result ma_decode_memory(const void *pData, size_t dataSize, ma_decoder_config *pConfig, ma_uint64 *pFrameCountOut, void **ppDataOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:45072
ma_convert_pcm_frames_format
void ma_convert_pcm_frames_format(void *pOut, ma_format formatOut, const void *pIn, ma_format formatIn, ma_uint64 frameCount, ma_uint32 channels, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30307
ma_resampler_config::speex
struct ma_resampler_config::@76 speex
MA_FORMAT_NOT_SUPPORTED
#define MA_FORMAT_NOT_SUPPORTED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1715
ma_pcm_s24_to_s24
MA_API void ma_pcm_s24_to_s24(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28920
ma_share_mode
ma_share_mode
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3018
ma_channel_converter_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2360
ma_channel_converter_config::weights
float weights[MA_MAX_CHANNELS][MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2366
ma_bool8
ma_uint8 ma_bool8
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1528
ma_context_config::tryAutoSpawn
ma_bool32 tryAutoSpawn
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3174
ma_channel_converter_init
ma_result ma_channel_converter_init(const ma_channel_converter_config *pConfig, ma_channel_converter *pConverter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:33779
ma_device::usingDefaultBufferSize
ma_bool32 usingDefaultBufferSize
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3600
ma_channel_converter::isStereoToMono
ma_bool32 isStereoToMono
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2383
ma_seek_origin_start
@ ma_seek_origin_start
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5141
ma_ios_session_category_default
@ ma_ios_session_category_default
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3027
ma_encoder::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5332
ma_device::isStarted
ma_bool32 isStarted
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3847
ma_channel
ma_uint8 ma_channel
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1600
ma_device_read__null
static ma_result ma_device_read__null(ma_device *pDevice, void *pPCMFrames, ma_uint32 frameCount, ma_uint32 *pFramesRead)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6574
ma_event_wait__posix
static ma_result ma_event_wait__posix(ma_event *pEvent)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4590
ma_device_config::channelMap
ma_channel channelMap[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3130
ma_linear_resampler_process_pcm_frames_s16_upsample
static ma_result ma_linear_resampler_process_pcm_frames_s16_upsample(ma_linear_resampler *pResampler, const void *pFramesIn, ma_uint64 *pFrameCountIn, void *pFramesOut, ma_uint64 *pFrameCountOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32694
ma_rb_uninit
void ma_rb_uninit(ma_rb *pRB)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:36429
MA_DEFAULT_SAMPLE_RATE
#define MA_DEFAULT_SAMPLE_RATE
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:606
ma_uint16
uint16_t ma_uint16
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1501
MA_FREE
#define MA_FREE(p)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:738
ma_device_config::playback
struct ma_device_config::@97 playback
ma_pcm_s32_to_s24__reference
static MA_INLINE void ma_pcm_s32_to_s24__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29290
ma_ios_session_category_none
@ ma_ios_session_category_none
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3028
ma_waveform::time
double time
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5377
DR_WAVE_FORMAT_ALAW
#define DR_WAVE_FORMAT_ALAW
Definition: porcupine/demo/c/dr_libs/dr_wav.h:257
ma_device_type_duplex
@ ma_device_type_duplex
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3014
ma_free
void ma_free(void *p, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37139
ma_hishelf2_process_pcm_frame_f32
static MA_INLINE void ma_hishelf2_process_pcm_frame_f32(ma_hishelf2 *pFilter, float *pFrameOut, const float *pFrameIn)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32405
MA_CHANNEL_SIDE_LEFT
#define MA_CHANNEL_SIDE_LEFT
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1612
ma_channel_converter::channelMapIn
ma_channel channelMapIn[MA_MAX_CHANNELS]
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2372
ma_device__post_init_setup
static ma_result ma_device__post_init_setup(ma_device *pDevice, ma_device_type deviceType)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:26166
ma_resampler_config::algorithm
ma_resample_algorithm algorithm
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2246
ma_device_start__null
static ma_result ma_device_start__null(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6474
ma_pcm_interleave_s16__reference
static MA_INLINE void ma_pcm_interleave_s16__reference(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28702
ma_device::internalPeriodSizeInFrames
ma_uint32 internalPeriodSizeInFrames
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3632
ma_mutex::_unused
int _unused
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2864
ma_biquad_coefficient
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1837
ma_copy_and_apply_volume_factor_pcm_frames
void ma_copy_and_apply_volume_factor_pcm_frames(void *pFramesOut, const void *pFramesIn, ma_uint32 frameCount, ma_format format, ma_uint32 channels, float factor)
ma_linear_resampler_interpolate_frame_f32
static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler *pResampler, float *MA_RESTRICT pFrameOut)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:32602
ma_device::playback
struct ma_device::@115 playback
ma_backend_aaudio
@ ma_backend_aaudio
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2805
ma_pcm_s24_to_s16
void ma_pcm_s24_to_s16(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28895
ma_data_converter_init
ma_result ma_data_converter_init(const ma_data_converter_config *pConfig, ma_data_converter *pConverter)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:34543
ma_interleave_pcm_frames
void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void **ppDeinterleavedPCMFrames, void *pInterleavedPCMFrames)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30362
ma_biquad_float_to_fp
static ma_int32 ma_biquad_float_to_fp(double x)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30418
ma_bpf2_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2017
ma_pcm_u8_to_s16
void ma_pcm_u8_to_s16(void *pOut, const void *pIn, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28110
DR_WAVE_FORMAT_ADPCM
#define DR_WAVE_FORMAT_ADPCM
Definition: porcupine/demo/c/dr_libs/dr_wav.h:255
ma_get_standard_channel_map_microsoft
static void ma_get_standard_channel_map_microsoft(ma_uint32 channels, ma_channel *pChannelMap)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:35574
stb_vorbis_info::max_frame_size
int max_frame_size
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:133
ma_device::type
ma_device_type type
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3587
ma_linear_resampler::x1
union ma_linear_resampler::@74 x1
ma_event_signal
MA_API ma_result ma_event_signal(ma_event *pEvent)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4913
ma_calculate_buffer_size_in_frames_from_milliseconds
ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:27770
MA_ZERO_MEMORY
#define MA_ZERO_MEMORY(p, sz)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:746
ma_clip_samples_f32
void ma_clip_samples_f32(float *p, ma_uint32 sampleCount)
ma_device_stop__null
static ma_result ma_device_stop__null(ma_device *pDevice)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:6484
ma_decoder::outputSampleRate
ma_uint32 outputSampleRate
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5205
ma_peak2::bq
ma_biquad bq
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2110
ma_semaphore_release__posix
static ma_result ma_semaphore_release__posix(ma_semaphore *pSemaphore)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:4671
MA_PI
#define MA_PI
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:581
ma_decoder_init_file_wav_w
ma_result ma_decoder_init_file_wav_w(const wchar_t *pFilePath, const ma_decoder_config *pConfig, ma_decoder *pDecoder)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:44719
MA_CHANNEL_AUX_24
#define MA_CHANNEL_AUX_24
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1645
ma_encoder_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5316
ma_channel_converter::channelsOut
ma_uint32 channelsOut
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2371
ma_pcm_interleave_s24__optimized
static MA_INLINE void ma_pcm_interleave_s24__optimized(void *dst, const void **src, ma_uint64 frameCount, ma_uint32 channels)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:29080
ma_channel_converter_config_init
ma_channel_converter_config ma_channel_converter_config_init(ma_format format, ma_uint32 channelsIn, const ma_channel channelMapIn[MA_MAX_CHANNELS], ma_uint32 channelsOut, const ma_channel channelMapOut[MA_MAX_CHANNELS], ma_channel_mix_mode mixingMode)
ma_peak2_config::channels
ma_uint32 channels
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2103
ma_encoder_init_proc
ma_result(* ma_encoder_init_proc)(ma_encoder *pEncoder)
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:5309
ma_device_config::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3112
MA_BIQUAD_FIXED_POINT_SHIFT
#define MA_BIQUAD_FIXED_POINT_SHIFT
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:30415
drflac_allocation_callbacks::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/dr_flac.h:566
ma_context_config
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3160
ma_get_format_name
const char * ma_get_format_name(ma_format format)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37176
MA_PROTOCOL_NOT_SUPPORTED
#define MA_PROTOCOL_NOT_SUPPORTED
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1700
MA_MAX_FILTER_ORDER
#define MA_MAX_FILTER_ORDER
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1758
ma_ptr
void * ma_ptr
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1534
ma_pcm_u8_to_f32__reference
static MA_INLINE void ma_pcm_u8_to_f32__reference(void *dst, const void *src, ma_uint64 count, ma_dither_mode ditherMode)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:28267
ma_loshelf2_config::format
ma_format format
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:2130
MA_INVALID_DATA
#define MA_INVALID_DATA
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1692
MA_OUT_OF_MEMORY
#define MA_OUT_OF_MEMORY
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1663


picovoice_driver
Author(s):
autogenerated on Fri Apr 1 2022 02:14:18