initial commit
[shapestoy] / libs / miniaudio / miniaudio.h
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.11.2 - 2021-12-31
4
5 David Reid - mackron@gmail.com
6
7 Website:       https://miniaud.io
8 Documentation: https://miniaud.io/docs
9 GitHub:        https://github.com/mackron/miniaudio
10 */
11
12 /*
13 1. Introduction
14 ===============
15 miniaudio is a single file library for audio playback and capture. To use it, do the following in
16 one .c file:
17
18     ```c
19     #define MINIAUDIO_IMPLEMENTATION
20     #include "miniaudio.h"
21     ```
22
23 You can do `#include "miniaudio.h"` in other parts of the program just like any other header.
24
25 miniaudio includes both low level and high level APIs. The low level API is good for those who want
26 to do all of their mixing themselves and only require a light weight interface to the underlying
27 audio device. The high level API is good for those who have complex mixing and effect requirements.
28
29 In miniaudio, objects are transparent structures. Unlike many other libraries, there are no handles
30 to opaque objects which means you need to allocate memory for objects yourself. In the examples
31 presented in this documentation you will often see objects declared on the stack. You need to be
32 careful when translating these examples to your own code so that you don't accidentally declare
33 your objects on the stack and then cause them to become invalid once the function returns. In
34 addition, you must ensure the memory address of your objects remain the same throughout their
35 lifetime. You therefore cannot be making copies of your objects.
36
37 A config/init pattern is used throughout the entire library. The idea is that you set up a config
38 object and pass that into the initialization routine. The advantage to this system is that the
39 config object can be initialized with logical defaults and new properties added to it without
40 breaking the API. The config object can be allocated on the stack and does not need to be
41 maintained after initialization of the corresponding object. 
42
43
44 1.1. Low Level API
45 ------------------
46 The low level API gives you access to the raw audio data of an audio device. It supports playback,
47 capture, full-duplex and loopback (WASAPI only). You can enumerate over devices to determine which
48 physical device(s) you want to connect to.
49
50 The low level API uses the concept of a "device" as the abstraction for physical devices. The idea
51 is that you choose a physical device to emit or capture audio from, and then move data to/from the
52 device when miniaudio tells you to. Data is delivered to and from devices asynchronously via a
53 callback which you specify when initializing the device.
54
55 When initializing the device you first need to configure it. The device configuration allows you to
56 specify things like the format of the data delivered via the callback, the size of the internal
57 buffer and the ID of the device you want to emit or capture audio from.
58
59 Once you have the device configuration set up you can initialize the device. When initializing a
60 device you need to allocate memory for the device object beforehand. This gives the application
61 complete control over how the memory is allocated. In the example below we initialize a playback
62 device on the stack, but you could allocate it on the heap if that suits your situation better.
63
64     ```c
65     void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
66     {
67         // In playback mode copy data to pOutput. In capture mode read data from pInput. In full-duplex mode, both
68         // pOutput and pInput will be valid and you can move data from pInput into pOutput. Never process more than
69         // frameCount frames.
70     }
71
72     int main()
73     {
74         ma_device_config config = ma_device_config_init(ma_device_type_playback);
75         config.playback.format   = ma_format_f32;   // Set to ma_format_unknown to use the device's native format.
76         config.playback.channels = 2;               // Set to 0 to use the device's native channel count.
77         config.sampleRate        = 48000;           // Set to 0 to use the device's native sample rate.
78         config.dataCallback      = data_callback;   // This function will be called when miniaudio needs more data.
79         config.pUserData         = pMyCustomData;   // Can be accessed from the device object (device.pUserData).
80
81         ma_device device;
82         if (ma_device_init(NULL, &config, &device) != MA_SUCCESS) {
83             return -1;  // Failed to initialize the device.
84         }
85
86         ma_device_start(&device);     // The device is sleeping by default so you'll need to start it manually.
87
88         // Do something here. Probably your program's main loop.
89
90         ma_device_uninit(&device);    // This will stop the device so no need to do that manually.
91         return 0;
92     }
93     ```
94
95 In the example above, `data_callback()` is where audio data is written and read from the device.
96 The idea is in playback mode you cause sound to be emitted from the speakers by writing audio data
97 to the output buffer (`pOutput` in the example). In capture mode you read data from the input
98 buffer (`pInput`) to extract sound captured by the microphone. The `frameCount` parameter tells you
99 how many frames can be written to the output buffer and read from the input buffer. A "frame" is
100 one sample for each channel. For example, in a stereo stream (2 channels), one frame is 2
101 samples: one for the left, one for the right. The channel count is defined by the device config.
102 The size in bytes of an individual sample is defined by the sample format which is also specified
103 in the device config. Multi-channel audio data is always interleaved, which means the samples for
104 each frame are stored next to each other in memory. For example, in a stereo stream the first pair
105 of samples will be the left and right samples for the first frame, the second pair of samples will
106 be the left and right samples for the second frame, etc.
107
108 The configuration of the device is defined by the `ma_device_config` structure. The config object
109 is always initialized with `ma_device_config_init()`. It's important to always initialize the
110 config with this function as it initializes it with logical defaults and ensures your program
111 doesn't break when new members are added to the `ma_device_config` structure. The example above
112 uses a fairly simple and standard device configuration. The call to `ma_device_config_init()` takes
113 a single parameter, which is whether or not the device is a playback, capture, duplex or loopback
114 device (loopback devices are not supported on all backends). The `config.playback.format` member
115 sets the sample format which can be one of the following (all formats are native-endian):
116
117     +---------------+----------------------------------------+---------------------------+
118     | Symbol        | Description                            | Range                     |
119     +---------------+----------------------------------------+---------------------------+
120     | ma_format_f32 | 32-bit floating point                  | [-1, 1]                   |
121     | ma_format_s16 | 16-bit signed integer                  | [-32768, 32767]           |
122     | ma_format_s24 | 24-bit signed integer (tightly packed) | [-8388608, 8388607]       |
123     | ma_format_s32 | 32-bit signed integer                  | [-2147483648, 2147483647] |
124     | ma_format_u8  | 8-bit unsigned integer                 | [0, 255]                  |
125     +---------------+----------------------------------------+---------------------------+
126
127 The `config.playback.channels` member sets the number of channels to use with the device. The
128 channel count cannot exceed MA_MAX_CHANNELS. The `config.sampleRate` member sets the sample rate
129 (which must be the same for both playback and capture in full-duplex configurations). This is
130 usually set to 44100 or 48000, but can be set to anything. It's recommended to keep this between
131 8000 and 384000, however.
132
133 Note that leaving the format, channel count and/or sample rate at their default values will result
134 in the internal device's native configuration being used which is useful if you want to avoid the
135 overhead of miniaudio's automatic data conversion.
136
137 In addition to the sample format, channel count and sample rate, the data callback and user data
138 pointer are also set via the config. The user data pointer is not passed into the callback as a
139 parameter, but is instead set to the `pUserData` member of `ma_device` which you can access
140 directly since all miniaudio structures are transparent.
141
142 Initializing the device is done with `ma_device_init()`. This will return a result code telling you
143 what went wrong, if anything. On success it will return `MA_SUCCESS`. After initialization is
144 complete the device will be in a stopped state. To start it, use `ma_device_start()`.
145 Uninitializing the device will stop it, which is what the example above does, but you can also stop
146 the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again.
147 Note that it's important to never stop or start the device from inside the callback. This will
148 result in a deadlock. Instead you set a variable or signal an event indicating that the device
149 needs to stop and handle it in a different thread. The following APIs must never be called inside
150 the callback:
151
152     ```c
153     ma_device_init()
154     ma_device_init_ex()
155     ma_device_uninit()
156     ma_device_start()
157     ma_device_stop()
158     ```
159
160 You must never try uninitializing and reinitializing a device inside the callback. You must also
161 never try to stop and start it from inside the callback. There are a few other things you shouldn't
162 do in the callback depending on your requirements, however this isn't so much a thread-safety
163 thing, but rather a real-time processing thing which is beyond the scope of this introduction.
164
165 The example above demonstrates the initialization of a playback device, but it works exactly the
166 same for capture. All you need to do is change the device type from `ma_device_type_playback` to
167 `ma_device_type_capture` when setting up the config, like so:
168
169     ```c
170     ma_device_config config = ma_device_config_init(ma_device_type_capture);
171     config.capture.format   = MY_FORMAT;
172     config.capture.channels = MY_CHANNEL_COUNT;
173     ```
174
175 In the data callback you just read from the input buffer (`pInput` in the example above) and leave
176 the output buffer alone (it will be set to NULL when the device type is set to
177 `ma_device_type_capture`).
178
179 These are the available device types and how you should handle the buffers in the callback:
180
181     +-------------------------+--------------------------------------------------------+
182     | Device Type             | Callback Behavior                                      |
183     +-------------------------+--------------------------------------------------------+
184     | ma_device_type_playback | Write to output buffer, leave input buffer untouched.  |
185     | ma_device_type_capture  | Read from input buffer, leave output buffer untouched. |
186     | ma_device_type_duplex   | Read from input buffer, write to output buffer.        |
187     | ma_device_type_loopback | Read from input buffer, leave output buffer untouched. |
188     +-------------------------+--------------------------------------------------------+
189
190 You will notice in the example above that the sample format and channel count is specified
191 separately for playback and capture. This is to support different data formats between the playback
192 and capture devices in a full-duplex system. An example may be that you want to capture audio data
193 as a monaural stream (one channel), but output sound to a stereo speaker system. Note that if you
194 use different formats between playback and capture in a full-duplex configuration you will need to
195 convert the data yourself. There are functions available to help you do this which will be
196 explained later.
197
198 The example above did not specify a physical device to connect to which means it will use the
199 operating system's default device. If you have multiple physical devices connected and you want to
200 use a specific one you will need to specify the device ID in the configuration, like so:
201
202     ```c
203     config.playback.pDeviceID = pMyPlaybackDeviceID;    // Only if requesting a playback or duplex device.
204     config.capture.pDeviceID = pMyCaptureDeviceID;      // Only if requesting a capture, duplex or loopback device.
205     ```
206
207 To retrieve the device ID you will need to perform device enumeration, however this requires the
208 use of a new concept called the "context". Conceptually speaking the context sits above the device.
209 There is one context to many devices. The purpose of the context is to represent the backend at a
210 more global level and to perform operations outside the scope of an individual device. Mainly it is
211 used for performing run-time linking against backend libraries, initializing backends and
212 enumerating devices. The example below shows how to enumerate devices.
213
214     ```c
215     ma_context context;
216     if (ma_context_init(NULL, 0, NULL, &context) != MA_SUCCESS) {
217         // Error.
218     }
219
220     ma_device_info* pPlaybackInfos;
221     ma_uint32 playbackCount;
222     ma_device_info* pCaptureInfos;
223     ma_uint32 captureCount;
224     if (ma_context_get_devices(&context, &pPlaybackInfos, &playbackCount, &pCaptureInfos, &captureCount) != MA_SUCCESS) {
225         // Error.
226     }
227
228     // Loop over each device info and do something with it. Here we just print the name with their index. You may want
229     // to give the user the opportunity to choose which device they'd prefer.
230     for (ma_uint32 iDevice = 0; iDevice < playbackCount; iDevice += 1) {
231         printf("%d - %s\n", iDevice, pPlaybackInfos[iDevice].name);
232     }
233
234     ma_device_config config = ma_device_config_init(ma_device_type_playback);
235     config.playback.pDeviceID = &pPlaybackInfos[chosenPlaybackDeviceIndex].id;
236     config.playback.format    = MY_FORMAT;
237     config.playback.channels  = MY_CHANNEL_COUNT;
238     config.sampleRate         = MY_SAMPLE_RATE;
239     config.dataCallback       = data_callback;
240     config.pUserData          = pMyCustomData;
241
242     ma_device device;
243     if (ma_device_init(&context, &config, &device) != MA_SUCCESS) {
244         // Error
245     }
246
247     ...
248
249     ma_device_uninit(&device);
250     ma_context_uninit(&context);
251     ```
252
253 The first thing we do in this example is initialize a `ma_context` object with `ma_context_init()`.
254 The first parameter is a pointer to a list of `ma_backend` values which are used to override the
255 default backend priorities. When this is NULL, as in this example, miniaudio's default priorities
256 are used. The second parameter is the number of backends listed in the array pointed to by the
257 first parameter. The third parameter is a pointer to a `ma_context_config` object which can be
258 NULL, in which case defaults are used. The context configuration is used for setting the logging
259 callback, custom memory allocation callbacks, user-defined data and some backend-specific
260 configurations.
261
262 Once the context has been initialized you can enumerate devices. In the example above we use the
263 simpler `ma_context_get_devices()`, however you can also use a callback for handling devices by
264 using `ma_context_enumerate_devices()`. When using `ma_context_get_devices()` you provide a pointer
265 to a pointer that will, upon output, be set to a pointer to a buffer containing a list of
266 `ma_device_info` structures. You also provide a pointer to an unsigned integer that will receive
267 the number of items in the returned buffer. Do not free the returned buffers as their memory is
268 managed internally by miniaudio.
269
270 The `ma_device_info` structure contains an `id` member which is the ID you pass to the device
271 config. It also contains the name of the device which is useful for presenting a list of devices
272 to the user via the UI.
273
274 When creating your own context you will want to pass it to `ma_device_init()` when initializing the
275 device. Passing in NULL, like we do in the first example, will result in miniaudio creating the
276 context for you, which you don't want to do since you've already created a context. Note that
277 internally the context is only tracked by it's pointer which means you must not change the location
278 of the `ma_context` object. If this is an issue, consider using `malloc()` to allocate memory for
279 the context.
280
281
282 1.2. High Level API
283 -------------------
284 The high level API consists of three main parts:
285
286   * Resource management for loading and streaming sounds.
287   * A node graph for advanced mixing and effect processing.
288   * A high level "engine" that wraps around the resource manager and node graph.
289
290 The resource manager (`ma_resource_manager`) is used for loading sounds. It supports loading sounds
291 fully into memory and also streaming. It will also deal with reference counting for you which
292 avoids the same sound being loaded multiple times.
293
294 The node graph is used for mixing and effect processing. The idea is that you connect a number of
295 nodes into the graph by connecting each node's outputs to another node's inputs. Each node can
296 implement it's own effect. By chaining nodes together, advanced mixing and effect processing can
297 be achieved.
298
299 The engine encapsulates both the resource manager and the node graph to create a simple, easy to
300 use high level API. The resource manager and node graph APIs are covered in more later sections of
301 this manual.
302
303 The code below shows how you can initialize an engine using it's default configuration.
304
305     ```c
306     ma_result result;
307     ma_engine engine;
308
309     result = ma_engine_init(NULL, &engine);
310     if (result != MA_SUCCESS) {
311         return result;  // Failed to initialize the engine.
312     }
313     ```
314
315 This creates an engine instance which will initialize a device internally which you can access with
316 `ma_engine_get_device()`. It will also initialize a resource manager for you which can be accessed
317 with `ma_engine_get_resource_manager()`. The engine itself is a node graph (`ma_node_graph`) which
318 means you can pass a pointer to the engine object into any of the `ma_node_graph` APIs (with a
319 cast). Alternatively, you can use `ma_engine_get_node_graph()` instead of a cast.
320
321 Note that all objects in miniaudio, including the `ma_engine` object in the example above, are
322 transparent structures. There are no handles to opaque structures in miniaudio which means you need
323 to be mindful of how you declare them. In the example above we are declaring it on the stack, but
324 this will result in the struct being invalidated once the function encapsulating it returns. If
325 allocating the engine on the heap is more appropriate, you can easily do so with a standard call
326 to `malloc()` or whatever heap allocation routine you like:
327
328     ```c
329     ma_engine* pEngine = malloc(sizeof(*pEngine));
330     ```
331
332 The `ma_engine` API uses the same config/init pattern used all throughout miniaudio. To configure
333 an engine, you can fill out a `ma_engine_config` object and pass it into the first parameter of
334 `ma_engine_init()`:
335
336     ```c
337     ma_result result;
338     ma_engine engine;
339     ma_engine_config engineConfig;
340
341     engineConfig = ma_engine_config_init();
342     engineConfig.pResourceManager = &myCustomResourceManager;   // <-- Initialized as some earlier stage.
343
344     result = ma_engine_init(&engineConfig, &engine);
345     if (result != MA_SUCCESS) {
346         return result;
347     }
348     ```
349
350 This creates an engine instance using a custom config. In this particular example it's showing how
351 you can specify a custom resource manager rather than having the engine initialize one internally.
352 This is particularly useful if you want to have multiple engine's share the same resource manager.
353
354 The engine must be uninitialized with `ma_engine_uninit()` when it's no longer needed.
355
356 By default the engine will be started, but nothing will be playing because no sounds have been
357 initialized. The easiest but least flexible way of playing a sound is like so:
358
359     ```c
360     ma_engine_play_sound(&engine, "my_sound.wav", NULL);
361     ```
362
363 This plays what miniaudio calls an "inline" sound. It plays the sound once, and then puts the
364 internal sound up for recycling. The last parameter is used to specify which sound group the sound
365 should be associated with which will be explained later. This particular way of playing a sound is
366 simple, but lacks flexibility and features. A more flexible way of playing a sound is to first 
367 initialize a sound:
368
369     ```c
370     ma_result result;
371     ma_sound sound;
372
373     result = ma_sound_init_from_file(&engine, "my_sound.wav", 0, NULL, NULL, &sound);
374     if (result != MA_SUCCESS) {
375         return result;
376     }
377
378     ma_sound_start(&sound);
379     ```
380
381 This returns a `ma_sound` object which represents a single instance of the specified sound file. If
382 you want to play the same file multiple times simultaneously, you need to create one sound for each
383 instance.
384
385 Sounds should be uninitialized with `ma_sound_uninit()`.
386
387 Sounds are not started by default. Start a sound with `ma_sound_start()` and stop it with
388 `ma_sound_stop()`. When a sound is stopped, it is not rewound to the start. Use
389 `ma_sound_seek_to_pcm_frames(&sound, 0)` to seek back to the start of a sound. By default, starting
390 and stopping sounds happens immediately, but sometimes it might be convenient to schedule the sound
391 the be started and/or stopped at a specific time. This can be done with the following functions:
392
393     ```c
394     ma_sound_set_start_time_in_pcm_frames()
395     ma_sound_set_start_time_in_milliseconds()
396     ma_sound_set_stop_time_in_pcm_frames()
397     ma_sound_set_stop_time_in_milliseconds()
398     ```
399
400 The start/stop time needs to be specified based on the absolute timer which is controlled by the
401 engine. The current global time time in PCM frames can be retrieved with `ma_engine_get_time()`.
402 The engine's global time can be changed with `ma_engine_set_time()` for synchronization purposes if
403 required.
404
405 The third parameter of `ma_sound_init_from_file()` is a set of flags that control how the sound be
406 loaded and a few options on which features should be enabled for that sound. By default, the sound
407 is synchronously loaded fully into memory straight from the file system without any kind of
408 decoding. If you want to decode the sound before storing it in memory, you need to specify the
409 `MA_SOUND_FLAG_DECODE` flag. This is useful if you want to incur the cost of decoding at an earlier
410 stage, such as a loading stage. Without this option, decoding will happen dynamically at mixing
411 time which might be too expensive on the audio thread.
412
413 If you want to load the sound asynchronously, you can specify the `MA_SOUND_FLAG_ASYNC` flag. This
414 will result in `ma_sound_init_from_file()` returning quickly, but the sound will not start playing
415 until the sound has had some audio decoded.
416
417 The fourth parameter is a pointer to sound group. A sound group is used as a mechanism to organise
418 sounds into groups which have their own effect processing and volume control. An example is a game
419 which might have separate groups for sfx, voice and music. Each of these groups have their own
420 independent volume control. Use `ma_sound_group_init()` or `ma_sound_group_init_ex()` to initialize
421 a sound group.
422
423 Sounds and sound groups are nodes in the engine's node graph and can be plugged into any `ma_node`
424 API. This makes it possible to connect sounds and sound groups to effect nodes to produce complex
425 effect chains.
426
427 A sound can have it's volume changed with `ma_sound_set_volume()`. If you prefer decibel volume
428 control you can use `ma_volume_db_to_linear()` to convert from decibel representation to linear.
429
430 Panning and pitching is supported with `ma_sound_set_pan()` and `ma_sound_set_pitch()`. If you know
431 a sound will never have it's pitch changed with `ma_sound_set_pitch()` or via the doppler effect,
432 you can specify the `MA_SOUND_FLAG_NO_PITCH` flag when initializing the sound for an optimization.
433
434 By default, sounds and sound groups have spatialization enabled. If you don't ever want to
435 spatialize your sounds, initialize the sound with the `MA_SOUND_FLAG_NO_SPATIALIZATION` flag. The
436 spatialization model is fairly simple and is roughly on feature parity with OpenAL. HRTF and
437 environmental occlusion are not currently supported, but planned for the future. The supported
438 features include:
439
440   * Sound and listener positioning and orientation with cones
441   * Attenuation models: none, inverse, linear and exponential
442   * Doppler effect
443
444 Sounds can be faded in and out with `ma_sound_set_fade_in_pcm_frames()`.
445
446 To check if a sound is currently playing, you can use `ma_sound_is_playing()`. To check if a sound
447 is at the end, use `ma_sound_at_end()`. Looping of a sound can be controlled with
448 `ma_sound_set_looping()`. Use `ma_sound_is_looping()` to check whether or not the sound is looping.
449
450
451
452 2. Building
453 ===========
454 miniaudio should work cleanly out of the box without the need to download or install any
455 dependencies. See below for platform-specific details.
456
457
458 2.1. Windows
459 ------------
460 The Windows build should compile cleanly on all popular compilers without the need to configure any
461 include paths nor link to any libraries.
462
463 The UWP build may require linking to mmdevapi.lib if you get errors about an unresolved external
464 symbol for `ActivateAudioInterfaceAsync()`.
465
466
467 2.2. macOS and iOS
468 ------------------
469 The macOS build should compile cleanly without the need to download any dependencies nor link to
470 any libraries or frameworks. The iOS build needs to be compiled as Objective-C and will need to
471 link the relevant frameworks but should compile cleanly out of the box with Xcode. Compiling
472 through the command line requires linking to `-lpthread` and `-lm`.
473
474 Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's
475 notarization process. To fix this there are two options. The first is to use the
476 `MA_NO_RUNTIME_LINKING` option, like so:
477
478     ```c
479     #ifdef __APPLE__
480         #define MA_NO_RUNTIME_LINKING
481     #endif
482     #define MINIAUDIO_IMPLEMENTATION
483     #include "miniaudio.h"
484     ```
485
486 This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioUnit`.
487 Alternatively, if you would rather keep using runtime linking you can add the following to your
488 entitlements.xcent file:
489
490     ```
491     <key>com.apple.security.cs.allow-dyld-environment-variables</key>
492     <true/>
493     <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
494     <true/>
495     ```
496
497
498 2.3. Linux
499 ----------
500 The Linux build only requires linking to `-ldl`, `-lpthread` and `-lm`. You do not need any
501 development packages. You may need to link with `-latomic` if you're compiling for 32-bit ARM.
502
503
504 2.4. BSD
505 --------
506 The BSD build only requires linking to `-lpthread` and `-lm`. NetBSD uses audio(4), OpenBSD uses
507 sndio and FreeBSD uses OSS. You may need to link with `-latomic` if you're compiling for 32-bit
508 ARM.
509
510
511 2.5. Android
512 ------------
513 AAudio is the highest priority backend on Android. This should work out of the box without needing
514 any kind of compiler configuration. Support for AAudio starts with Android 8 which means older
515 versions will fall back to OpenSL|ES which requires API level 16+.
516
517 There have been reports that the OpenSL|ES backend fails to initialize on some Android based
518 devices due to `dlopen()` failing to open "libOpenSLES.so". If this happens on your platform
519 you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link with -lOpenSLES.
520
521
522 2.6. Emscripten
523 ---------------
524 The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box.
525 You cannot use `-std=c*` compiler flags, nor `-ansi`.
526
527
528 2.7. Build Options
529 ------------------
530 `#define` these options before including miniaudio.h.
531
532     +----------------------------------+--------------------------------------------------------------------+
533     | Option                           | Description                                                        |
534     +----------------------------------+--------------------------------------------------------------------+
535     | MA_NO_WASAPI                     | Disables the WASAPI backend.                                       |
536     +----------------------------------+--------------------------------------------------------------------+
537     | MA_NO_DSOUND                     | Disables the DirectSound backend.                                  |
538     +----------------------------------+--------------------------------------------------------------------+
539     | MA_NO_WINMM                      | Disables the WinMM backend.                                        |
540     +----------------------------------+--------------------------------------------------------------------+
541     | MA_NO_ALSA                       | Disables the ALSA backend.                                         |
542     +----------------------------------+--------------------------------------------------------------------+
543     | MA_NO_PULSEAUDIO                 | Disables the PulseAudio backend.                                   |
544     +----------------------------------+--------------------------------------------------------------------+
545     | MA_NO_JACK                       | Disables the JACK backend.                                         |
546     +----------------------------------+--------------------------------------------------------------------+
547     | MA_NO_COREAUDIO                  | Disables the Core Audio backend.                                   |
548     +----------------------------------+--------------------------------------------------------------------+
549     | MA_NO_SNDIO                      | Disables the sndio backend.                                        |
550     +----------------------------------+--------------------------------------------------------------------+
551     | MA_NO_AUDIO4                     | Disables the audio(4) backend.                                     |
552     +----------------------------------+--------------------------------------------------------------------+
553     | MA_NO_OSS                        | Disables the OSS backend.                                          |
554     +----------------------------------+--------------------------------------------------------------------+
555     | MA_NO_AAUDIO                     | Disables the AAudio backend.                                       |
556     +----------------------------------+--------------------------------------------------------------------+
557     | MA_NO_OPENSL                     | Disables the OpenSL|ES backend.                                    |
558     +----------------------------------+--------------------------------------------------------------------+
559     | MA_NO_WEBAUDIO                   | Disables the Web Audio backend.                                    |
560     +----------------------------------+--------------------------------------------------------------------+
561     | MA_NO_NULL                       | Disables the null backend.                                         |
562     +----------------------------------+--------------------------------------------------------------------+
563     | MA_ENABLE_ONLY_SPECIFIC_BACKENDS | Disables all backends by default and requires `MA_ENABLE_*` to     |
564     |                                  | enable specific backends.                                          |
565     +----------------------------------+--------------------------------------------------------------------+
566     | MA_ENABLE_WASAPI                 | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
567     |                                  | enable the WASAPI backend.                                         |
568     +----------------------------------+--------------------------------------------------------------------+
569     | MA_ENABLE_DSOUND                 | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
570     |                                  | enable the DirectSound backend.                                    |
571     +----------------------------------+--------------------------------------------------------------------+
572     | MA_ENABLE_WINMM                  | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
573     |                                  | enable the WinMM backend.                                          |
574     +----------------------------------+--------------------------------------------------------------------+
575     | MA_ENABLE_ALSA                   | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
576     |                                  | enable the ALSA backend.                                           |
577     +----------------------------------+--------------------------------------------------------------------+
578     | MA_ENABLE_PULSEAUDIO             | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
579     |                                  | enable the PulseAudio backend.                                     |
580     +----------------------------------+--------------------------------------------------------------------+
581     | MA_ENABLE_JACK                   | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
582     |                                  | enable the JACK backend.                                           |
583     +----------------------------------+--------------------------------------------------------------------+
584     | MA_ENABLE_COREAUDIO              | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
585     |                                  | enable the Core Audio backend.                                     |
586     +----------------------------------+--------------------------------------------------------------------+
587     | MA_ENABLE_SNDIO                  | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
588     |                                  | enable the sndio backend.                                          |
589     +----------------------------------+--------------------------------------------------------------------+
590     | MA_ENABLE_AUDIO4                 | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
591     |                                  | enable the audio(4) backend.                                       |
592     +----------------------------------+--------------------------------------------------------------------+
593     | MA_ENABLE_OSS                    | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
594     |                                  | enable the OSS backend.                                            |
595     +----------------------------------+--------------------------------------------------------------------+
596     | MA_ENABLE_AAUDIO                 | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
597     |                                  | enable the AAudio backend.                                         |
598     +----------------------------------+--------------------------------------------------------------------+
599     | MA_ENABLE_OPENSL                 | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
600     |                                  | enable the OpenSL|ES backend.                                      |
601     +----------------------------------+--------------------------------------------------------------------+
602     | MA_ENABLE_WEBAUDIO               | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
603     |                                  | enable the Web Audio backend.                                      |
604     +----------------------------------+--------------------------------------------------------------------+
605     | MA_ENABLE_NULL                   | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
606     |                                  | enable the null backend.                                           |
607     +----------------------------------+--------------------------------------------------------------------+
608     | MA_NO_DECODING                   | Disables decoding APIs.                                            |
609     +----------------------------------+--------------------------------------------------------------------+
610     | MA_NO_ENCODING                   | Disables encoding APIs.                                            |
611     +----------------------------------+--------------------------------------------------------------------+
612     | MA_NO_WAV                        | Disables the built-in WAV decoder and encoder.                     |
613     +----------------------------------+--------------------------------------------------------------------+
614     | MA_NO_FLAC                       | Disables the built-in FLAC decoder.                                |
615     +----------------------------------+--------------------------------------------------------------------+
616     | MA_NO_MP3                        | Disables the built-in MP3 decoder.                                 |
617     +----------------------------------+--------------------------------------------------------------------+
618     | MA_NO_DEVICE_IO                  | Disables playback and recording. This will disable `ma_context`    |
619     |                                  | and `ma_device` APIs. This is useful if you only want to use       |
620     |                                  | miniaudio's data conversion and/or decoding APIs.                  |
621     +----------------------------------+--------------------------------------------------------------------+
622     | MA_NO_THREADING                  | Disables the `ma_thread`, `ma_mutex`, `ma_semaphore` and           |
623     |                                  | `ma_event` APIs. This option is useful if you only need to use     |
624     |                                  | miniaudio for data conversion, decoding and/or encoding. Some      |
625     |                                  | families of APIsrequire threading which means the following        |
626     |                                  | options must also be set:                                          |
627     |                                  |                                                                    |
628     |                                  |     ```                                                            |
629     |                                  |     MA_NO_DEVICE_IO                                                |
630     |                                  |     ```                                                            |
631     +----------------------------------+--------------------------------------------------------------------+
632     | MA_NO_GENERATION                 | Disables generation APIs such a `ma_waveform` and `ma_noise`.      |
633     +----------------------------------+--------------------------------------------------------------------+
634     | MA_NO_SSE2                       | Disables SSE2 optimizations.                                       |
635     +----------------------------------+--------------------------------------------------------------------+
636     | MA_NO_AVX2                       | Disables AVX2 optimizations.                                       |
637     +----------------------------------+--------------------------------------------------------------------+
638     | MA_NO_NEON                       | Disables NEON optimizations.                                       |
639     +----------------------------------+--------------------------------------------------------------------+
640     | MA_NO_RUNTIME_LINKING            | Disables runtime linking. This is useful for passing Apple's       |
641     |                                  | notarization process. When enabling this, you may need to avoid    |
642     |                                  | using `-std=c89` or `-std=c99` on Linux builds or else you may end |
643     |                                  | up with compilation errors due to conflicts with `timespec` and    |
644     |                                  | `timeval` data types.                                              |
645     |                                  |                                                                    |
646     |                                  | You may need to enable this if your target platform does not allow |
647     |                                  | runtime linking via `dlopen()`.                                    |
648     +----------------------------------+--------------------------------------------------------------------+
649     | MA_DEBUG_OUTPUT                  | Enable processing of `MA_LOG_LEVEL_DEBUG` messages and `printf()`  |
650     |                                  | output.                                                            |
651     +----------------------------------+--------------------------------------------------------------------+
652     | MA_COINIT_VALUE                  | Windows only. The value to pass to internal calls to               |
653     |                                  | `CoInitializeEx()`. Defaults to `COINIT_MULTITHREADED`.            |
654     +----------------------------------+--------------------------------------------------------------------+
655     | MA_API                           | Controls how public APIs should be decorated. Default is `extern`. |
656     +----------------------------------+--------------------------------------------------------------------+
657     | MA_DLL                           | If set, configures `MA_API` to either import or export APIs        |
658     |                                  | depending on whether or not the implementation is being defined.   |
659     |                                  | If defining the implementation, `MA_API` will be configured to     |
660     |                                  | export. Otherwise it will be configured to import. This has no     |
661     |                                  | effect if `MA_API` is defined externally.                          |
662     +----------------------------------+--------------------------------------------------------------------+
663
664
665 3. Definitions
666 ==============
667 This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity
668 in the use of terms throughout the audio space, so this section is intended to clarify how miniaudio
669 uses each term.
670
671 3.1. Sample
672 -----------
673 A sample is a single unit of audio data. If the sample format is f32, then one sample is one 32-bit
674 floating point number.
675
676 3.2. Frame / PCM Frame
677 ----------------------
678 A frame is a group of samples equal to the number of channels. For a stereo stream a frame is 2
679 samples, a mono frame is 1 sample, a 5.1 surround sound frame is 6 samples, etc. The terms "frame"
680 and "PCM frame" are the same thing in miniaudio. Note that this is different to a compressed frame.
681 If ever miniaudio needs to refer to a compressed frame, such as a FLAC frame, it will always
682 clarify what it's referring to with something like "FLAC frame".
683
684 3.3. Channel
685 ------------
686 A stream of monaural audio that is emitted from an individual speaker in a speaker system, or
687 received from an individual microphone in a microphone system. A stereo stream has two channels (a
688 left channel, and a right channel), a 5.1 surround sound system has 6 channels, etc. Some audio
689 systems refer to a channel as a complex audio stream that's mixed with other channels to produce
690 the final mix - this is completely different to miniaudio's use of the term "channel" and should
691 not be confused.
692
693 3.4. Sample Rate
694 ----------------
695 The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It's the number
696 of PCM frames that are processed per second.
697
698 3.5. Formats
699 ------------
700 Throughout miniaudio you will see references to different sample formats:
701
702     +---------------+----------------------------------------+---------------------------+
703     | Symbol        | Description                            | Range                     |
704     +---------------+----------------------------------------+---------------------------+
705     | ma_format_f32 | 32-bit floating point                  | [-1, 1]                   |
706     | ma_format_s16 | 16-bit signed integer                  | [-32768, 32767]           |
707     | ma_format_s24 | 24-bit signed integer (tightly packed) | [-8388608, 8388607]       |
708     | ma_format_s32 | 32-bit signed integer                  | [-2147483648, 2147483647] |
709     | ma_format_u8  | 8-bit unsigned integer                 | [0, 255]                  |
710     +---------------+----------------------------------------+---------------------------+
711
712 All formats are native-endian.
713
714
715
716 4. Data Sources
717 ===============
718 The data source abstraction in miniaudio is used for retrieving audio data from some source. A few
719 examples include `ma_decoder`, `ma_noise` and `ma_waveform`. You will need to be familiar with data
720 sources in order to make sense of some of the higher level concepts in miniaudio.
721
722 The `ma_data_source` API is a generic interface for reading from a data source. Any object that
723 implements the data source interface can be plugged into any `ma_data_source` function.
724
725 To read data from a data source:
726
727     ```c
728     ma_result result;
729     ma_uint64 framesRead;
730
731     result = ma_data_source_read_pcm_frames(pDataSource, pFramesOut, frameCount, &framesRead, loop);
732     if (result != MA_SUCCESS) {
733         return result;  // Failed to read data from the data source.
734     }
735     ```
736
737 If you don't need the number of frames that were successfully read you can pass in `NULL` to the
738 `pFramesRead` parameter. If this returns a value less than the number of frames requested it means
739 the end of the file has been reached. `MA_AT_END` will be returned only when the number of frames
740 read is 0.
741
742 When calling any data source function, with the exception of `ma_data_source_init()` and
743 `ma_data_source_uninit()`, you can pass in any object that implements a data source. For example,
744 you could plug in a decoder like so:
745
746     ```c
747     ma_result result;
748     ma_uint64 framesRead;
749     ma_decoder decoder;   // <-- This would be initialized with `ma_decoder_init_*()`.
750
751     result = ma_data_source_read_pcm_frames(&decoder, pFramesOut, frameCount, &framesRead, loop);
752     if (result != MA_SUCCESS) {
753         return result;  // Failed to read data from the decoder.
754     }
755     ```
756
757 If you want to seek forward you can pass in `NULL` to the `pFramesOut` parameter. Alternatively you
758 can use `ma_data_source_seek_pcm_frames()`.
759
760 To seek to a specific PCM frame:
761
762     ```c
763     result = ma_data_source_seek_to_pcm_frame(pDataSource, frameIndex);
764     if (result != MA_SUCCESS) {
765         return result;  // Failed to seek to PCM frame.
766     }
767     ```
768
769 You can retrieve the total length of a data source in PCM frames, but note that some data sources
770 may not have the notion of a length, such as noise and waveforms, and others may just not have a
771 way of determining the length such as some decoders. To retrieve the length:
772
773     ```c
774     ma_uint64 length;
775
776     result = ma_data_source_get_length_in_pcm_frames(pDataSource, &length);
777     if (result != MA_SUCCESS) {
778         return result;  // Failed to retrieve the length.
779     }
780     ```
781
782 Care should be taken when retrieving the length of a data source where the underlying decoder is
783 pulling data from a data stream with an undefined length, such as internet radio or some kind of
784 broadcast. If you do this, `ma_data_source_get_length_in_pcm_frames()` may never return.
785
786 The current position of the cursor in PCM frames can also be retrieved:
787
788     ```c
789     ma_uint64 cursor;
790
791     result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &cursor);
792     if (result != MA_SUCCESS) {
793         return result;  // Failed to retrieve the cursor.
794     }
795     ```
796
797 You will often need to know the data format that will be returned after reading. This can be
798 retrieved like so:
799
800     ```c
801     ma_format format;
802     ma_uint32 channels;
803     ma_uint32 sampleRate;
804     ma_channel channelMap[MA_MAX_CHANNELS];
805     
806     result = ma_data_source_get_data_format(pDataSource, &format, &channels, &sampleRate, channelMap, MA_MAX_CHANNELS);
807     if (result != MA_SUCCESS) {
808         return result;  // Failed to retrieve data format.
809     }
810     ```
811
812 If you do not need a specific data format property, just pass in NULL to the respective parameter.
813
814 There may be cases where you want to implement something like a sound bank where you only want to
815 read data within a certain range of the underlying data. To do this you can use a range:
816
817     ```c
818     result = ma_data_source_set_range_in_pcm_frames(pDataSource, rangeBegInFrames, rangeEndInFrames);
819     if (result != MA_SUCCESS) {
820         return result;  // Failed to set the range.
821     }
822     ```
823
824 This is useful if you have a sound bank where many sounds are stored in the same file and you want
825 the data source to only play one of those sub-sounds.
826
827 Custom loop points can also be used with data sources. By default, data sources will loop after
828 they reach the end of the data source, but if you need to loop at a specific location, you can do
829 the following:
830
831     ```c
832     result = ma_data_set_loop_point_in_pcm_frames(pDataSource, loopBegInFrames, loopEndInFrames);
833     if (result != MA_SUCCESS) {
834         return result;  // Failed to set the loop point.
835     }
836     ```
837
838 The loop point is relative to the current range.
839
840 It's sometimes useful to chain data sources together so that a seamless transition can be achieved.
841 To do this, you can use chaining:
842
843     ```c
844     ma_decoder decoder1;
845     ma_decoder decoder2;
846
847     // ... initialize decoders with ma_decoder_init_*() ...
848
849     result = ma_data_source_set_next(&decoder1, &decoder2);
850     if (result != MA_SUCCESS) {
851         return result;  // Failed to set the next data source.
852     }
853
854     result = ma_data_source_read_pcm_frames(&decoder1, pFramesOut, frameCount, pFramesRead, MA_FALSE);
855     if (result != MA_SUCCESS) {
856         return result;  // Failed to read from the decoder.
857     }
858     ```
859
860 In the example above we're using decoders. When reading from a chain, you always want to read from
861 the top level data source in the chain. In the example above, `decoder1` is the top level data 
862 source in the chain. When `decoder1` reaches the end, `decoder2` will start seamlessly without any
863 gaps.
864
865 Note that the `loop` parameter is set to false in the example above. When this is set to true, only
866 the current data source will be looped. You can loop the entire chain by linking in a loop like so:
867
868     ```c
869     ma_data_source_set_next(&decoder1, &decoder2);  // decoder1 -> decoder2
870     ma_data_source_set_next(&decoder2, &decoder1);  // decoder2 -> decoder1 (loop back to the start).
871     ```
872
873 Note that setting up chaining is not thread safe, so care needs to be taken if you're dynamically
874 changing links while the audio thread is in the middle of reading.
875
876 Do not use `ma_decoder_seek_to_pcm_frame()` as a means to reuse a data source to play multiple
877 instances of the same sound simultaneously. Instead, initialize multiple data sources for each
878 instance. This can be extremely inefficient depending on the data source and can result in
879 glitching due to subtle changes to the state of internal filters.
880
881
882 4.1. Custom Data Sources
883 ------------------------
884 You can implement a custom data source by implementing the functions in `ma_data_source_vtable`.
885 Your custom object must have `ma_data_source_base` as it's first member:
886
887     ```c
888     struct my_data_source
889     {
890         ma_data_source_base base;
891         ...
892     };
893     ```
894
895 In your initialization routine, you need to call `ma_data_source_init()` in order to set up the
896 base object (`ma_data_source_base`):
897
898     ```c
899     static ma_result my_data_source_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
900     {
901         // Read data here. Output in the same format returned by my_data_source_get_data_format().
902     }
903
904     static ma_result my_data_source_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
905     {
906         // Seek to a specific PCM frame here. Return MA_NOT_IMPLEMENTED if seeking is not supported.
907     }
908
909     static ma_result my_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
910     {
911         // Return the format of the data here.
912     }
913
914     static ma_result my_data_source_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
915     {
916         // Retrieve the current position of the cursor here. Return MA_NOT_IMPLEMENTED and set *pCursor to 0 if there is no notion of a cursor.
917     }
918
919     static ma_result my_data_source_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
920     {
921         // Retrieve the length in PCM frames here. Return MA_NOT_IMPLEMENTED and set *pLength to 0 if there is no notion of a length or if the length is unknown.
922     }
923
924     static g_my_data_source_vtable =
925     {
926         my_data_source_read,
927         my_data_source_seek,
928         my_data_source_get_data_format,
929         my_data_source_get_cursor,
930         my_data_source_get_length
931     };
932
933     ma_result my_data_source_init(my_data_source* pMyDataSource)
934     {
935         ma_result result;
936         ma_data_source_config baseConfig;
937
938         baseConfig = ma_data_source_config_init();
939         baseConfig.vtable = &g_my_data_source_vtable;
940
941         result = ma_data_source_init(&baseConfig, &pMyDataSource->base);
942         if (result != MA_SUCCESS) {
943             return result;
944         }
945
946         // ... do the initialization of your custom data source here ...
947
948         return MA_SUCCESS;
949     }
950
951     void my_data_source_uninit(my_data_source* pMyDataSource)
952     {
953         // ... do the uninitialization of your custom data source here ...
954         
955         // You must uninitialize the base data source.
956         ma_data_source_uninit(&pMyDataSource->base);
957     }
958     ```
959
960 Note that `ma_data_source_init()` and `ma_data_source_uninit()` are never called directly outside
961 of the custom data source. It's up to the custom data source itself to call these within their own
962 init/uninit functions.
963
964
965
966 5. Engine
967 =========
968 The `ma_engine` API is a high level API for managing and mixing sounds and effect processing. The
969 `ma_engine` object encapsulates a resource manager and a node graph, both of which will be
970 explained in more detail later.
971
972 Sounds are called `ma_sound` and are created from an engine. Sounds can be associated with a mixing
973 group called `ma_sound_group` which are also created from the engine. Both `ma_sound` and
974 `ma_sound_group` objects are nodes within the engine's node graph.
975
976 When the engine is initialized, it will normally create a device internally. If you would rather
977 manage the device yourself, you can do so and just pass a pointer to it via the engine config when
978 you initialize the engine. You can also just use the engine without a device, which again can be
979 configured via the engine config.
980
981 The most basic way to initialize the engine is with a default config, like so:
982
983     ```c
984     ma_result result;
985     ma_engine engine;
986
987     result = ma_engine_init(NULL, &engine);
988     if (result != MA_SUCCESS) {
989         return result;  // Failed to initialize the engine.
990     }
991     ```
992
993 This will result in the engine initializing a playback device using the operating system's default
994 device. This will be sufficient for many use cases, but if you need more flexibility you'll want to
995 configure the engine with an engine config:
996
997     ```c
998     ma_result result;
999     ma_engine engine;
1000     ma_engine_config engineConfig;
1001
1002     engineConfig = ma_engine_config_init();
1003     engineConfig.pPlaybackDevice = &myDevice;
1004
1005     result = ma_engine_init(&engineConfig, &engine);
1006     if (result != MA_SUCCESS) {
1007         return result;  // Failed to initialize the engine.
1008     }
1009     ```
1010
1011 In the example above we're passing in a pre-initialized device. Since the caller is the one in
1012 control of the device's data callback, it's their responsibility to manually call
1013 `ma_engine_read_pcm_frames()` from inside their data callback:
1014
1015     ```c
1016     void playback_data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
1017     {
1018         ma_engine_read_pcm_frames(&g_Engine, pOutput, frameCount, NULL);
1019     }
1020     ```
1021
1022 You can also use the engine independent of a device entirely:
1023
1024     ```c
1025     ma_result result;
1026     ma_engine engine;
1027     ma_engine_config engineConfig;
1028
1029     engineConfig = ma_engine_config_init();
1030     engineConfig.noDevice   = MA_TRUE;
1031     engineConfig.channels   = 2;        // Must be set when not using a device.
1032     engineConfig.sampleRate = 48000;    // Must be set when not using a device.
1033
1034     result = ma_engine_init(&engineConfig, &engine);
1035     if (result != MA_SUCCESS) {
1036         return result;  // Failed to initialize the engine.
1037     }
1038     ```
1039
1040 Note that when you're not using a device, you must set the channel count and sample rate in the
1041 config or else miniaudio won't know what to use (miniaudio will use the device to determine this
1042 normally). When not using a device, you need to use `ma_engine_read_pcm_frames()` to process audio
1043 data from the engine. This kind of setup is useful if you want to do something like offline
1044 processing.
1045
1046 When a sound is loaded it goes through a resource manager. By default the engine will initialize a
1047 resource manager internally, but you can also specify a pre-initialized resource manager:
1048
1049     ```c
1050     ma_result result;
1051     ma_engine engine1;
1052     ma_engine engine2;
1053     ma_engine_config engineConfig;
1054
1055     engineConfig = ma_engine_config_init();
1056     engineConfig.pResourceManager = &myResourceManager;
1057
1058     ma_engine_init(&engineConfig, &engine1);
1059     ma_engine_init(&engineConfig, &engine2);
1060     ```
1061
1062 In this example we are initializing two engines, both of which are sharing the same resource
1063 manager. This is especially useful for saving memory when loading the same file across multiple
1064 engines. If you were not to use a shared resource manager, each engine instance would use their own
1065 which would result in any sounds that are used between both engine's being loaded twice. By using
1066 a shared resource manager, it would only be loaded once. Using multiple engine's is useful when you
1067 need to output to multiple playback devices, such as in a local multiplayer game where each player
1068 is using their own set of headphones.
1069
1070 By default an engine will be in a started state. To make it so the engine is not automatically
1071 started you can configure it as such:
1072
1073     ```c
1074     engineConfig.noAutoStart = MA_TRUE;
1075
1076     // The engine will need to be started manually.
1077     ma_engine_start(&engine);
1078
1079     // Later on the engine can be stopped with ma_engine_stop().
1080     ma_engine_stop(&engine);
1081     ```
1082
1083 The concept of starting or stopping an engine is only relevant when using the engine with a
1084 device. Attempting to start or stop an engine that is not associated with a device will result in
1085 `MA_INVALID_OPERATION`.
1086
1087 The master volume of the engine can be controlled with `ma_engine_set_volume()` which takes a
1088 linear scale, with 0 resulting in silence and anything above 1 resulting in amplification. If you
1089 prefer decibel based volume control, use `ma_volume_db_to_linear()` to convert from dB to linear.
1090
1091 When a sound is spatialized, it is done so relative to a listener. An engine can be configured to
1092 have multiple listeners which can be configured via the config:
1093
1094     ```c
1095     engineConfig.listenerCount = 2;
1096     ```
1097
1098 The maximum number of listeners is restricted to `MA_ENGINE_MAX_LISTENERS`. By default, when a
1099 sound is spatialized, it will be done so relative to the closest listener. You can also pin a sound
1100 to a specific listener which will be explained later. Listener's have a position, direction, cone,
1101 and velocity (for doppler effect). A listener is referenced by an index, the meaning of which is up
1102 to the caller (the index is 0 based and cannot go beyond the listener count, minus 1). The
1103 position, direction and velocity are all specified in absolute terms:
1104
1105     ```c
1106     ma_engine_listener_set_position(&engine, listenerIndex, worldPosX, worldPosY, worldPosZ);
1107     ```
1108
1109 The direction of the listener represents it's forward vector. The listener's up vector can also be
1110 specified and defaults to +1 on the Y axis.
1111
1112     ```c
1113     ma_engine_listener_set_direction(&engine, listenerIndex, forwardX, forwardY, forwardZ);
1114     ma_engine_listener_set_world_up(&engine, listenerIndex, 0, 1, 0);
1115     ```
1116
1117 The engine supports directional attenuation. The listener can have a cone the controls how sound is
1118 attenuated based on the listener's direction. When a sound is between the inner and outer cones, it
1119 will be attenuated between 1 and the cone's outer gain:
1120
1121     ```c
1122     ma_engine_listener_set_cone(&engine, listenerIndex, innerAngleInRadians, outerAngleInRadians, outerGain);
1123     ```
1124
1125 When a sound is inside the inner code, no directional attenuation is applied. When the sound is
1126 outside of the outer cone, the attenuation will be set to `outerGain` in the example above. When
1127 the sound is in between the inner and outer cones, the attenuation will be interpolated between 1
1128 and the outer gain.
1129
1130 The engine's coordinate system follows the OpenGL coordinate system where positive X points right,
1131 positive Y points up and negative Z points forward.
1132
1133 The simplest and least flexible way to play a sound is like so:
1134
1135     ```c
1136     ma_engine_play_sound(&engine, "my_sound.wav", pGroup);
1137     ```
1138
1139 This is a "fire and forget" style of function. The engine will manage the `ma_sound` object
1140 internally. When the sound finishes playing, it'll be put up for recycling. For more flexibility
1141 you'll want to initialize a sound object:
1142
1143     ```c
1144     ma_sound sound;
1145
1146     result = ma_sound_init_from_file(&engine, "my_sound.wav", flags, pGroup, NULL, &sound);
1147     if (result != MA_SUCCESS) {
1148         return result;  // Failed to load sound.
1149     }
1150     ```
1151
1152 Sounds need to be uninitialized with `ma_sound_uninit()`.
1153
1154 The example above loads a sound from a file. If the resource manager has been disabled you will not
1155 be able to use this function and instead you'll need to initialize a sound directly from a data
1156 source:
1157
1158     ```c
1159     ma_sound sound;
1160
1161     result = ma_sound_init_from_data_source(&engine, &dataSource, flags, pGroup, &sound);
1162     if (result != MA_SUCCESS) {
1163         return result;
1164     }
1165     ```
1166
1167 Each `ma_sound` object represents a single instance of the sound. If you want to play the same
1168 sound multiple times at the same time, you need to initialize a separate `ma_sound` object.
1169
1170 For the most flexibility when initializing sounds, use `ma_sound_init_ex()`. This uses miniaudio's
1171 standard config/init pattern:
1172
1173     ```c
1174     ma_sound sound;
1175     ma_sound_config soundConfig;
1176
1177     soundConfig = ma_sound_config_init();
1178     soundConfig.pFilePath   = NULL; // Set this to load from a file path.
1179     soundConfig.pDataSource = NULL; // Set this to initialize from an existing data source.
1180     soundConfig.pInitialAttachment = &someNodeInTheNodeGraph;
1181     soundConfig.initialAttachmentInputBusIndex = 0;
1182     soundConfig.channelsIn  = 1;
1183     soundConfig.channelsOut = 0;    // Set to 0 to use the engine's native channel count.
1184
1185     result = ma_sound_init_ex(&soundConfig, &sound);
1186     if (result != MA_SUCCESS) {
1187         return result;
1188     }
1189     ```
1190
1191 In the example above, the sound is being initialized without a file nor a data source. This is
1192 valid, in which case the sound acts as a node in the middle of the node graph. This means you can
1193 connect other sounds to this sound and allow it to act like a sound group. Indeed, this is exactly
1194 what a `ma_sound_group` is.
1195
1196 When loading a sound, you specify a set of flags that control how the sound is loaded and what
1197 features are enabled for that sound. When no flags are set, the sound will be fully loaded into
1198 memory in exactly the same format as how it's stored on the file system. The resource manager will
1199 allocate a block of memory and then load the file directly into it. When reading audio data, it
1200 will be decoded dynamically on the fly. In order to save processing time on the audio thread, it
1201 might be beneficial to pre-decode the sound. You can do this with the `MA_SOUND_FLAG_DECODE` flag:
1202
1203     ```c
1204     ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_DECODE, pGroup, NULL, &sound);
1205     ```
1206
1207 By default, sounds will be loaded synchronously, meaning `ma_sound_init_*()` will not return until
1208 the sound has been fully loaded. If this is prohibitive you can instead load sounds asynchronously
1209 by specificying the `MA_SOUND_FLAG_ASYNC` flag:
1210
1211     ```c
1212     ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, pGroup, NULL, &sound);
1213     ```
1214
1215 This will result in `ma_sound_init_*()` returning quickly, but the sound won't yet have been fully
1216 loaded. When you start the sound, it won't output anything until some sound is available. The sound
1217 will start outputting audio before the sound has been fully decoded when the `MA_SOUND_FLAG_DECODE`
1218 is specified.
1219
1220 If you need to wait for an asynchronously loaded sound to be fully loaded, you can use a fence. A
1221 fence in miniaudio is a simple synchronization mechanism which simply blocks until it's internal
1222 counter hit's zero. You can specify a fence like so:
1223
1224     ```c
1225     ma_result result;
1226     ma_fence fence;
1227     ma_sound sounds[4];
1228
1229     result = ma_fence_init(&fence);
1230     if (result != MA_SUCCES) {
1231         return result;
1232     }
1233
1234     // Load some sounds asynchronously.
1235     for (int iSound = 0; iSound < 4; iSound += 1) {
1236         ma_sound_init_from_file(&engine, mySoundFilesPaths[iSound], MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, pGroup, &fence, &sounds[iSound]);
1237     }
1238
1239     // ... do some other stuff here in the mean time ...
1240
1241     // Wait for all sounds to finish loading.
1242     ma_fence_wait(&fence);
1243     ```
1244
1245 If loading the entire sound into memory is prohibitive, you can also configure the engine to stream
1246 the audio data:
1247
1248     ```c
1249     ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_STREAM, pGroup, NULL, &sound);
1250     ```
1251
1252 When streaming sounds, 2 seconds worth of audio data is stored in memory. Although it should work
1253 fine, it's inefficient to use streaming for short sounds. Streaming is useful for things like music
1254 tracks in games.
1255
1256 When you initialize a sound, if you specify a sound group the sound will be attached to that group
1257 automatically. If you set it to NULL, it will be automatically attached to the engine's endpoint.
1258 If you would instead rather leave the sound unattached by default, you can can specify the
1259 `MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT` flag. This is useful if you want to set up a complex node
1260 graph.
1261
1262 Sounds are not started by default. To start a sound, use `ma_sound_start()`. Stop a sound with
1263 `ma_sound_stop()`.
1264
1265 Sounds can have their volume controlled with `ma_sound_set_volume()` in the same way as the
1266 engine's master volume.
1267
1268 Sounds support stereo panning and pitching. Set the pan with `ma_sound_set_pan()`. Setting the pan
1269 to 0 will result in an unpanned sound. Setting it to -1 will shift everything to the left, whereas
1270 +1 will shift it to the right. The pitch can be controlled with `ma_sound_set_pitch()`. A larger
1271 value will result in a higher pitch. The pitch must be greater than 0.
1272
1273 The engine supports 3D spatialization of sounds. By default sounds will have spatialization
1274 enabled, but if a sound does not need to be spatialized it's best to disable it. There are two ways
1275 to disable spatialization of a sound:
1276
1277     ```c
1278     // Disable spatialization at initialization time via a flag:
1279     ma_sound_init_from_file(&engine, "my_sound.wav", MA_SOUND_FLAG_NO_SPATIALIZATION, NULL, NULL, &sound);
1280
1281     // Dynamically disable or enable spatialization post-initialization:
1282     ma_sound_set_spatialization_enabled(&sound, isSpatializationEnabled);
1283     ```
1284
1285 By default sounds will be spatialized based on the closest listener. If a sound should always be
1286 spatialized relative to a specific listener it can be pinned to one:
1287
1288     ```c
1289     ma_sound_set_pinned_listener_index(&sound, listenerIndex);
1290     ```
1291
1292 Like listeners, sounds have a position. By default, the position of a sound is in absolute space,
1293 but it can be changed to be relative to a listener:
1294
1295     ```c
1296     ma_sound_set_positioning(&sound, ma_positioning_relative);
1297     ```
1298
1299 Note that relative positioning of a sound only makes sense if there is either only one listener, or
1300 the sound is pinned to a specific listener. To set the position of a sound:
1301
1302     ```c
1303     ma_sound_set_position(&sound, posX, posY, posZ);
1304     ```
1305
1306 The direction works the same way as a listener and represents the sound's forward direction:
1307
1308     ```c
1309     ma_sound_set_direction(&sound, forwardX, forwardY, forwardZ);
1310     ```
1311
1312 Sound's also have a cone for controlling directional attenuation. This works exactly the same as
1313 listeners:
1314
1315     ```c
1316     ma_sound_set_cone(&sound, innerAngleInRadians, outerAngleInRadians, outerGain);
1317     ```
1318
1319 The velocity of a sound is used for doppler effect and can be set as such:
1320
1321     ```c
1322     ma_sound_set_velocity(&sound, velocityX, velocityY, velocityZ);
1323     ```
1324
1325 The engine supports different attenuation models which can be configured on a per-sound basis. By
1326 default the attenuation model is set to `ma_attenuation_model_inverse` which is the equivalent to
1327 OpenAL's `AL_INVERSE_DISTANCE_CLAMPED`. Configure the attenuation model like so:
1328
1329     ```c
1330     ma_sound_set_attenuation_model(&sound, ma_attenuation_model_inverse);
1331     ```
1332
1333 The supported attenuation models include the following:
1334
1335     +----------------------------------+----------------------------------------------+
1336     | ma_attenuation_model_none        | No distance attenuation.                     |
1337     +----------------------------------+----------------------------------------------+
1338     | ma_attenuation_model_inverse     | Equivalent to `AL_INVERSE_DISTANCE_CLAMPED`. |
1339     +----------------------------------+----------------------------------------------+
1340     | ma_attenuation_model_linear      | Linear attenuation.                          |
1341     +----------------------------------+----------------------------------------------+
1342     | ma_attenuation_model_exponential | Exponential attenuation.                     |
1343     +----------------------------------+----------------------------------------------+
1344
1345 To control how quickly a sound rolls off as it moves away from the listener, you need to configure
1346 the rolloff:
1347
1348     ```c
1349     ma_sound_set_rolloff(&sound, rolloff);
1350     ```
1351
1352 You can control the minimum and maximum gain to apply from spatialization:
1353
1354     ```c
1355     ma_sound_set_min_gain(&sound, minGain);
1356     ma_sound_set_max_gain(&sound, maxGain);
1357     ```
1358
1359 Likewise, in the calculation of attenuation, you can control the minimum and maximum distances for
1360 the attenuation calculation. This is useful if you want to ensure sounds don't drop below a certain
1361 volume after the listener moves further away and to have sounds play a maximum volume when the
1362 listener is within a certain distance:
1363
1364     ```c
1365     ma_sound_set_min_distance(&sound, minDistance);
1366     ma_sound_set_max_distance(&sound, maxDistance);
1367     ```
1368
1369 The engine's spatialization system supports doppler effect. The doppler factor can be configure on
1370 a per-sound basis like so:
1371
1372     ```c
1373     ma_sound_set_doppler_factor(&sound, dopplerFactor);
1374     ```
1375
1376 You can fade sounds in and out with `ma_sound_set_fade_in_pcm_frames()` and
1377 `ma_sound_set_fade_in_milliseconds()`. Set the volume to -1 to use the current volume as the
1378 starting volume:
1379
1380     ```c
1381     // Fade in over 1 second.
1382     ma_sound_set_fade_in_milliseconds(&sound, 0, 1, 1000);
1383
1384     // ... sometime later ...
1385
1386     // Fade out over 1 second, starting from the current volume.
1387     ma_sound_set_fade_in_milliseconds(&sound, -1, 0, 1000);
1388     ```
1389
1390 By default sounds will start immediately, but sometimes for timing and synchronization purposes it
1391 can be useful to schedule a sound to start or stop:
1392
1393     ```c
1394     // Start the sound in 1 second from now.
1395     ma_sound_set_start_time_in_pcm_frames(&sound, ma_engine_get_time(&engine) + (ma_engine_get_sample_rate(&engine) * 1));
1396
1397     // Stop the sound in 2 seconds from now.
1398     ma_sound_set_stop_time_in_pcm_frames(&sound, ma_engine_get_time(&engine) + (ma_engine_get_sample_rate(&engine) * 2));
1399     ```
1400
1401 The time is specified in global time which is controlled by the engine. You can get the engine's
1402 current time with `ma_engine_get_time()`. The engine's global time is incremented automatically as
1403 audio data is read, but it can be reset with `ma_engine_set_time()` in case it needs to be
1404 resynchronized for some reason.
1405
1406 To determine whether or not a sound is currently playing, use `ma_sound_is_playing()`. This will
1407 take the scheduled start and stop times into account.
1408
1409 Whether or not a sound should loop can be controlled with `ma_sound_set_looping()`. Sounds will not
1410 be looping by default. Use `ma_sound_is_looping()` to determine whether or not a sound is looping.
1411
1412 Use `ma_sound_at_end()` to determine whether or not a sound is currently at the end. For a looping
1413 sound this should never return true.
1414
1415 Internally a sound wraps around a data source. Some APIs exist to control the underlying data
1416 source, mainly for convenience:
1417
1418     ```c
1419     ma_sound_seek_to_pcm_frame(&sound, frameIndex);
1420     ma_sound_get_data_format(&sound, &format, &channels, &sampleRate, pChannelMap, channelMapCapacity);
1421     ma_sound_get_cursor_in_pcm_frames(&sound, &cursor);
1422     ma_sound_get_length_in_pcm_frames(&sound, &length);
1423     ```
1424
1425 Sound groups have the same API as sounds, only they are called `ma_sound_group`, and since they do
1426 not have any notion of a data source, anything relating to a data source is unavailable.
1427
1428 Internally, sound data is loaded via the `ma_decoder` API which means by default in only supports
1429 file formats that have built-in support in miniaudio. You can extend this to support any kind of
1430 file format through the use of custom decoders. To do this you'll need to use a self-managed
1431 resource manager and configure it appropriately. See the "Resource Management" section below for
1432 details on how to set this up.
1433
1434
1435 6. Resource Management
1436 ======================
1437 Many programs will want to manage sound resources for things such as reference counting and
1438 streaming. This is supported by miniaudio via the `ma_resource_manager` API.
1439
1440 The resource manager is mainly responsible for the following:
1441
1442   * Loading of sound files into memory with reference counting.
1443   * Streaming of sound data
1444
1445 When loading a sound file, the resource manager will give you back a `ma_data_source` compatible
1446 object called `ma_resource_manager_data_source`. This object can be passed into any
1447 `ma_data_source` API which is how you can read and seek audio data. When loading a sound file, you
1448 specify whether or not you want the sound to be fully loaded into memory (and optionally
1449 pre-decoded) or streamed. When loading into memory, you can also specify whether or not you want
1450 the data to be loaded asynchronously.
1451
1452 The example below is how you can initialize a resource manager using it's default configuration:
1453
1454     ```c
1455     ma_resource_manager_config config;
1456     ma_resource_manager resourceManager;
1457
1458     config = ma_resource_manager_config_init();
1459     result = ma_resource_manager_init(&config, &resourceManager);
1460     if (result != MA_SUCCESS) {
1461         ma_device_uninit(&device);
1462         printf("Failed to initialize the resource manager.");
1463         return -1;
1464     }
1465     ```
1466
1467 You can configure the format, channels and sample rate of the decoded audio data. By default it
1468 will use the file's native data format, but you can configure it to use a consistent format. This
1469 is useful for offloading the cost of data conversion to load time rather than dynamically
1470 converting at mixing time. To do this, you configure the decoded format, channels and sample rate
1471 like the code below:
1472
1473     ```c
1474     config = ma_resource_manager_config_init();
1475     config.decodedFormat     = device.playback.format;
1476     config.decodedChannels   = device.playback.channels;
1477     config.decodedSampleRate = device.sampleRate;
1478     ```
1479
1480 In the code above, the resource manager will be configured so that any decoded audio data will be
1481 pre-converted at load time to the device's native data format. If instead you used defaults and
1482 the data format of the file did not match the device's data format, you would need to convert the
1483 data at mixing time which may be prohibitive in high-performance and large scale scenarios like
1484 games.
1485
1486 Internally the resource manager uses the `ma_decoder` API to load sounds. This means by default it
1487 only supports decoders that are built into miniaudio. It's possible to support additional encoding
1488 formats through the use of custom decoders. To do so, pass in your `ma_decoding_backend_vtable`
1489 vtables into the resource manager config:
1490
1491     ```c
1492     ma_decoding_backend_vtable* pCustomBackendVTables[] =
1493     {
1494         &g_ma_decoding_backend_vtable_libvorbis,
1495         &g_ma_decoding_backend_vtable_libopus
1496     };
1497
1498     ...
1499
1500     resourceManagerConfig.ppCustomDecodingBackendVTables = pCustomBackendVTables;
1501     resourceManagerConfig.customDecodingBackendCount     = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]);
1502     resourceManagerConfig.pCustomDecodingBackendUserData = NULL;
1503     ```
1504
1505 This system can allow you to support any kind of file format. See the "Decoding" section for
1506 details on how to implement custom decoders. The miniaudio repository includes examples for Opus
1507 via libopus and libopusfile and Vorbis via libvorbis and libvorbisfile.
1508
1509 Asynchronicity is achieved via a job system. When an operation needs to be performed, such as the
1510 decoding of a page, a job will be posted to a queue which will then be processed by a job thread.
1511 By default there will be only one job thread running, but this can be configured, like so:
1512
1513     ```c
1514     config = ma_resource_manager_config_init();
1515     config.jobThreadCount = MY_JOB_THREAD_COUNT;
1516     ```
1517
1518 By default job threads are managed internally by the resource manager, however you can also self
1519 manage your job threads if, for example, you want to integrate the job processing into your
1520 existing job infrastructure, or if you simply don't like the way the resource manager does it. To
1521 do this, just set the job thread count to 0 and process jobs manually. To process jobs, you first
1522 need to retrieve a job using `ma_resource_manager_next_job()` and then process it using
1523 `ma_resource_manager_process_job()`:
1524
1525     ```c
1526     config = ma_resource_manager_config_init();
1527     config.jobThreadCount = 0;                            // Don't manage any job threads internally.
1528     config.flags = MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING; // Optional. Makes `ma_resource_manager_next_job()` non-blocking.
1529
1530     // ... Initialize your custom job threads ...
1531
1532     void my_custom_job_thread(...)
1533     {
1534         for (;;) {
1535             ma_resource_manager_job job;
1536             ma_result result = ma_resource_manager_next_job(pMyResourceManager, &job);
1537             if (result != MA_SUCCESS) {
1538                 if (result == MA_NOT_DATA_AVAILABLE) {
1539                     // No jobs are available. Keep going. Will only get this if the resource manager was initialized
1540                     // with MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING.
1541                     continue;
1542                 } else if (result == MA_CANCELLED) {
1543                     // MA_RESOURCE_MANAGER_JOB_QUIT was posted. Exit.
1544                     break;
1545                 } else {
1546                     // Some other error occurred.
1547                     break;
1548                 }
1549             }
1550
1551             ma_resource_manager_process_job(pMyResourceManager, &job);
1552         }
1553     }
1554     ```
1555
1556 In the example above, the `MA_RESOURCE_MANAGER_JOB_QUIT` event is the used as the termination
1557 indicator, but you can use whatever you would like to terminate the thread. The call to
1558 `ma_resource_manager_next_job()` is blocking by default, but can be configured to be non-blocking
1559 by initializing the resource manager with the `MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING` configuration
1560 flag. Note that the `MA_RESOURCE_MANAGER_JOB_QUIT` will never be removed from the job queue. This
1561 is to give every thread the opportunity to catch the event and terminate naturally.
1562
1563 When loading a file, it's sometimes convenient to be able to customize how files are opened and
1564 read instead of using standard `fopen()`, `fclose()`, etc. which is what miniaudio will use by
1565 default. This can be done by setting `pVFS` member of the resource manager's config:
1566
1567     ```c
1568     // Initialize your custom VFS object. See documentation for VFS for information on how to do this.
1569     my_custom_vfs vfs = my_custom_vfs_init();
1570
1571     config = ma_resource_manager_config_init();
1572     config.pVFS = &vfs;
1573     ```
1574
1575 This is particularly useful in programs like games where you want to read straight from an archive
1576 rather than the normal file system. If you do not specify a custom VFS, the resource manager will
1577 use the operating system's normal file operations. This is default.
1578
1579 To load a sound file and create a data source, call `ma_resource_manager_data_source_init()`. When
1580 loading a sound you need to specify the file path and options for how the sounds should be loaded.
1581 By default a sound will be loaded synchronously. The returned data source is owned by the caller
1582 which means the caller is responsible for the allocation and freeing of the data source. Below is
1583 an example for initializing a data source:
1584
1585     ```c
1586     ma_resource_manager_data_source dataSource;
1587     ma_result result = ma_resource_manager_data_source_init(pResourceManager, pFilePath, flags, &dataSource);
1588     if (result != MA_SUCCESS) {
1589         // Error.
1590     }
1591
1592     // ...
1593
1594     // A ma_resource_manager_data_source object is compatible with the `ma_data_source` API. To read data, just call
1595     // the `ma_data_source_read_pcm_frames()` like you would with any normal data source.
1596     result = ma_data_source_read_pcm_frames(&dataSource, pDecodedData, frameCount, &framesRead);
1597     if (result != MA_SUCCESS) {
1598         // Failed to read PCM frames.
1599     }
1600
1601     // ...
1602
1603     ma_resource_manager_data_source_uninit(pResourceManager, &dataSource);
1604     ```
1605
1606 The `flags` parameter specifies how you want to perform loading of the sound file. It can be a
1607 combination of the following flags:
1608
1609     ```
1610     MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM
1611     MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE
1612     MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC
1613     MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT
1614     ```
1615
1616 When no flags are specified (set to 0), the sound will be fully loaded into memory, but not
1617 decoded, meaning the raw file data will be stored in memory, and then dynamically decoded when
1618 `ma_data_source_read_pcm_frames()` is called. To instead decode the audio data before storing it in
1619 memory, use the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` flag. By default, the sound file will
1620 be loaded synchronously, meaning `ma_resource_manager_data_source_init()` will only return after
1621 the entire file has been loaded. This is good for simplicity, but can be prohibitively slow. You
1622 can instead load the sound asynchronously using the `MA_DATA_SOURCE_ASYNC` flag. This will result
1623 in `ma_resource_manager_data_source_init()` returning quickly, but no data will be returned by
1624 `ma_data_source_read_pcm_frames()` until some data is available. When no data is available because
1625 the asynchronous decoding hasn't caught up, `MA_BUSY` will be returned by
1626 `ma_data_source_read_pcm_frames()`.
1627
1628 For large sounds, it's often prohibitive to store the entire file in memory. To mitigate this, you
1629 can instead stream audio data which you can do by specifying the
1630 `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag. When streaming, data will be decoded in 1
1631 second pages. When a new page needs to be decoded, a job will be posted to the job queue and then
1632 subsequently processed in a job thread.
1633
1634 For in-memory sounds, reference counting is used to ensure the data is loaded only once. This means
1635 multiple calls to `ma_resource_manager_data_source_init()` with the same file path will result in
1636 the file data only being loaded once. Each call to `ma_resource_manager_data_source_init()` must be
1637 matched up with a call to `ma_resource_manager_data_source_uninit()`. Sometimes it can be useful
1638 for a program to register self-managed raw audio data and associate it with a file path. Use the
1639 `ma_resource_manager_register_*()` and `ma_resource_manager_unregister_*()` APIs to do this.
1640 `ma_resource_manager_register_decoded_data()` is used to associate a pointer to raw, self-managed
1641 decoded audio data in the specified data format with the specified name. Likewise,
1642 `ma_resource_manager_register_encoded_data()` is used to associate a pointer to raw self-managed
1643 encoded audio data (the raw file data) with the specified name. Note that these names need not be
1644 actual file paths. When `ma_resource_manager_data_source_init()` is called (without the
1645 `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag), the resource manager will look for these
1646 explicitly registered data buffers and, if found, will use it as the backing data for the data
1647 source. Note that the resource manager does *not* make a copy of this data so it is up to the
1648 caller to ensure the pointer stays valid for it's lifetime. Use
1649 `ma_resource_manager_unregister_data()` to unregister the self-managed data. You can also use
1650 `ma_resource_manager_register_file()` and `ma_resource_manager_unregister_file()` to register and
1651 unregister a file. It does not make sense to use the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM`
1652 flag with a self-managed data pointer.
1653
1654
1655 6.1. Asynchronous Loading and Synchronization
1656 ---------------------------------------------
1657 When loading asynchronously, it can be useful to poll whether or not loading has finished. Use
1658 `ma_resource_manager_data_source_result()` to determine this. For in-memory sounds, this will
1659 return `MA_SUCCESS` when the file has been *entirely* decoded. If the sound is still being decoded,
1660 `MA_BUSY` will be returned. Otherwise, some other error code will be returned if the sound failed
1661 to load. For streaming data sources, `MA_SUCCESS` will be returned when the first page has been
1662 decoded and the sound is ready to be played. If the first page is still being decoded, `MA_BUSY`
1663 will be returned. Otherwise, some other error code will be returned if the sound failed to load.
1664
1665 In addition to polling, you can also use a simple synchronization object called a "fence" to wait
1666 for asynchronously loaded sounds to finish. This is called `ma_fence`. The advantage to using a
1667 fence is that it can be used to wait for a group of sounds to finish loading rather than waiting
1668 for sounds on an individual basis. There are two stages to loading a sound:
1669
1670   * Initialization of the internal decoder; and
1671   * Completion of decoding of the file (the file is fully decoded)
1672
1673 You can specify separate fences for each of the different stages. Waiting for the initialization
1674 of the internal decoder is important for when you need to know the sample format, channels and
1675 sample rate of the file.
1676
1677 The example below shows how you could use a fence when loading a number of sounds:
1678
1679     ```c
1680     // This fence will be released when all sounds are finished loading entirely.
1681     ma_fence fence;
1682     ma_fence_init(&fence);
1683
1684     // This will be passed into the initialization routine for each sound.
1685     ma_resource_manager_pipeline_notifications notifications = ma_resource_manager_pipeline_notifications_init();
1686     notifications.done.pFence = &fence;
1687
1688     // Now load a bunch of sounds:
1689     for (iSound = 0; iSound < soundCount; iSound += 1) {
1690         ma_resource_manager_data_source_init(pResourceManager, pSoundFilePaths[iSound], flags, &notifications, &pSoundSources[iSound]);
1691     }
1692
1693     // ... DO SOMETHING ELSE WHILE SOUNDS ARE LOADING ...
1694
1695     // Wait for loading of sounds to finish.
1696     ma_fence_wait(&fence);
1697     ```
1698
1699 In the example above we used a fence for waiting until the entire file has been fully decoded. If
1700 You only need to wait for the initialization of the internal decoder to complete, you can use the
1701 `init` member of the `ma_resource_manager_pipeline_notifications` object:
1702
1703     ```c
1704     notifications.init.pFence = &fence;
1705     ```
1706
1707 If a fence is not appropriate for your situation, you can instead use a callback that is fired on
1708 an individual sound basis. This is done in a very similar way to fences:
1709
1710     ```c
1711     typedef struct
1712     {
1713         ma_async_notification_callbacks cb;
1714         void* pMyData;
1715     } my_notification;
1716
1717     void my_notification_callback(ma_async_notification* pNotification)
1718     {
1719         my_notification* pMyNotification = (my_notification*)pNotification;
1720
1721         // Do something in response to the sound finishing loading.
1722     }
1723
1724     ...
1725
1726     my_notification myCallback;
1727     myCallback.cb.onSignal = my_notification_callback;
1728     myCallback.pMyData     = pMyData;
1729
1730     ma_resource_manager_pipeline_notifications notifications = ma_resource_manager_pipeline_notifications_init();
1731     notifications.done.pNotification = &myCallback;
1732
1733     ma_resource_manager_data_source_init(pResourceManager, "my_sound.wav", flags, &notifications, &mySound);
1734     ```
1735
1736 In the example above we just extend the `ma_async_notification_callbacks` object and pass an
1737 instantiation into the `ma_resource_manager_pipeline_notifications` in the same way as we did with
1738 the fence, only we set `pNotification` instead of `pFence`. You can set both of these at the same
1739 time and they should both work as expected. If using the `pNotification` system, you need to ensure
1740 your `ma_async_notification_callbacks` object stays valid.
1741
1742
1743
1744 6.2. Resource Manager Implementation Details
1745 --------------------------------------------
1746 Resources are managed in two main ways:
1747
1748   * By storing the entire sound inside an in-memory buffer (referred to as a data buffer)
1749   * By streaming audio data on the fly (referred to as a data stream)
1750
1751 A resource managed data source (`ma_resource_manager_data_source`) encapsulates a data buffer or
1752 data stream, depending on whether or not the data source was initialized with the
1753 `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag. If so, it will make use of a
1754 `ma_resource_manager_data_stream` object. Otherwise it will use a `ma_resource_manager_data_buffer`
1755 object. Both of these objects are data sources which means they can be used with any
1756 `ma_data_source_*()` API.
1757
1758 Another major feature of the resource manager is the ability to asynchronously decode audio files.
1759 This relieves the audio thread of time-consuming decoding which can negatively affect scalability
1760 due to the audio thread needing to complete it's work extremely quickly to avoid glitching.
1761 Asynchronous decoding is achieved through a job system. There is a central multi-producer,
1762 multi-consumer, fixed-capacity job queue. When some asynchronous work needs to be done, a job is
1763 posted to the queue which is then read by a job thread. The number of job threads can be
1764 configured for improved scalability, and job threads can all run in parallel without needing to
1765 worry about the order of execution (how this is achieved is explained below).
1766
1767 When a sound is being loaded asynchronously, playback can begin before the sound has been fully
1768 decoded. This enables the application to start playback of the sound quickly, while at the same
1769 time allowing to resource manager to keep loading in the background. Since there may be less
1770 threads than the number of sounds being loaded at a given time, a simple scheduling system is used
1771 to keep decoding time balanced and fair. The resource manager solves this by splitting decoding
1772 into chunks called pages. By default, each page is 1 second long. When a page has been decoded, a
1773 new job will be posted to start decoding the next page. By dividing up decoding into pages, an
1774 individual sound shouldn't ever delay every other sound from having their first page decoded. Of
1775 course, when loading many sounds at the same time, there will always be an amount of time required
1776 to process jobs in the queue so in heavy load situations there will still be some delay. To
1777 determine if a data source is ready to have some frames read, use
1778 `ma_resource_manager_data_source_get_available_frames()`. This will return the number of frames
1779 available starting from the current position.
1780
1781
1782 6.2.1. Job Queue
1783 ----------------
1784 The resource manager uses a job queue which is multi-producer, multi-consumer, and fixed-capacity.
1785 This job queue is not currently lock-free, and instead uses a spinlock to achieve thread-safety.
1786 Only a fixed number of jobs can be allocated and inserted into the queue which is done through a
1787 lock-free data structure for allocating an index into a fixed sized array, with reference counting
1788 for mitigation of the ABA problem. The reference count is 32-bit.
1789
1790 For many types of jobs it's important that they execute in a specific order. In these cases, jobs
1791 are executed serially. For the resource manager, serial execution of jobs is only required on a
1792 per-object basis (per data buffer or per data stream). Each of these objects stores an execution
1793 counter. When a job is posted it is associated with an execution counter. When the job is
1794 processed, it checks if the execution counter of the job equals the execution counter of the
1795 owning object and if so, processes the job. If the counters are not equal, the job will be posted
1796 back onto the job queue for later processing. When the job finishes processing the execution order
1797 of the main object is incremented. This system means the no matter how many job threads are
1798 executing, decoding of an individual sound will always get processed serially. The advantage to
1799 having multiple threads comes into play when loading multiple sounds at the same time.
1800
1801 The resource manager's job queue is not 100% lock-free and will use a spinlock to achieve
1802 thread-safety for a very small section of code. This is only relevant when the resource manager
1803 uses more than one job thread. If only using a single job thread, which is the default, the
1804 lock should never actually wait in practice. The amount of time spent locking should be quite
1805 short, but it's something to be aware of for those who have pedantic lock-free requirements and
1806 need to use more than one job thread. There are plans to remove this lock in a future version.
1807
1808 In addition, posting a job will release a semaphore, which on Win32 is implemented with
1809 `ReleaseSemaphore` and on POSIX platforms via a condition variable:
1810
1811     ```c
1812     pthread_mutex_lock(&pSemaphore->lock);
1813     {
1814         pSemaphore->value += 1;
1815         pthread_cond_signal(&pSemaphore->cond);
1816     }
1817     pthread_mutex_unlock(&pSemaphore->lock);
1818     ```
1819
1820 Again, this is relevant for those with strict lock-free requirements in the audio thread. To avoid
1821 this, you can use non-blocking mode (via the `MA_RESOURCE_MANAGER_JOB_QUEUE_FLAG_NON_BLOCKING`
1822 flag) and implement your own job processing routine (see the "Resource Manager" section above for
1823 details on how to do this).
1824
1825
1826
1827 6.2.2. Data Buffers
1828 -------------------
1829 When the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag is excluded at initialization time, the
1830 resource manager will try to load the data into an in-memory data buffer. Before doing so, however,
1831 it will first check if the specified file is already loaded. If so, it will increment a reference
1832 counter and just use the already loaded data. This saves both time and memory. When the data buffer
1833 is uninitialized, the reference counter will be decremented. If the counter hits zero, the file
1834 will be unloaded. This is a detail to keep in mind because it could result in excessive loading and
1835 unloading of a sound. For example, the following sequence will result in a file be loaded twice,
1836 once after the other:
1837
1838     ```c
1839     ma_resource_manager_data_source_init(pResourceManager, "my_file", ..., &myDataBuffer0); // Refcount = 1. Initial load.
1840     ma_resource_manager_data_source_uninit(pResourceManager, &myDataBuffer0);               // Refcount = 0. Unloaded.
1841
1842     ma_resource_manager_data_source_init(pResourceManager, "my_file", ..., &myDataBuffer1); // Refcount = 1. Reloaded because previous uninit() unloaded it.
1843     ma_resource_manager_data_source_uninit(pResourceManager, &myDataBuffer1);               // Refcount = 0. Unloaded.
1844     ```
1845
1846 A binary search tree (BST) is used for storing data buffers as it has good balance between
1847 efficiency and simplicity. The key of the BST is a 64-bit hash of the file path that was passed
1848 into `ma_resource_manager_data_source_init()`. The advantage of using a hash is that it saves
1849 memory over storing the entire path, has faster comparisons, and results in a mostly balanced BST
1850 due to the random nature of the hash. The disadvantage is that file names are case-sensitive. If
1851 this is an issue, you should normalize your file names to upper- or lower-case before initializing
1852 your data sources.
1853
1854 When a sound file has not already been loaded and the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC`
1855 flag is excluded, the file will be decoded synchronously by the calling thread. There are two
1856 options for controlling how the audio is stored in the data buffer - encoded or decoded. When the
1857 `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` option is excluded, the raw file data will be stored
1858 in memory. Otherwise the sound will be decoded before storing it in memory. Synchronous loading is
1859 a very simple and standard process of simply adding an item to the BST, allocating a block of
1860 memory and then decoding (if `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE` is specified).
1861
1862 When the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` flag is specified, loading of the data buffer
1863 is done asynchronously. In this case, a job is posted to the queue to start loading and then the
1864 function immediately returns, setting an internal result code to `MA_BUSY`. This result code is
1865 returned when the program calls `ma_resource_manager_data_source_result()`. When decoding has fully
1866 completed `MA_SUCCESS` will be returned. This can be used to know if loading has fully completed.
1867
1868 When loading asynchronously, a single job is posted to the queue of the type
1869 `MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE`. This involves making a copy of the file path and
1870 associating it with job. When the job is processed by the job thread, it will first load the file
1871 using the VFS associated with the resource manager. When using a custom VFS, it's important that it
1872 be completely thread-safe because it will be used from one or more job threads at the same time.
1873 Individual files should only ever be accessed by one thread at a time, however. After opening the
1874 file via the VFS, the job will determine whether or not the file is being decoded. If not, it
1875 simply allocates a block of memory and loads the raw file contents into it and returns. On the
1876 other hand, when the file is being decoded, it will first allocate a decoder on the heap and
1877 initialize it. Then it will check if the length of the file is known. If so it will allocate a
1878 block of memory to store the decoded output and initialize it to silence. If the size is unknown,
1879 it will allocate room for one page. After memory has been allocated, the first page will be
1880 decoded. If the sound is shorter than a page, the result code will be set to `MA_SUCCESS` and the
1881 completion event will be signalled and loading is now complete. If, however, there is more to
1882 decode, a job with the code `MA_RESOURCE_MANAGER_JOB_PAGE_DATA_BUFFER_NODE` is posted. This job
1883 will decode the next page and perform the same process if it reaches the end. If there is more to
1884 decode, the job will post another `MA_RESOURCE_MANAGER_JOB_PAGE_DATA_BUFFER_NODE` job which will
1885 keep on happening until the sound has been fully decoded. For sounds of an unknown length, each
1886 page will be linked together as a linked list. Internally this is implemented via the
1887 `ma_paged_audio_buffer` object.
1888
1889
1890 6.2.3. Data Streams
1891 -------------------
1892 Data streams only ever store two pages worth of data for each instance. They are most useful for
1893 large sounds like music tracks in games that would consume too much memory if fully decoded in
1894 memory. After every frame from a page has been read, a job will be posted to load the next page
1895 which is done from the VFS.
1896
1897 For data streams, the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC` flag will determine whether or
1898 not initialization of the data source waits until the two pages have been decoded. When unset,
1899 `ma_resource_manager_data_source_init()` will wait until the two pages have been loaded, otherwise
1900 it will return immediately.
1901
1902 When frames are read from a data stream using `ma_resource_manager_data_source_read_pcm_frames()`,
1903 `MA_BUSY` will be returned if there are no frames available. If there are some frames available,
1904 but less than the number requested, `MA_SUCCESS` will be returned, but the actual number of frames
1905 read will be less than the number requested. Due to the asymchronous nature of data streams,
1906 seeking is also asynchronous. If the data stream is in the middle of a seek, `MA_BUSY` will be
1907 returned when trying to read frames.
1908
1909 When `ma_resource_manager_data_source_read_pcm_frames()` results in a page getting fully consumed
1910 a job is posted to load the next page. This will be posted from the same thread that called
1911 `ma_resource_manager_data_source_read_pcm_frames()`.
1912
1913 Data streams are uninitialized by posting a job to the queue, but the function won't return until
1914 that job has been processed. The reason for this is that the caller owns the data stream object and
1915 therefore miniaudio needs to ensure everything completes before handing back control to the caller.
1916 Also, if the data stream is uninitialized while pages are in the middle of decoding, they must
1917 complete before destroying any underlying object and the job system handles this cleanly.
1918
1919 Note that when a new page needs to be loaded, a job will be posted to the resource manager's job
1920 thread from the audio thread. You must keep in mind the details mentioned in the "Job Queue"
1921 section above regarding locking when posting an event if you require a strictly lock-free audio
1922 thread.
1923
1924
1925
1926 7. Node Graph
1927 =============
1928 miniaudio's routing infrastructure follows a node graph paradigm. The idea is that you create a
1929 node whose outputs are attached to inputs of another node, thereby creating a graph. There are
1930 different types of nodes, with each node in the graph processing input data to produce output,
1931 which is then fed through the chain. Each node in the graph can apply their own custom effects. At
1932 the start of the graph will usually be one or more data source nodes which have no inputs, but
1933 instead pull their data from a data source. At the end of the graph is an endpoint which represents
1934 the end of the chain and is where the final output is ultimately extracted from.
1935
1936 Each node has a number of input buses and a number of output buses. An output bus from a node is
1937 attached to an input bus of another. Multiple nodes can connect their output buses to another
1938 node's input bus, in which case their outputs will be mixed before processing by the node. Below is
1939 a diagram that illustrates a hypothetical node graph setup:
1940
1941     ```
1942     >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Data flows left to right >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
1943
1944     +---------------+                              +-----------------+
1945     | Data Source 1 =----+    +----------+    +----= Low Pass Filter =----+
1946     +---------------+    |    |          =----+    +-----------------+    |    +----------+
1947                          +----= Splitter |                                +----= ENDPOINT |
1948     +---------------+    |    |          =----+    +-----------------+    |    +----------+
1949     | Data Source 2 =----+    +----------+    +----=  Echo / Delay   =----+
1950     +---------------+                              +-----------------+
1951     ```
1952
1953 In the above graph, it starts with two data sources whose outputs are attached to the input of a
1954 splitter node. It's at this point that the two data sources are mixed. After mixing, the splitter
1955 performs it's processing routine and produces two outputs which is simply a duplication of the
1956 input stream. One output is attached to a low pass filter, whereas the other output is attached to
1957 a echo/delay. The outputs of the the low pass filter and the echo are attached to the endpoint, and
1958 since they're both connected to the same input but, they'll be mixed.
1959
1960 Each input bus must be configured to accept the same number of channels, but the number of channels
1961 used by input buses can be different to the number of channels for output buses in which case
1962 miniaudio will automatically convert the input data to the output channel count before processing.
1963 The number of channels of an output bus of one node must match the channel count of the input bus
1964 it's attached to. The channel counts cannot be changed after the node has been initialized. If you
1965 attempt to attach an output bus to an input bus with a different channel count, attachment will
1966 fail.
1967
1968 To use a node graph, you first need to initialize a `ma_node_graph` object. This is essentially a
1969 container around the entire graph. The `ma_node_graph` object is required for some thread-safety
1970 issues which will be explained later. A `ma_node_graph` object is initialized using miniaudio's
1971 standard config/init system:
1972
1973     ```c
1974     ma_node_graph_config nodeGraphConfig = ma_node_graph_config_init(myChannelCount);
1975
1976     result = ma_node_graph_init(&nodeGraphConfig, NULL, &nodeGraph);    // Second parameter is a pointer to allocation callbacks.
1977     if (result != MA_SUCCESS) {
1978         // Failed to initialize node graph.
1979     }
1980     ```
1981
1982 When you initialize the node graph, you're specifying the channel count of the endpoint. The
1983 endpoint is a special node which has one input bus and one output bus, both of which have the
1984 same channel count, which is specified in the config. Any nodes that connect directly to the
1985 endpoint must be configured such that their output buses have the same channel count. When you read
1986 audio data from the node graph, it'll have the channel count you specified in the config. To read
1987 data from the graph:
1988
1989     ```c
1990     ma_uint32 framesRead;
1991     result = ma_node_graph_read_pcm_frames(&nodeGraph, pFramesOut, frameCount, &framesRead);
1992     if (result != MA_SUCCESS) {
1993         // Failed to read data from the node graph.
1994     }
1995     ```
1996
1997 When you read audio data, miniaudio starts at the node graph's endpoint node which then pulls in
1998 data from it's input attachments, which in turn recusively pull in data from their inputs, and so
1999 on. At the start of the graph there will be some kind of data source node which will have zero
2000 inputs and will instead read directly from a data source. The base nodes don't literally need to
2001 read from a `ma_data_source` object, but they will always have some kind of underlying object that
2002 sources some kind of audio. The `ma_data_source_node` node can be used to read from a
2003 `ma_data_source`. Data is always in floating-point format and in the number of channels you
2004 specified when the graph was initialized. The sample rate is defined by the underlying data sources.
2005 It's up to you to ensure they use a consistent and appropraite sample rate.
2006
2007 The `ma_node` API is designed to allow custom nodes to be implemented with relative ease, but
2008 miniaudio includes a few stock nodes for common functionality. This is how you would initialize a
2009 node which reads directly from a data source (`ma_data_source_node`) which is an example of one
2010 of the stock nodes that comes with miniaudio:
2011
2012     ```c
2013     ma_data_source_node_config config = ma_data_source_node_config_init(pMyDataSource);
2014
2015     ma_data_source_node dataSourceNode;
2016     result = ma_data_source_node_init(&nodeGraph, &config, NULL, &dataSourceNode);
2017     if (result != MA_SUCCESS) {
2018         // Failed to create data source node.
2019     }
2020     ```
2021
2022 The data source node will use the output channel count to determine the channel count of the output
2023 bus. There will be 1 output bus and 0 input buses (data will be drawn directly from the data
2024 source). The data source must output to floating-point (`ma_format_f32`) or else an error will be
2025 returned from `ma_data_source_node_init()`.
2026
2027 By default the node will not be attached to the graph. To do so, use `ma_node_attach_output_bus()`:
2028
2029     ```c
2030     result = ma_node_attach_output_bus(&dataSourceNode, 0, ma_node_graph_get_endpoint(&nodeGraph), 0);
2031     if (result != MA_SUCCESS) {
2032         // Failed to attach node.
2033     }
2034     ```
2035
2036 The code above connects the data source node directly to the endpoint. Since the data source node
2037 has only a single output bus, the index will always be 0. Likewise, the endpoint only has a single
2038 input bus which means the input bus index will also always be 0.
2039
2040 To detach a specific output bus, use `ma_node_detach_output_bus()`. To detach all output buses, use
2041 `ma_node_detach_all_output_buses()`. If you want to just move the output bus from one attachment to
2042 another, you do not need to detach first. You can just call `ma_node_attach_output_bus()` and it'll
2043 deal with it for you.
2044
2045 Less frequently you may want to create a specialized node. This will be a node where you implement
2046 your own processing callback to apply a custom effect of some kind. This is similar to initalizing
2047 one of the stock node types, only this time you need to specify a pointer to a vtable containing a
2048 pointer to the processing function and the number of input and output buses. Example:
2049
2050     ```c
2051     static void my_custom_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
2052     {
2053         // Do some processing of ppFramesIn (one stream of audio data per input bus)
2054         const float* pFramesIn_0 = ppFramesIn[0]; // Input bus @ index 0.
2055         const float* pFramesIn_1 = ppFramesIn[1]; // Input bus @ index 1.
2056         float* pFramesOut_0 = ppFramesOut[0];     // Output bus @ index 0.
2057
2058         // Do some processing. On input, `pFrameCountIn` will be the number of input frames in each
2059         // buffer in `ppFramesIn` and `pFrameCountOut` will be the capacity of each of the buffers
2060         // in `ppFramesOut`. On output, `pFrameCountIn` should be set to the number of input frames
2061         // your node consumed and `pFrameCountOut` should be set the number of output frames that
2062         // were produced.
2063         //
2064         // You should process as many frames as you can. If your effect consumes input frames at the
2065         // same rate as output frames (always the case, unless you're doing resampling), you need
2066         // only look at `ppFramesOut` and process that exact number of frames. If you're doing
2067         // resampling, you'll need to be sure to set both `pFrameCountIn` and `pFrameCountOut`
2068         // properly.
2069     }
2070
2071     static ma_node_vtable my_custom_node_vtable =
2072     {
2073         my_custom_node_process_pcm_frames, // The function that will be called process your custom node. This is where you'd implement your effect processing.
2074         NULL,   // Optional. A callback for calculating the number of input frames that are required to process a specified number of output frames.
2075         2,      // 2 input buses.
2076         1,      // 1 output bus.
2077         0       // Default flags.
2078     };
2079
2080     ...
2081
2082     // Each bus needs to have a channel count specified. To do this you need to specify the channel
2083     // counts in an array and then pass that into the node config.
2084     ma_uint32 inputChannels[2];     // Equal in size to the number of input channels specified in the vtable.
2085     ma_uint32 outputChannels[1];    // Equal in size to the number of output channels specicied in the vtable.
2086
2087     inputChannels[0]  = channelsIn;
2088     inputChannels[1]  = channelsIn;
2089     outputChannels[0] = channelsOut;
2090
2091     ma_node_config nodeConfig = ma_node_config_init();
2092     nodeConfig.vtable          = &my_custom_node_vtable;
2093     nodeConfig.pInputChannels  = inputChannels;
2094     nodeConfig.pOutputChannels = outputChannels;
2095
2096     ma_node_base node;
2097     result = ma_node_init(&nodeGraph, &nodeConfig, NULL, &node);
2098     if (result != MA_SUCCESS) {
2099         // Failed to initialize node.
2100     }
2101     ```
2102
2103 When initializing a custom node, as in the code above, you'll normally just place your vtable in
2104 static space. The number of input and output buses are specified as part of the vtable. If you need
2105 a variable number of buses on a per-node bases, the vtable should have the relevant bus count set
2106 to `MA_NODE_BUS_COUNT_UNKNOWN`. In this case, the bus count should be set in the node config:
2107
2108     ```c
2109     static ma_node_vtable my_custom_node_vtable =
2110     {
2111         my_custom_node_process_pcm_frames, // The function that will be called process your custom node. This is where you'd implement your effect processing.
2112         NULL,   // Optional. A callback for calculating the number of input frames that are required to process a specified number of output frames.
2113         MA_NODE_BUS_COUNT_UNKNOWN,  // The number of input buses is determined on a per-node basis.
2114         1,      // 1 output bus.
2115         0       // Default flags.
2116     };
2117
2118     ...
2119
2120     ma_node_config nodeConfig = ma_node_config_init();
2121     nodeConfig.vtable          = &my_custom_node_vtable;
2122     nodeConfig.inputBusCount   = myBusCount;        // <-- Since the vtable specifies MA_NODE_BUS_COUNT_UNKNOWN, the input bus count should be set here.
2123     nodeConfig.pInputChannels  = inputChannels;     // <-- Make sure there are nodeConfig.inputBusCount elements in this array.
2124     nodeConfig.pOutputChannels = outputChannels;    // <-- The vtable specifies 1 output bus, so there must be 1 element in this array.
2125     ```
2126
2127 In the above example it's important to never set the `inputBusCount` and `outputBusCount` members
2128 to anything other than their defaults if the vtable specifies an explicit count. They can only be
2129 set if the vtable specifies MA_NODE_BUS_COUNT_UNKNOWN in the relevant bus count.
2130
2131 Most often you'll want to create a structure to encapsulate your node with some extra data. You
2132 need to make sure the `ma_node_base` object is your first member of the structure:
2133
2134     ```c
2135     typedef struct
2136     {
2137         ma_node_base base; // <-- Make sure this is always the first member.
2138         float someCustomData;
2139     } my_custom_node;
2140     ```
2141
2142 By doing this, your object will be compatible with all `ma_node` APIs and you can attach it to the
2143 graph just like any other node.
2144
2145 In the custom processing callback (`my_custom_node_process_pcm_frames()` in the example above), the
2146 number of channels for each bus is what was specified by the config when the node was initialized
2147 with `ma_node_init()`. In addition, all attachments to each of the input buses will have been
2148 pre-mixed by miniaudio. The config allows you to specify different channel counts for each
2149 individual input and output bus. It's up to the effect to handle it appropriate, and if it can't,
2150 return an error in it's initialization routine.
2151
2152 Custom nodes can be assigned some flags to describe their behaviour. These are set via the vtable
2153 and include the following:
2154
2155     +-----------------------------------------+---------------------------------------------------+
2156     | Flag Name                               | Description                                       |
2157     +-----------------------------------------+---------------------------------------------------+
2158     | MA_NODE_FLAG_PASSTHROUGH                | Useful for nodes that do not do any kind of audio |
2159     |                                         | processing, but are instead used for tracking     |
2160     |                                         | time, handling events, etc. Also used by the      |
2161     |                                         | internal endpoint node. It reads directly from    |
2162     |                                         | the input bus to the output bus. Nodes with this  |
2163     |                                         | flag must have exactly 1 input bus and 1 output   |
2164     |                                         | bus, and both buses must have the same channel    |
2165     |                                         | counts.                                           |
2166     +-----------------------------------------+---------------------------------------------------+
2167     | MA_NODE_FLAG_CONTINUOUS_PROCESSING      | Causes the processing callback to be called even  |
2168     |                                         | when no data is available to be read from input   |
2169     |                                         | attachments. This is useful for effects like      |
2170     |                                         | echos where there will be a tail of audio data    |
2171     |                                         | that still needs to be processed even when the    |
2172     |                                         | original data sources have reached their ends.    |
2173     +-----------------------------------------+---------------------------------------------------+
2174     | MA_NODE_FLAG_ALLOW_NULL_INPUT           | Used in conjunction with                          |
2175     |                                         | `MA_NODE_FLAG_CONTINUOUS_PROCESSING`. When this   |
2176     |                                         | is set, the `ppFramesIn` parameter of the         |
2177     |                                         | processing callback will be set to NULL when      |
2178     |                                         | there are no input frames are available. When     |
2179     |                                         | this is unset, silence will be posted to the      |
2180     |                                         | processing callback.                              |
2181     +-----------------------------------------+---------------------------------------------------+
2182     | MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES | Used to tell miniaudio that input and output      |
2183     |                                         | frames are processed at different rates. You      |
2184     |                                         | should set this for any nodes that perform        |
2185     |                                         | resampling.                                       |
2186     +-----------------------------------------+---------------------------------------------------+
2187
2188
2189 If you need to make a copy of an audio stream for effect processing you can use a splitter node
2190 called `ma_splitter_node`. This takes has 1 input bus and splits the stream into 2 output buses.
2191 You can use it like this:
2192
2193     ```c
2194     ma_splitter_node_config splitterNodeConfig = ma_splitter_node_config_init(channelsIn, channelsOut);
2195
2196     ma_splitter_node splitterNode;
2197     result = ma_splitter_node_init(&nodeGraph, &splitterNodeConfig, NULL, &splitterNode);
2198     if (result != MA_SUCCESS) {
2199         // Failed to create node.
2200     }
2201
2202     // Attach your output buses to two different input buses (can be on two different nodes).
2203     ma_node_attach_output_bus(&splitterNode, 0, ma_node_graph_get_endpoint(&nodeGraph), 0); // Attach directly to the endpoint.
2204     ma_node_attach_output_bus(&splitterNode, 1, &myEffectNode,                          0); // Attach to input bus 0 of some effect node.
2205     ```
2206
2207 The volume of an output bus can be configured on a per-bus basis:
2208
2209     ```c
2210     ma_node_set_output_bus_volume(&splitterNode, 0, 0.5f);
2211     ma_node_set_output_bus_volume(&splitterNode, 1, 0.5f);
2212     ```
2213
2214 In the code above we're using the splitter node from before and changing the volume of each of the
2215 copied streams.
2216
2217 You can start and stop a node with the following:
2218
2219     ```c
2220     ma_node_set_state(&splitterNode, ma_node_state_started);    // The default state.
2221     ma_node_set_state(&splitterNode, ma_node_state_stopped);
2222     ```
2223
2224 By default the node is in a started state, but since it won't be connected to anything won't
2225 actually be invoked by the node graph until it's connected. When you stop a node, data will not be
2226 read from any of it's input connections. You can use this property to stop a group of sounds
2227 atomically.
2228
2229 You can configure the initial state of a node in it's config:
2230
2231     ```c
2232     nodeConfig.initialState = ma_node_state_stopped;
2233     ```
2234
2235 Note that for the stock specialized nodes, all of their configs will have a `nodeConfig` member
2236 which is the config to use with the base node. This is where the initial state can be configured
2237 for specialized nodes:
2238
2239     ```c
2240     dataSourceNodeConfig.nodeConfig.initialState = ma_node_state_stopped;
2241     ```
2242
2243 When using a specialized node like `ma_data_source_node` or `ma_splitter_node`, be sure to not
2244 modify the `vtable` member of the `nodeConfig` object.
2245
2246
2247 7.1. Timing
2248 -----------
2249 The node graph supports starting and stopping nodes at scheduled times. This is especially useful
2250 for data source nodes where you want to get the node set up, but only start playback at a specific
2251 time. There are two clocks: local and global.
2252
2253 A local clock is per-node, whereas the global clock is per graph. Scheduling starts and stops can
2254 only be done based on the global clock because the local clock will not be running while the node
2255 is stopped. The global clocks advances whenever `ma_node_graph_read_pcm_frames()` is called. On the
2256 other hand, the local clock only advances when the node's processing callback is fired, and is
2257 advanced based on the output frame count.
2258
2259 To retrieve the global time, use `ma_node_graph_get_time()`. The global time can be set with
2260 `ma_node_graph_set_time()` which might be useful if you want to do seeking on a global timeline.
2261 Getting and setting the local time is similar. Use `ma_node_get_time()` to retrieve the local time,
2262 and `ma_node_set_time()` to set the local time. The global and local times will be advanced by the
2263 audio thread, so care should be taken to avoid data races. Ideally you should avoid calling these
2264 outside of the node processing callbacks which are always run on the audio thread.
2265
2266 There is basic support for scheduling the starting and stopping of nodes. You can only schedule one
2267 start and one stop at a time. This is mainly intended for putting nodes into a started or stopped
2268 state in a frame-exact manner. Without this mechanism, starting and stopping of a node is limited
2269 to the resolution of a call to `ma_node_graph_read_pcm_frames()` which would typically be in blocks
2270 of several milliseconds. The following APIs can be used for scheduling node states:
2271
2272     ```c
2273     ma_node_set_state_time()
2274     ma_node_get_state_time()
2275     ```
2276
2277 The time is absolute and must be based on the global clock. An example is below:
2278
2279     ```c
2280     ma_node_set_state_time(&myNode, ma_node_state_started, sampleRate*1);   // Delay starting to 1 second.
2281     ma_node_set_state_time(&myNode, ma_node_state_stopped, sampleRate*5);   // Delay stopping to 5 seconds.
2282     ```
2283
2284 An example for changing the state using a relative time.
2285
2286     ```c
2287     ma_node_set_state_time(&myNode, ma_node_state_started, sampleRate*1 + ma_node_graph_get_time(&myNodeGraph));
2288     ma_node_set_state_time(&myNode, ma_node_state_stopped, sampleRate*5 + ma_node_graph_get_time(&myNodeGraph));
2289     ```
2290
2291 Note that due to the nature of multi-threading the times may not be 100% exact. If this is an
2292 issue, consider scheduling state changes from within a processing callback. An idea might be to
2293 have some kind of passthrough trigger node that is used specifically for tracking time and handling
2294 events.
2295
2296
2297
2298 7.2. Thread Safety and Locking
2299 ------------------------------
2300 When processing audio, it's ideal not to have any kind of locking in the audio thread. Since it's
2301 expected that `ma_node_graph_read_pcm_frames()` would be run on the audio thread, it does so
2302 without the use of any locks. This section discusses the implementation used by miniaudio and goes
2303 over some of the compromises employed by miniaudio to achieve this goal. Note that the current
2304 implementation may not be ideal - feedback and critiques are most welcome.
2305
2306 The node graph API is not *entirely* lock-free. Only `ma_node_graph_read_pcm_frames()` is expected
2307 to be lock-free. Attachment, detachment and uninitialization of nodes use locks to simplify the
2308 implementation, but are crafted in a way such that such locking is not required when reading audio
2309 data from the graph. Locking in these areas are achieved by means of spinlocks.
2310
2311 The main complication with keeping `ma_node_graph_read_pcm_frames()` lock-free stems from the fact
2312 that a node can be uninitialized, and it's memory potentially freed, while in the middle of being
2313 processed on the audio thread. There are times when the audio thread will be referencing a node,
2314 which means the uninitialization process of a node needs to make sure it delays returning until the
2315 audio thread is finished so that control is not handed back to the caller thereby giving them a
2316 chance to free the node's memory.
2317
2318 When the audio thread is processing a node, it does so by reading from each of the output buses of
2319 the node. In order for a node to process data for one of it's output buses, it needs to read from
2320 each of it's input buses, and so on an so forth. It follows that once all output buses of a node
2321 are detached, the node as a whole will be disconnected and no further processing will occur unless
2322 it's output buses are reattached, which won't be happening when the node is being uninitialized.
2323 By having `ma_node_detach_output_bus()` wait until the audio thread is finished with it, we can
2324 simplify a few things, at the expense of making `ma_node_detach_output_bus()` a bit slower. By
2325 doing this, the implementation of `ma_node_uninit()` becomes trivial - just detach all output
2326 nodes, followed by each of the attachments to each of it's input nodes, and then do any final clean
2327 up.
2328
2329 With the above design, the worst-case scenario is `ma_node_detach_output_bus()` taking as long as
2330 it takes to process the output bus being detached. This will happen if it's called at just the
2331 wrong moment where the audio thread has just iterated it and has just started processing. The
2332 caller of `ma_node_detach_output_bus()` will stall until the audio thread is finished, which
2333 includes the cost of recursively processing it's inputs. This is the biggest compromise made with
2334 the approach taken by miniaudio for it's lock-free processing system. The cost of detaching nodes
2335 earlier in the pipeline (data sources, for example) will be cheaper than the cost of detaching
2336 higher level nodes, such as some kind of final post-processing endpoint. If you need to do mass
2337 detachments, detach starting from the lowest level nodes and work your way towards the final
2338 endpoint node (but don't try detaching the node graph's endpoint). If the audio thread is not
2339 running, detachment will be fast and detachment in any order will be the same. The reason nodes
2340 need to wait for their input attachments to complete is due to the potential for desyncs between
2341 data sources. If the node was to terminate processing mid way through processing it's inputs,
2342 there's a chance that some of the underlying data sources will have been read, but then others not.
2343 That will then result in a potential desynchronization when detaching and reattaching higher-level
2344 nodes. A possible solution to this is to have an option when detaching to terminate processing
2345 before processing all input attachments which should be fairly simple.
2346
2347 Another compromise, albeit less significant, is locking when attaching and detaching nodes. This
2348 locking is achieved by means of a spinlock in order to reduce memory overhead. A lock is present
2349 for each input bus and output bus. When an output bus is connected to an input bus, both the output
2350 bus and input bus is locked. This locking is specifically for attaching and detaching across
2351 different threads and does not affect `ma_node_graph_read_pcm_frames()` in any way. The locking and
2352 unlocking is mostly self-explanatory, but a slightly less intuitive aspect comes into it when
2353 considering that iterating over attachments must not break as a result of attaching or detaching a
2354 node while iteration is occuring.
2355
2356 Attaching and detaching are both quite simple. When an output bus of a node is attached to an input
2357 bus of another node, it's added to a linked list. Basically, an input bus is a linked list, where
2358 each item in the list is and output bus. We have some intentional (and convenient) restrictions on
2359 what can done with the linked list in order to simplify the implementation. First of all, whenever
2360 something needs to iterate over the list, it must do so in a forward direction. Backwards iteration
2361 is not supported. Also, items can only be added to the start of the list.
2362
2363 The linked list is a doubly-linked list where each item in the list (an output bus) holds a pointer
2364 to the next item in the list, and another to the previous item. A pointer to the previous item is
2365 only required for fast detachment of the node - it is never used in iteration. This is an
2366 important property because it means from the perspective of iteration, attaching and detaching of
2367 an item can be done with a single atomic assignment. This is exploited by both the attachment and
2368 detachment process. When attaching the node, the first thing that is done is the setting of the
2369 local "next" and "previous" pointers of the node. After that, the item is "attached" to the list
2370 by simply performing an atomic exchange with the head pointer. After that, the node is "attached"
2371 to the list from the perspective of iteration. Even though the "previous" pointer of the next item
2372 hasn't yet been set, from the perspective of iteration it's been attached because iteration will
2373 only be happening in a forward direction which means the "previous" pointer won't actually ever get
2374 used. The same general process applies to detachment. See `ma_node_attach_output_bus()` and
2375 `ma_node_detach_output_bus()` for the implementation of this mechanism.
2376
2377
2378
2379 8. Decoding
2380 ===========
2381 The `ma_decoder` API is used for reading audio files. Decoders are completely decoupled from
2382 devices and can be used independently. The following formats are supported:
2383
2384     +---------+------------------+----------+
2385     | Format  | Decoding Backend | Built-In |
2386     +---------+------------------+----------+
2387     | WAV     | dr_wav           | Yes      |
2388     | MP3     | dr_mp3           | Yes      |
2389     | FLAC    | dr_flac          | Yes      |
2390     | Vorbis  | stb_vorbis       | No       |
2391     +---------+------------------+----------+
2392
2393 Vorbis is supported via stb_vorbis which can be enabled by including the header section before the
2394 implementation of miniaudio, like the following:
2395
2396     ```c
2397     #define STB_VORBIS_HEADER_ONLY
2398     #include "extras/stb_vorbis.c"    // Enables Vorbis decoding.
2399
2400     #define MINIAUDIO_IMPLEMENTATION
2401     #include "miniaudio.h"
2402
2403     // The stb_vorbis implementation must come after the implementation of miniaudio.
2404     #undef STB_VORBIS_HEADER_ONLY
2405     #include "extras/stb_vorbis.c"
2406     ```
2407
2408 A copy of stb_vorbis is included in the "extras" folder in the miniaudio repository (https://github.com/mackron/miniaudio).
2409
2410 Built-in decoders are amalgamated into the implementation section of miniaudio. You can disable the
2411 built-in decoders by specifying one or more of the following options before the miniaudio
2412 implementation:
2413
2414     ```c
2415     #define MA_NO_WAV
2416     #define MA_NO_MP3
2417     #define MA_NO_FLAC
2418     ```
2419
2420 Disabling built-in decoding libraries is useful if you use these libraries independantly of the
2421 `ma_decoder` API.
2422
2423 A decoder can be initialized from a file with `ma_decoder_init_file()`, a block of memory with
2424 `ma_decoder_init_memory()`, or from data delivered via callbacks with `ma_decoder_init()`. Here is
2425 an example for loading a decoder from a file:
2426
2427     ```c
2428     ma_decoder decoder;
2429     ma_result result = ma_decoder_init_file("MySong.mp3", NULL, &decoder);
2430     if (result != MA_SUCCESS) {
2431         return false;   // An error occurred.
2432     }
2433
2434     ...
2435
2436     ma_decoder_uninit(&decoder);
2437     ```
2438
2439 When initializing a decoder, you can optionally pass in a pointer to a `ma_decoder_config` object
2440 (the `NULL` argument in the example above) which allows you to configure the output format, channel
2441 count, sample rate and channel map:
2442
2443     ```c
2444     ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 2, 48000);
2445     ```
2446
2447 When passing in `NULL` for decoder config in `ma_decoder_init*()`, the output format will be the
2448 same as that defined by the decoding backend.
2449
2450 Data is read from the decoder as PCM frames. This will output the number of PCM frames actually
2451 read. If this is less than the requested number of PCM frames it means you've reached the end. The
2452 return value will be `MA_AT_END` if no samples have been read and the end has been reached.
2453
2454     ```c
2455     ma_result result = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead, &framesRead);
2456     if (framesRead < framesToRead) {
2457         // Reached the end.
2458     }
2459     ```
2460
2461 You can also seek to a specific frame like so:
2462
2463     ```c
2464     ma_result result = ma_decoder_seek_to_pcm_frame(pDecoder, targetFrame);
2465     if (result != MA_SUCCESS) {
2466         return false;   // An error occurred.
2467     }
2468     ```
2469
2470 If you want to loop back to the start, you can simply seek back to the first PCM frame:
2471
2472     ```c
2473     ma_decoder_seek_to_pcm_frame(pDecoder, 0);
2474     ```
2475
2476 When loading a decoder, miniaudio uses a trial and error technique to find the appropriate decoding
2477 backend. This can be unnecessarily inefficient if the type is already known. In this case you can
2478 use `encodingFormat` variable in the device config to specify a specific encoding format you want
2479 to decode:
2480
2481     ```c
2482     decoderConfig.encodingFormat = ma_encoding_format_wav;
2483     ```
2484
2485 See the `ma_encoding_format` enum for possible encoding formats.
2486
2487 The `ma_decoder_init_file()` API will try using the file extension to determine which decoding
2488 backend to prefer.
2489
2490
2491 8.1. Custom Decoders
2492 --------------------
2493 It's possible to implement a custom decoder and plug it into miniaudio. This is extremely useful
2494 when you want to use the `ma_decoder` API, but need to support an encoding format that's not one of
2495 the stock formats supported by miniaudio. This can be put to particularly good use when using the
2496 `ma_engine` and/or `ma_resource_manager` APIs because they use `ma_decoder` internally. If, for
2497 example, you wanted to support Opus, you can do so with a custom decoder (there if a reference
2498 Opus decoder in the "extras" folder of the miniaudio repository which uses libopus + libopusfile).
2499
2500 A custom decoder must implement a data source. A vtable called `ma_decoding_backend_vtable` needs
2501 to be implemented which is then passed into the decoder config:
2502
2503     ```c
2504     ma_decoding_backend_vtable* pCustomBackendVTables[] =
2505     {
2506         &g_ma_decoding_backend_vtable_libvorbis,
2507         &g_ma_decoding_backend_vtable_libopus
2508     };
2509
2510     ...
2511
2512     decoderConfig = ma_decoder_config_init_default();
2513     decoderConfig.pCustomBackendUserData = NULL;
2514     decoderConfig.ppCustomBackendVTables = pCustomBackendVTables;
2515     decoderConfig.customBackendCount     = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]);
2516     ```
2517
2518 The `ma_decoding_backend_vtable` vtable has the following functions:
2519
2520     ```
2521     onInit
2522     onInitFile 
2523     onInitFileW
2524     onInitMemory
2525     onUninit
2526     ```
2527
2528 There are only two functions that must be implemented - `onInit` and `onUninit`. The other
2529 functions can be implemented for a small optimization for loading from a file path or memory. If
2530 these are not specified, miniaudio will deal with it for you via a generic implementation.
2531
2532 When you initialize a custom data source (by implementing the `onInit` function in the vtable) you
2533 will need to output a pointer to a `ma_data_source` which implements your custom decoder. See the
2534 section about data sources for details on how to implemen this. Alternatively, see the
2535 "custom_decoders" example in the miniaudio repository.
2536
2537 The `onInit` function takes a pointer to some callbacks for the purpose of reading raw audio data
2538 from some abitrary source. You'll use these functions to read from the raw data and perform the
2539 decoding. When you call them, you will pass in the `pReadSeekTellUserData` pointer to the relevant
2540 parameter.
2541
2542 The `pConfig` parameter in `onInit` can be used to configure the backend if appropriate. It's only
2543 used as a hint and can be ignored. However, if any of the properties are relevant to your decoder,
2544 an optimal implementation will handle the relevant properties appropriately.
2545
2546 If memory allocation is required, it should be done so via the specified allocation callbacks if
2547 possible (the `pAllocationCallbacks` parameter).
2548
2549 If an error occurs when initializing the decoder, you should leave `ppBackend` unset, or set to
2550 NULL, and make sure everything is cleaned up appropriately and an appropriate result code returned.
2551 When multiple custom backends are specified, miniaudio will cycle through the vtables in the order
2552 they're listed in the array that's passed into the decoder config so it's important that your
2553 initialization routine is clean.
2554
2555 When a decoder is uninitialized, the `onUninit` callback will be fired which will give you an
2556 opportunity to clean up and internal data.
2557
2558
2559
2560 9. Encoding
2561 ===========
2562 The `ma_encoding` API is used for writing audio files. The only supported output format is WAV
2563 which is achieved via dr_wav which is amalgamated into the implementation section of miniaudio.
2564 This can be disabled by specifying the following option before the implementation of miniaudio:
2565
2566     ```c
2567     #define MA_NO_WAV
2568     ```
2569
2570 An encoder can be initialized to write to a file with `ma_encoder_init_file()` or from data
2571 delivered via callbacks with `ma_encoder_init()`. Below is an example for initializing an encoder
2572 to output to a file.
2573
2574     ```c
2575     ma_encoder_config config = ma_encoder_config_init(ma_encoding_format_wav, FORMAT, CHANNELS, SAMPLE_RATE);
2576     ma_encoder encoder;
2577     ma_result result = ma_encoder_init_file("my_file.wav", &config, &encoder);
2578     if (result != MA_SUCCESS) {
2579         // Error
2580     }
2581
2582     ...
2583
2584     ma_encoder_uninit(&encoder);
2585     ```
2586
2587 When initializing an encoder you must specify a config which is initialized with
2588 `ma_encoder_config_init()`. Here you must specify the file type, the output sample format, output
2589 channel count and output sample rate. The following file types are supported:
2590
2591     +------------------------+-------------+
2592     | Enum                   | Description |
2593     +------------------------+-------------+
2594     | ma_encoding_format_wav | WAV         |
2595     +------------------------+-------------+
2596
2597 If the format, channel count or sample rate is not supported by the output file type an error will
2598 be returned. The encoder will not perform data conversion so you will need to convert it before
2599 outputting any audio data. To output audio data, use `ma_encoder_write_pcm_frames()`, like in the
2600 example below:
2601
2602     ```c
2603     framesWritten = ma_encoder_write_pcm_frames(&encoder, pPCMFramesToWrite, framesToWrite);
2604     ```
2605
2606 Encoders must be uninitialized with `ma_encoder_uninit()`.
2607
2608
2609
2610 10. Data Conversion
2611 ===================
2612 A data conversion API is included with miniaudio which supports the majority of data conversion
2613 requirements. This supports conversion between sample formats, channel counts (with channel
2614 mapping) and sample rates.
2615
2616
2617 10.1. Sample Format Conversion
2618 ------------------------------
2619 Conversion between sample formats is achieved with the `ma_pcm_*_to_*()`, `ma_pcm_convert()` and
2620 `ma_convert_pcm_frames_format()` APIs. Use `ma_pcm_*_to_*()` to convert between two specific
2621 formats. Use `ma_pcm_convert()` to convert based on a `ma_format` variable. Use
2622 `ma_convert_pcm_frames_format()` to convert PCM frames where you want to specify the frame count
2623 and channel count as a variable instead of the total sample count.
2624
2625
2626 10.1.1. Dithering
2627 -----------------
2628 Dithering can be set using the ditherMode parameter.
2629
2630 The different dithering modes include the following, in order of efficiency:
2631
2632     +-----------+--------------------------+
2633     | Type      | Enum Token               |
2634     +-----------+--------------------------+
2635     | None      | ma_dither_mode_none      |
2636     | Rectangle | ma_dither_mode_rectangle |
2637     | Triangle  | ma_dither_mode_triangle  |
2638     +-----------+--------------------------+
2639
2640 Note that even if the dither mode is set to something other than `ma_dither_mode_none`, it will be
2641 ignored for conversions where dithering is not needed. Dithering is available for the following
2642 conversions:
2643
2644     ```
2645     s16 -> u8
2646     s24 -> u8
2647     s32 -> u8
2648     f32 -> u8
2649     s24 -> s16
2650     s32 -> s16
2651     f32 -> s16
2652     ```
2653
2654 Note that it is not an error to pass something other than ma_dither_mode_none for conversions where
2655 dither is not used. It will just be ignored.
2656
2657
2658
2659 10.2. Channel Conversion
2660 ------------------------
2661 Channel conversion is used for channel rearrangement and conversion from one channel count to
2662 another. The `ma_channel_converter` API is used for channel conversion. Below is an example of
2663 initializing a simple channel converter which converts from mono to stereo.
2664
2665     ```c
2666     ma_channel_converter_config config = ma_channel_converter_config_init(
2667         ma_format,                      // Sample format
2668         1,                              // Input channels
2669         NULL,                           // Input channel map
2670         2,                              // Output channels
2671         NULL,                           // Output channel map
2672         ma_channel_mix_mode_default);   // The mixing algorithm to use when combining channels.
2673
2674     result = ma_channel_converter_init(&config, &converter);
2675     if (result != MA_SUCCESS) {
2676         // Error.
2677     }
2678     ```
2679
2680 To perform the conversion simply call `ma_channel_converter_process_pcm_frames()` like so:
2681
2682     ```c
2683     ma_result result = ma_channel_converter_process_pcm_frames(&converter, pFramesOut, pFramesIn, frameCount);
2684     if (result != MA_SUCCESS) {
2685         // Error.
2686     }
2687     ```
2688
2689 It is up to the caller to ensure the output buffer is large enough to accomodate the new PCM
2690 frames.
2691
2692 Input and output PCM frames are always interleaved. Deinterleaved layouts are not supported.
2693
2694
2695 10.2.1. Channel Mapping
2696 -----------------------
2697 In addition to converting from one channel count to another, like the example above, the channel
2698 converter can also be used to rearrange channels. When initializing the channel converter, you can
2699 optionally pass in channel maps for both the input and output frames. If the channel counts are the
2700 same, and each channel map contains the same channel positions with the exception that they're in
2701 a different order, a simple shuffling of the channels will be performed. If, however, there is not
2702 a 1:1 mapping of channel positions, or the channel counts differ, the input channels will be mixed
2703 based on a mixing mode which is specified when initializing the `ma_channel_converter_config`
2704 object.
2705
2706 When converting from mono to multi-channel, the mono channel is simply copied to each output
2707 channel. When going the other way around, the audio of each output channel is simply averaged and
2708 copied to the mono channel.
2709
2710 In more complicated cases blending is used. The `ma_channel_mix_mode_simple` mode will drop excess
2711 channels and silence extra channels. For example, converting from 4 to 2 channels, the 3rd and 4th
2712 channels will be dropped, whereas converting from 2 to 4 channels will put silence into the 3rd and
2713 4th channels.
2714
2715 The `ma_channel_mix_mode_rectangle` mode uses spacial locality based on a rectangle to compute a
2716 simple distribution between input and output. Imagine sitting in the middle of a room, with
2717 speakers on the walls representing channel positions. The `MA_CHANNEL_FRONT_LEFT` position can be
2718 thought of as being in the corner of the front and left walls.
2719
2720 Finally, the `ma_channel_mix_mode_custom_weights` mode can be used to use custom user-defined
2721 weights. Custom weights can be passed in as the last parameter of
2722 `ma_channel_converter_config_init()`.
2723
2724 Predefined channel maps can be retrieved with `ma_channel_map_init_standard()`. This takes a
2725 `ma_standard_channel_map` enum as it's first parameter, which can be one of the following:
2726
2727     +-----------------------------------+-----------------------------------------------------------+
2728     | Name                              | Description                                               |
2729     +-----------------------------------+-----------------------------------------------------------+
2730     | ma_standard_channel_map_default   | Default channel map used by miniaudio. See below.         |
2731     | ma_standard_channel_map_microsoft | Channel map used by Microsoft's bitfield channel maps.    |
2732     | ma_standard_channel_map_alsa      | Default ALSA channel map.                                 |
2733     | ma_standard_channel_map_rfc3551   | RFC 3551. Based on AIFF.                                  |
2734     | ma_standard_channel_map_flac      | FLAC channel map.                                         |
2735     | ma_standard_channel_map_vorbis    | Vorbis channel map.                                       |
2736     | ma_standard_channel_map_sound4    | FreeBSD's sound(4).                                       |
2737     | ma_standard_channel_map_sndio     | sndio channel map. http://www.sndio.org/tips.html.        |
2738     | ma_standard_channel_map_webaudio  | https://webaudio.github.io/web-audio-api/#ChannelOrdering |
2739     +-----------------------------------+-----------------------------------------------------------+
2740
2741 Below are the channel maps used by default in miniaudio (`ma_standard_channel_map_default`):
2742
2743     +---------------+---------------------------------+
2744     | Channel Count | Mapping                         |
2745     +---------------+---------------------------------+
2746     | 1 (Mono)      | 0: MA_CHANNEL_MONO              |
2747     +---------------+---------------------------------+
2748     | 2 (Stereo)    | 0: MA_CHANNEL_FRONT_LEFT   <br> |
2749     |               | 1: MA_CHANNEL_FRONT_RIGHT       |
2750     +---------------+---------------------------------+
2751     | 3             | 0: MA_CHANNEL_FRONT_LEFT   <br> |
2752     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
2753     |               | 2: MA_CHANNEL_FRONT_CENTER      |
2754     +---------------+---------------------------------+
2755     | 4 (Surround)  | 0: MA_CHANNEL_FRONT_LEFT   <br> |
2756     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
2757     |               | 2: MA_CHANNEL_FRONT_CENTER <br> |
2758     |               | 3: MA_CHANNEL_BACK_CENTER       |
2759     +---------------+---------------------------------+
2760     | 5             | 0: MA_CHANNEL_FRONT_LEFT   <br> |
2761     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
2762     |               | 2: MA_CHANNEL_FRONT_CENTER <br> |
2763     |               | 3: MA_CHANNEL_BACK_LEFT    <br> |
2764     |               | 4: MA_CHANNEL_BACK_RIGHT        |
2765     +---------------+---------------------------------+
2766     | 6 (5.1)       | 0: MA_CHANNEL_FRONT_LEFT   <br> |
2767     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
2768     |               | 2: MA_CHANNEL_FRONT_CENTER <br> |
2769     |               | 3: MA_CHANNEL_LFE          <br> |
2770     |               | 4: MA_CHANNEL_SIDE_LEFT    <br> |
2771     |               | 5: MA_CHANNEL_SIDE_RIGHT        |
2772     +---------------+---------------------------------+
2773     | 7             | 0: MA_CHANNEL_FRONT_LEFT   <br> |
2774     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
2775     |               | 2: MA_CHANNEL_FRONT_CENTER <br> |
2776     |               | 3: MA_CHANNEL_LFE          <br> |
2777     |               | 4: MA_CHANNEL_BACK_CENTER  <br> |
2778     |               | 4: MA_CHANNEL_SIDE_LEFT    <br> |
2779     |               | 5: MA_CHANNEL_SIDE_RIGHT        |
2780     +---------------+---------------------------------+
2781     | 8 (7.1)       | 0: MA_CHANNEL_FRONT_LEFT   <br> |
2782     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
2783     |               | 2: MA_CHANNEL_FRONT_CENTER <br> |
2784     |               | 3: MA_CHANNEL_LFE          <br> |
2785     |               | 4: MA_CHANNEL_BACK_LEFT    <br> |
2786     |               | 5: MA_CHANNEL_BACK_RIGHT   <br> |
2787     |               | 6: MA_CHANNEL_SIDE_LEFT    <br> |
2788     |               | 7: MA_CHANNEL_SIDE_RIGHT        |
2789     +---------------+---------------------------------+
2790     | Other         | All channels set to 0. This     |
2791     |               | is equivalent to the same       |
2792     |               | mapping as the device.          |
2793     +---------------+---------------------------------+
2794
2795
2796
2797 10.3. Resampling
2798 ----------------
2799 Resampling is achieved with the `ma_resampler` object. To create a resampler object, do something
2800 like the following:
2801
2802     ```c
2803     ma_resampler_config config = ma_resampler_config_init(
2804         ma_format_s16,
2805         channels,
2806         sampleRateIn,
2807         sampleRateOut,
2808         ma_resample_algorithm_linear);
2809
2810     ma_resampler resampler;
2811     ma_result result = ma_resampler_init(&config, &resampler);
2812     if (result != MA_SUCCESS) {
2813         // An error occurred...
2814     }
2815     ```
2816
2817 Do the following to uninitialize the resampler:
2818
2819     ```c
2820     ma_resampler_uninit(&resampler);
2821     ```
2822
2823 The following example shows how data can be processed
2824
2825     ```c
2826     ma_uint64 frameCountIn  = 1000;
2827     ma_uint64 frameCountOut = 2000;
2828     ma_result result = ma_resampler_process_pcm_frames(&resampler, pFramesIn, &frameCountIn, pFramesOut, &frameCountOut);
2829     if (result != MA_SUCCESS) {
2830         // An error occurred...
2831     }
2832
2833     // At this point, frameCountIn contains the number of input frames that were consumed and frameCountOut contains the
2834     // number of output frames written.
2835     ```
2836
2837 To initialize the resampler you first need to set up a config (`ma_resampler_config`) with
2838 `ma_resampler_config_init()`. You need to specify the sample format you want to use, the number of
2839 channels, the input and output sample rate, and the algorithm.
2840
2841 The sample format can be either `ma_format_s16` or `ma_format_f32`. If you need a different format
2842 you will need to perform pre- and post-conversions yourself where necessary. Note that the format
2843 is the same for both input and output. The format cannot be changed after initialization.
2844
2845 The resampler supports multiple channels and is always interleaved (both input and output). The
2846 channel count cannot be changed after initialization.
2847
2848 The sample rates can be anything other than zero, and are always specified in hertz. They should be
2849 set to something like 44100, etc. The sample rate is the only configuration property that can be
2850 changed after initialization.
2851
2852 The miniaudio resampler has built-in support for the following algorithms:
2853
2854     +-----------+------------------------------+
2855     | Algorithm | Enum Token                   |
2856     +-----------+------------------------------+
2857     | Linear    | ma_resample_algorithm_linear |
2858     | Custom    | ma_resample_algorithm_custom |
2859     +-----------+------------------------------+
2860
2861 The algorithm cannot be changed after initialization.
2862
2863 Processing always happens on a per PCM frame basis and always assumes interleaved input and output.
2864 De-interleaved processing is not supported. To process frames, use
2865 `ma_resampler_process_pcm_frames()`. On input, this function takes the number of output frames you
2866 can fit in the output buffer and the number of input frames contained in the input buffer. On
2867 output these variables contain the number of output frames that were written to the output buffer
2868 and the number of input frames that were consumed in the process. You can pass in NULL for the
2869 input buffer in which case it will be treated as an infinitely large buffer of zeros. The output
2870 buffer can also be NULL, in which case the processing will be treated as seek.
2871
2872 The sample rate can be changed dynamically on the fly. You can change this with explicit sample
2873 rates with `ma_resampler_set_rate()` and also with a decimal ratio with
2874 `ma_resampler_set_rate_ratio()`. The ratio is in/out.
2875
2876 Sometimes it's useful to know exactly how many input frames will be required to output a specific
2877 number of frames. You can calculate this with `ma_resampler_get_required_input_frame_count()`.
2878 Likewise, it's sometimes useful to know exactly how many frames would be output given a certain
2879 number of input frames. You can do this with `ma_resampler_get_expected_output_frame_count()`.
2880
2881 Due to the nature of how resampling works, the resampler introduces some latency. This can be
2882 retrieved in terms of both the input rate and the output rate with
2883 `ma_resampler_get_input_latency()` and `ma_resampler_get_output_latency()`.
2884
2885
2886 10.3.1. Resampling Algorithms
2887 -----------------------------
2888 The choice of resampling algorithm depends on your situation and requirements.
2889
2890
2891 10.3.1.1. Linear Resampling
2892 ---------------------------
2893 The linear resampler is the fastest, but comes at the expense of poorer quality. There is, however,
2894 some control over the quality of the linear resampler which may make it a suitable option depending
2895 on your requirements.
2896
2897 The linear resampler performs low-pass filtering before or after downsampling or upsampling,
2898 depending on the sample rates you're converting between. When decreasing the sample rate, the
2899 low-pass filter will be applied before downsampling. When increasing the rate it will be performed
2900 after upsampling. By default a fourth order low-pass filter will be applied. This can be configured
2901 via the `lpfOrder` configuration variable. Setting this to 0 will disable filtering.
2902
2903 The low-pass filter has a cutoff frequency which defaults to half the sample rate of the lowest of
2904 the input and output sample rates (Nyquist Frequency).
2905
2906 The API for the linear resampler is the same as the main resampler API, only it's called
2907 `ma_linear_resampler`.
2908
2909
2910 10.3.2. Custom Resamplers
2911 -------------------------
2912 You can implement a custom resampler by using the `ma_resample_algorithm_custom` resampling
2913 algorithm and setting a vtable in the resampler config:
2914
2915     ```c
2916     ma_resampler_config config = ma_resampler_config_init(..., ma_resample_algorithm_custom);
2917     config.pBackendVTable = &g_customResamplerVTable;
2918     ```
2919
2920 Custom resamplers are useful if the stock algorithms are not appropriate for your use case. You
2921 need to implement the required functions in `ma_resampling_backend_vtable`. Note that not all
2922 functions in the vtable need to be implemented, but if it's possible to implement, they should be.
2923
2924 You can use the `ma_linear_resampler` object for an example on how to implement the vtable. The
2925 `onGetHeapSize` callback is used to calculate the size of any internal heap allocation the custom
2926 resampler will need to make given the supplied config. When you initialize the resampler via the
2927 `onInit` callback, you'll be given a pointer to a heap allocation which is where you should store
2928 the heap allocated data. You should not free this data in `onUninit` because miniaudio will manage
2929 it for you.
2930
2931 The `onProcess` callback is where the actual resampling takes place. On input, `pFrameCountIn`
2932 points to a variable containing the number of frames in the `pFramesIn` buffer and
2933 `pFrameCountOut` points to a variable containing the capacity in frames of the `pFramesOut` buffer.
2934 On output, `pFrameCountIn` should be set to the number of input frames that were fully consumed,
2935 whereas `pFrameCountOut` should be set to the number of frames that were written to `pFramesOut`.
2936
2937 The `onSetRate` callback is optional and is used for dynamically changing the sample rate. If
2938 dynamic rate changes are not supported, you can set this callback to NULL.
2939
2940 The `onGetInputLatency` and `onGetOutputLatency` functions are used for retrieving the latency in
2941 input and output rates respectively. These can be NULL in which case latency calculations will be
2942 assumed to be NULL.
2943
2944 The `onGetRequiredInputFrameCount` callback is used to give miniaudio a hint as to how many input
2945 frames are required to be available to produce the given number of output frames. Likewise, the
2946 `onGetExpectedOutputFrameCount` callback is used to determine how many output frames will be
2947 produced given the specified number of input frames. miniaudio will use these as a hint, but they
2948 are optional and can be set to NULL if you're unable to implement them.
2949
2950
2951
2952 10.4. General Data Conversion
2953 -----------------------------
2954 The `ma_data_converter` API can be used to wrap sample format conversion, channel conversion and
2955 resampling into one operation. This is what miniaudio uses internally to convert between the format
2956 requested when the device was initialized and the format of the backend's native device. The API
2957 for general data conversion is very similar to the resampling API. Create a `ma_data_converter`
2958 object like this:
2959
2960     ```c
2961     ma_data_converter_config config = ma_data_converter_config_init(
2962         inputFormat,
2963         outputFormat,
2964         inputChannels,
2965         outputChannels,
2966         inputSampleRate,
2967         outputSampleRate
2968     );
2969
2970     ma_data_converter converter;
2971     ma_result result = ma_data_converter_init(&config, &converter);
2972     if (result != MA_SUCCESS) {
2973         // An error occurred...
2974     }
2975     ```
2976
2977 In the example above we use `ma_data_converter_config_init()` to initialize the config, however
2978 there's many more properties that can be configured, such as channel maps and resampling quality.
2979 Something like the following may be more suitable depending on your requirements:
2980
2981     ```c
2982     ma_data_converter_config config = ma_data_converter_config_init_default();
2983     config.formatIn = inputFormat;
2984     config.formatOut = outputFormat;
2985     config.channelsIn = inputChannels;
2986     config.channelsOut = outputChannels;
2987     config.sampleRateIn = inputSampleRate;
2988     config.sampleRateOut = outputSampleRate;
2989     ma_channel_map_init_standard(ma_standard_channel_map_flac, config.channelMapIn, sizeof(config.channelMapIn)/sizeof(config.channelMapIn[0]), config.channelCountIn);
2990     config.resampling.linear.lpfOrder = MA_MAX_FILTER_ORDER;
2991     ```
2992
2993 Do the following to uninitialize the data converter:
2994
2995     ```c
2996     ma_data_converter_uninit(&converter);
2997     ```
2998
2999 The following example shows how data can be processed
3000
3001     ```c
3002     ma_uint64 frameCountIn  = 1000;
3003     ma_uint64 frameCountOut = 2000;
3004     ma_result result = ma_data_converter_process_pcm_frames(&converter, pFramesIn, &frameCountIn, pFramesOut, &frameCountOut);
3005     if (result != MA_SUCCESS) {
3006         // An error occurred...
3007     }
3008
3009     // At this point, frameCountIn contains the number of input frames that were consumed and frameCountOut contains the number
3010     // of output frames written.
3011     ```
3012
3013 The data converter supports multiple channels and is always interleaved (both input and output).
3014 The channel count cannot be changed after initialization.
3015
3016 Sample rates can be anything other than zero, and are always specified in hertz. They should be set
3017 to something like 44100, etc. The sample rate is the only configuration property that can be
3018 changed after initialization, but only if the `resampling.allowDynamicSampleRate` member of
3019 `ma_data_converter_config` is set to `MA_TRUE`. To change the sample rate, use
3020 `ma_data_converter_set_rate()` or `ma_data_converter_set_rate_ratio()`. The ratio must be in/out.
3021 The resampling algorithm cannot be changed after initialization.
3022
3023 Processing always happens on a per PCM frame basis and always assumes interleaved input and output.
3024 De-interleaved processing is not supported. To process frames, use
3025 `ma_data_converter_process_pcm_frames()`. On input, this function takes the number of output frames
3026 you can fit in the output buffer and the number of input frames contained in the input buffer. On
3027 output these variables contain the number of output frames that were written to the output buffer
3028 and the number of input frames that were consumed in the process. You can pass in NULL for the
3029 input buffer in which case it will be treated as an infinitely large
3030 buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated
3031 as seek.
3032
3033 Sometimes it's useful to know exactly how many input frames will be required to output a specific
3034 number of frames. You can calculate this with `ma_data_converter_get_required_input_frame_count()`.
3035 Likewise, it's sometimes useful to know exactly how many frames would be output given a certain
3036 number of input frames. You can do this with `ma_data_converter_get_expected_output_frame_count()`.
3037
3038 Due to the nature of how resampling works, the data converter introduces some latency if resampling
3039 is required. This can be retrieved in terms of both the input rate and the output rate with
3040 `ma_data_converter_get_input_latency()` and `ma_data_converter_get_output_latency()`.
3041
3042
3043
3044 11. Filtering
3045 =============
3046
3047 11.1. Biquad Filtering
3048 ----------------------
3049 Biquad filtering is achieved with the `ma_biquad` API. Example:
3050
3051     ```c
3052     ma_biquad_config config = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2);
3053     ma_result result = ma_biquad_init(&config, &biquad);
3054     if (result != MA_SUCCESS) {
3055         // Error.
3056     }
3057
3058     ...
3059
3060     ma_biquad_process_pcm_frames(&biquad, pFramesOut, pFramesIn, frameCount);
3061     ```
3062
3063 Biquad filtering is implemented using transposed direct form 2. The numerator coefficients are b0,
3064 b1 and b2, and the denominator coefficients are a0, a1 and a2. The a0 coefficient is required and
3065 coefficients must not be pre-normalized.
3066
3067 Supported formats are `ma_format_s16` and `ma_format_f32`. If you need to use a different format
3068 you need to convert it yourself beforehand. When using `ma_format_s16` the biquad filter will use
3069 fixed point arithmetic. When using `ma_format_f32`, floating point arithmetic will be used.
3070
3071 Input and output frames are always interleaved.
3072
3073 Filtering can be applied in-place by passing in the same pointer for both the input and output
3074 buffers, like so:
3075
3076     ```c
3077     ma_biquad_process_pcm_frames(&biquad, pMyData, pMyData, frameCount);
3078     ```
3079
3080 If you need to change the values of the coefficients, but maintain the values in the registers you
3081 can do so with `ma_biquad_reinit()`. This is useful if you need to change the properties of the
3082 filter while keeping the values of registers valid to avoid glitching. Do not use
3083 `ma_biquad_init()` for this as it will do a full initialization which involves clearing the
3084 registers to 0. Note that changing the format or channel count after initialization is invalid and
3085 will result in an error.
3086
3087
3088 11.2. Low-Pass Filtering
3089 ------------------------
3090 Low-pass filtering is achieved with the following APIs:
3091
3092     +---------+------------------------------------------+
3093     | API     | Description                              |
3094     +---------+------------------------------------------+
3095     | ma_lpf1 | First order low-pass filter              |
3096     | ma_lpf2 | Second order low-pass filter             |
3097     | ma_lpf  | High order low-pass filter (Butterworth) |
3098     +---------+------------------------------------------+
3099
3100 Low-pass filter example:
3101
3102     ```c
3103     ma_lpf_config config = ma_lpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order);
3104     ma_result result = ma_lpf_init(&config, &lpf);
3105     if (result != MA_SUCCESS) {
3106         // Error.
3107     }
3108
3109     ...
3110
3111     ma_lpf_process_pcm_frames(&lpf, pFramesOut, pFramesIn, frameCount);
3112     ```
3113
3114 Supported formats are `ma_format_s16` and` ma_format_f32`. If you need to use a different format
3115 you need to convert it yourself beforehand. Input and output frames are always interleaved.
3116
3117 Filtering can be applied in-place by passing in the same pointer for both the input and output
3118 buffers, like so:
3119
3120     ```c
3121     ma_lpf_process_pcm_frames(&lpf, pMyData, pMyData, frameCount);
3122     ```
3123
3124 The maximum filter order is limited to `MA_MAX_FILTER_ORDER` which is set to 8. If you need more,
3125 you can chain first and second order filters together.
3126
3127     ```c
3128     for (iFilter = 0; iFilter < filterCount; iFilter += 1) {
3129         ma_lpf2_process_pcm_frames(&lpf2[iFilter], pMyData, pMyData, frameCount);
3130     }
3131     ```
3132
3133 If you need to change the configuration of the filter, but need to maintain the state of internal
3134 registers you can do so with `ma_lpf_reinit()`. This may be useful if you need to change the sample
3135 rate and/or cutoff frequency dynamically while maintaing smooth transitions. Note that changing the
3136 format or channel count after initialization is invalid and will result in an error.
3137
3138 The `ma_lpf` object supports a configurable order, but if you only need a first order filter you
3139 may want to consider using `ma_lpf1`. Likewise, if you only need a second order filter you can use
3140 `ma_lpf2`. The advantage of this is that they're lighter weight and a bit more efficient.
3141
3142 If an even filter order is specified, a series of second order filters will be processed in a
3143 chain. If an odd filter order is specified, a first order filter will be applied, followed by a
3144 series of second order filters in a chain.
3145
3146
3147 11.3. High-Pass Filtering
3148 -------------------------
3149 High-pass filtering is achieved with the following APIs:
3150
3151     +---------+-------------------------------------------+
3152     | API     | Description                               |
3153     +---------+-------------------------------------------+
3154     | ma_hpf1 | First order high-pass filter              |
3155     | ma_hpf2 | Second order high-pass filter             |
3156     | ma_hpf  | High order high-pass filter (Butterworth) |
3157     +---------+-------------------------------------------+
3158
3159 High-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_hpf1`,
3160 `ma_hpf2` and `ma_hpf`. See example code for low-pass filters for example usage.
3161
3162
3163 11.4. Band-Pass Filtering
3164 -------------------------
3165 Band-pass filtering is achieved with the following APIs:
3166
3167     +---------+-------------------------------+
3168     | API     | Description                   |
3169     +---------+-------------------------------+
3170     | ma_bpf2 | Second order band-pass filter |
3171     | ma_bpf  | High order band-pass filter   |
3172     +---------+-------------------------------+
3173
3174 Band-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_bpf2` and
3175 `ma_hpf`. See example code for low-pass filters for example usage. Note that the order for
3176 band-pass filters must be an even number which means there is no first order band-pass filter,
3177 unlike low-pass and high-pass filters.
3178
3179
3180 11.5. Notch Filtering
3181 ---------------------
3182 Notch filtering is achieved with the following APIs:
3183
3184     +-----------+------------------------------------------+
3185     | API       | Description                              |
3186     +-----------+------------------------------------------+
3187     | ma_notch2 | Second order notching filter             |
3188     +-----------+------------------------------------------+
3189
3190
3191 11.6. Peaking EQ Filtering
3192 -------------------------
3193 Peaking filtering is achieved with the following APIs:
3194
3195     +----------+------------------------------------------+
3196     | API      | Description                              |
3197     +----------+------------------------------------------+
3198     | ma_peak2 | Second order peaking filter              |
3199     +----------+------------------------------------------+
3200
3201
3202 11.7. Low Shelf Filtering
3203 -------------------------
3204 Low shelf filtering is achieved with the following APIs:
3205
3206     +-------------+------------------------------------------+
3207     | API         | Description                              |
3208     +-------------+------------------------------------------+
3209     | ma_loshelf2 | Second order low shelf filter            |
3210     +-------------+------------------------------------------+
3211
3212 Where a high-pass filter is used to eliminate lower frequencies, a low shelf filter can be used to
3213 just turn them down rather than eliminate them entirely.
3214
3215
3216 11.8. High Shelf Filtering
3217 --------------------------
3218 High shelf filtering is achieved with the following APIs:
3219
3220     +-------------+------------------------------------------+
3221     | API         | Description                              |
3222     +-------------+------------------------------------------+
3223     | ma_hishelf2 | Second order high shelf filter           |
3224     +-------------+------------------------------------------+
3225
3226 The high shelf filter has the same API as the low shelf filter, only you would use `ma_hishelf`
3227 instead of `ma_loshelf`. Where a low shelf filter is used to adjust the volume of low frequencies,
3228 the high shelf filter does the same thing for high frequencies.
3229
3230
3231
3232
3233 12. Waveform and Noise Generation
3234 =================================
3235
3236 12.1. Waveforms
3237 ---------------
3238 miniaudio supports generation of sine, square, triangle and sawtooth waveforms. This is achieved
3239 with the `ma_waveform` API. Example:
3240
3241     ```c
3242     ma_waveform_config config = ma_waveform_config_init(
3243         FORMAT,
3244         CHANNELS,
3245         SAMPLE_RATE,
3246         ma_waveform_type_sine,
3247         amplitude,
3248         frequency);
3249
3250     ma_waveform waveform;
3251     ma_result result = ma_waveform_init(&config, &waveform);
3252     if (result != MA_SUCCESS) {
3253         // Error.
3254     }
3255
3256     ...
3257
3258     ma_waveform_read_pcm_frames(&waveform, pOutput, frameCount);
3259     ```
3260
3261 The amplitude, frequency, type, and sample rate can be changed dynamically with
3262 `ma_waveform_set_amplitude()`, `ma_waveform_set_frequency()`, `ma_waveform_set_type()`, and
3263 `ma_waveform_set_sample_rate()` respectively.
3264
3265 You can invert the waveform by setting the amplitude to a negative value. You can use this to
3266 control whether or not a sawtooth has a positive or negative ramp, for example.
3267
3268 Below are the supported waveform types:
3269
3270     +---------------------------+
3271     | Enum Name                 |
3272     +---------------------------+
3273     | ma_waveform_type_sine     |
3274     | ma_waveform_type_square   |
3275     | ma_waveform_type_triangle |
3276     | ma_waveform_type_sawtooth |
3277     +---------------------------+
3278
3279
3280
3281 12.2. Noise
3282 -----------
3283 miniaudio supports generation of white, pink and Brownian noise via the `ma_noise` API. Example:
3284
3285     ```c
3286     ma_noise_config config = ma_noise_config_init(
3287         FORMAT,
3288         CHANNELS,
3289         ma_noise_type_white,
3290         SEED,
3291         amplitude);
3292
3293     ma_noise noise;
3294     ma_result result = ma_noise_init(&config, &noise);
3295     if (result != MA_SUCCESS) {
3296         // Error.
3297     }
3298
3299     ...
3300
3301     ma_noise_read_pcm_frames(&noise, pOutput, frameCount);
3302     ```
3303
3304 The noise API uses simple LCG random number generation. It supports a custom seed which is useful
3305 for things like automated testing requiring reproducibility. Setting the seed to zero will default
3306 to `MA_DEFAULT_LCG_SEED`.
3307
3308 The amplitude, seed, and type can be changed dynamically with `ma_noise_set_amplitude()`,
3309 `ma_noise_set_seed()`, and `ma_noise_set_type()` respectively.
3310
3311 By default, the noise API will use different values for different channels. So, for example, the
3312 left side in a stereo stream will be different to the right side. To instead have each channel use
3313 the same random value, set the `duplicateChannels` member of the noise config to true, like so:
3314
3315     ```c
3316     config.duplicateChannels = MA_TRUE;
3317     ```
3318
3319 Below are the supported noise types.
3320
3321     +------------------------+
3322     | Enum Name              |
3323     +------------------------+
3324     | ma_noise_type_white    |
3325     | ma_noise_type_pink     |
3326     | ma_noise_type_brownian |
3327     +------------------------+
3328
3329
3330
3331 13. Audio Buffers
3332 =================
3333 miniaudio supports reading from a buffer of raw audio data via the `ma_audio_buffer` API. This can
3334 read from memory that's managed by the application, but can also handle the memory management for
3335 you internally. Memory management is flexible and should support most use cases.
3336
3337 Audio buffers are initialised using the standard configuration system used everywhere in miniaudio:
3338
3339     ```c
3340     ma_audio_buffer_config config = ma_audio_buffer_config_init(
3341         format,
3342         channels,
3343         sizeInFrames,
3344         pExistingData,
3345         &allocationCallbacks);
3346
3347     ma_audio_buffer buffer;
3348     result = ma_audio_buffer_init(&config, &buffer);
3349     if (result != MA_SUCCESS) {
3350         // Error.
3351     }
3352
3353     ...
3354
3355     ma_audio_buffer_uninit(&buffer);
3356     ```
3357
3358 In the example above, the memory pointed to by `pExistingData` will *not* be copied and is how an
3359 application can do self-managed memory allocation. If you would rather make a copy of the data, use
3360 `ma_audio_buffer_init_copy()`. To uninitialize the buffer, use `ma_audio_buffer_uninit()`.
3361
3362 Sometimes it can be convenient to allocate the memory for the `ma_audio_buffer` structure and the
3363 raw audio data in a contiguous block of memory. That is, the raw audio data will be located
3364 immediately after the `ma_audio_buffer` structure. To do this, use
3365 `ma_audio_buffer_alloc_and_init()`:
3366
3367     ```c
3368     ma_audio_buffer_config config = ma_audio_buffer_config_init(
3369         format,
3370         channels,
3371         sizeInFrames,
3372         pExistingData,
3373         &allocationCallbacks);
3374
3375     ma_audio_buffer* pBuffer
3376     result = ma_audio_buffer_alloc_and_init(&config, &pBuffer);
3377     if (result != MA_SUCCESS) {
3378         // Error
3379     }
3380
3381     ...
3382
3383     ma_audio_buffer_uninit_and_free(&buffer);
3384     ```
3385
3386 If you initialize the buffer with `ma_audio_buffer_alloc_and_init()` you should uninitialize it
3387 with `ma_audio_buffer_uninit_and_free()`. In the example above, the memory pointed to by
3388 `pExistingData` will be copied into the buffer, which is contrary to the behavior of
3389 `ma_audio_buffer_init()`.
3390
3391 An audio buffer has a playback cursor just like a decoder. As you read frames from the buffer, the
3392 cursor moves forward. The last parameter (`loop`) can be used to determine if the buffer should
3393 loop. The return value is the number of frames actually read. If this is less than the number of
3394 frames requested it means the end has been reached. This should never happen if the `loop`
3395 parameter is set to true. If you want to manually loop back to the start, you can do so with with
3396 `ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)`. Below is an example for reading data from an
3397 audio buffer.
3398
3399     ```c
3400     ma_uint64 framesRead = ma_audio_buffer_read_pcm_frames(pAudioBuffer, pFramesOut, desiredFrameCount, isLooping);
3401     if (framesRead < desiredFrameCount) {
3402         // If not looping, this means the end has been reached. This should never happen in looping mode with valid input.
3403     }
3404     ```
3405
3406 Sometimes you may want to avoid the cost of data movement between the internal buffer and the
3407 output buffer. Instead you can use memory mapping to retrieve a pointer to a segment of data:
3408
3409     ```c
3410     void* pMappedFrames;
3411     ma_uint64 frameCount = frameCountToTryMapping;
3412     ma_result result = ma_audio_buffer_map(pAudioBuffer, &pMappedFrames, &frameCount);
3413     if (result == MA_SUCCESS) {
3414         // Map was successful. The value in frameCount will be how many frames were _actually_ mapped, which may be
3415         // less due to the end of the buffer being reached.
3416         ma_copy_pcm_frames(pFramesOut, pMappedFrames, frameCount, pAudioBuffer->format, pAudioBuffer->channels);
3417
3418         // You must unmap the buffer.
3419         ma_audio_buffer_unmap(pAudioBuffer, frameCount);
3420     }
3421     ```
3422
3423 When you use memory mapping, the read cursor is increment by the frame count passed in to
3424 `ma_audio_buffer_unmap()`. If you decide not to process every frame you can pass in a value smaller
3425 than the value returned by `ma_audio_buffer_map()`. The disadvantage to using memory mapping is
3426 that it does not handle looping for you. You can determine if the buffer is at the end for the
3427 purpose of looping with `ma_audio_buffer_at_end()` or by inspecting the return value of
3428 `ma_audio_buffer_unmap()` and checking if it equals `MA_AT_END`. You should not treat `MA_AT_END`
3429 as an error when returned by `ma_audio_buffer_unmap()`.
3430
3431
3432
3433 14. Ring Buffers
3434 ================
3435 miniaudio supports lock free (single producer, single consumer) ring buffers which are exposed via
3436 the `ma_rb` and `ma_pcm_rb` APIs. The `ma_rb` API operates on bytes, whereas the `ma_pcm_rb`
3437 operates on PCM frames. They are otherwise identical as `ma_pcm_rb` is just a wrapper around
3438 `ma_rb`.
3439
3440 Unlike most other APIs in miniaudio, ring buffers support both interleaved and deinterleaved
3441 streams. The caller can also allocate their own backing memory for the ring buffer to use
3442 internally for added flexibility. Otherwise the ring buffer will manage it's internal memory for
3443 you.
3444
3445 The examples below use the PCM frame variant of the ring buffer since that's most likely the one
3446 you will want to use. To initialize a ring buffer, do something like the following:
3447
3448     ```c
3449     ma_pcm_rb rb;
3450     ma_result result = ma_pcm_rb_init(FORMAT, CHANNELS, BUFFER_SIZE_IN_FRAMES, NULL, NULL, &rb);
3451     if (result != MA_SUCCESS) {
3452         // Error
3453     }
3454     ```
3455
3456 The `ma_pcm_rb_init()` function takes the sample format and channel count as parameters because
3457 it's the PCM varient of the ring buffer API. For the regular ring buffer that operates on bytes you
3458 would call `ma_rb_init()` which leaves these out and just takes the size of the buffer in bytes
3459 instead of frames. The fourth parameter is an optional pre-allocated buffer and the fifth parameter
3460 is a pointer to a `ma_allocation_callbacks` structure for custom memory allocation routines.
3461 Passing in `NULL` for this results in `MA_MALLOC()` and `MA_FREE()` being used.
3462
3463 Use `ma_pcm_rb_init_ex()` if you need a deinterleaved buffer. The data for each sub-buffer is
3464 offset from each other based on the stride. To manage your sub-buffers you can use
3465 `ma_pcm_rb_get_subbuffer_stride()`, `ma_pcm_rb_get_subbuffer_offset()` and
3466 `ma_pcm_rb_get_subbuffer_ptr()`.
3467
3468 Use `ma_pcm_rb_acquire_read()` and `ma_pcm_rb_acquire_write()` to retrieve a pointer to a section
3469 of the ring buffer. You specify the number of frames you need, and on output it will set to what
3470 was actually acquired. If the read or write pointer is positioned such that the number of frames
3471 requested will require a loop, it will be clamped to the end of the buffer. Therefore, the number
3472 of frames you're given may be less than the number you requested.
3473
3474 After calling `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()`, you do your work on the
3475 buffer and then "commit" it with `ma_pcm_rb_commit_read()` or `ma_pcm_rb_commit_write()`. This is
3476 where the read/write pointers are updated. When you commit you need to pass in the buffer that was
3477 returned by the earlier call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is
3478 only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and
3479 `ma_pcm_rb_commit_write()` is what's used to increment the pointers, and can be less that what was
3480 originally requested.
3481
3482 If you want to correct for drift between the write pointer and the read pointer you can use a
3483 combination of `ma_pcm_rb_pointer_distance()`, `ma_pcm_rb_seek_read()` and
3484 `ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only
3485 move the read pointer forward via the consumer thread, and the write pointer forward by the
3486 producer thread. If there is too much space between the pointers, move the read pointer forward. If
3487 there is too little space between the pointers, move the write pointer forward.
3488
3489 You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb`
3490 API. This is exactly the same, only you will use the `ma_rb` functions instead of `ma_pcm_rb` and
3491 instead of frame counts you will pass around byte counts.
3492
3493 The maximum size of the buffer in bytes is `0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)` due to the most
3494 significant bit being used to encode a loop flag and the internally managed buffers always being
3495 aligned to `MA_SIMD_ALIGNMENT`.
3496
3497 Note that the ring buffer is only thread safe when used by a single consumer thread and single
3498 producer thread.
3499
3500
3501
3502 15. Backends
3503 ============
3504 The following backends are supported by miniaudio.
3505
3506     +-------------+-----------------------+--------------------------------------------------------+
3507     | Name        | Enum Name             | Supported Operating Systems                            |
3508     +-------------+-----------------------+--------------------------------------------------------+
3509     | WASAPI      | ma_backend_wasapi     | Windows Vista+                                         |
3510     | DirectSound | ma_backend_dsound     | Windows XP+                                            |
3511     | WinMM       | ma_backend_winmm      | Windows XP+ (may work on older versions, but untested) |
3512     | Core Audio  | ma_backend_coreaudio  | macOS, iOS                                             |
3513     | ALSA        | ma_backend_alsa       | Linux                                                  |
3514     | PulseAudio  | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android)  |
3515     | JACK        | ma_backend_jack       | Cross Platform (disabled on BSD and Android)           |
3516     | sndio       | ma_backend_sndio      | OpenBSD                                                |
3517     | audio(4)    | ma_backend_audio4     | NetBSD, OpenBSD                                        |
3518     | OSS         | ma_backend_oss        | FreeBSD                                                |
3519     | AAudio      | ma_backend_aaudio     | Android 8+                                             |
3520     | OpenSL ES   | ma_backend_opensl     | Android (API level 16+)                                |
3521     | Web Audio   | ma_backend_webaudio   | Web (via Emscripten)                                   |
3522     | Custom      | ma_backend_custom     | Cross Platform                                         |
3523     | Null        | ma_backend_null       | Cross Platform (not used on Web)                       |
3524     +-------------+-----------------------+--------------------------------------------------------+
3525
3526 Some backends have some nuance details you may want to be aware of.
3527
3528 15.1. WASAPI
3529 ------------
3530 - Low-latency shared mode will be disabled when using an application-defined sample rate which is
3531   different to the device's native sample rate. To work around this, set `wasapi.noAutoConvertSRC`
3532   to true in the device config. This is due to IAudioClient3_InitializeSharedAudioStream() failing
3533   when the `AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM` flag is specified. Setting wasapi.noAutoConvertSRC
3534   will result in miniaudio's internal resampler being used instead which will in turn enable the
3535   use of low-latency shared mode.
3536
3537 15.2. PulseAudio
3538 ----------------
3539 - If you experience bad glitching/noise on Arch Linux, consider this fix from the Arch wiki:
3540   https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling.
3541   Alternatively, consider using a different backend such as ALSA.
3542
3543 15.3. Android
3544 -------------
3545 - To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest:
3546   `<uses-permission android:name="android.permission.RECORD_AUDIO" />`
3547 - With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a
3548   limitation with OpenSL|ES.
3549 - With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration
3550   API (devices are enumerated through Java). You can however perform your own device enumeration
3551   through Java and then set the ID in the ma_device_id structure (ma_device_id.aaudio) and pass it
3552   to ma_device_init().
3553 - The backend API will perform resampling where possible. The reason for this as opposed to using
3554   miniaudio's built-in resampler is to take advantage of any potential device-specific
3555   optimizations the driver may implement.
3556
3557 15.4. UWP
3558 ---------
3559 - UWP only supports default playback and capture devices.
3560 - UWP requires the Microphone capability to be enabled in the application's manifest (Package.appxmanifest):
3561
3562     ```
3563     <Package ...>
3564         ...
3565         <Capabilities>
3566             <DeviceCapability Name="microphone" />
3567         </Capabilities>
3568     </Package>
3569     ```
3570
3571 15.5. Web Audio / Emscripten
3572 ----------------------------
3573 - You cannot use `-std=c*` compiler flags, nor `-ansi`. This only applies to the Emscripten build.
3574 - The first time a context is initialized it will create a global object called "miniaudio" whose
3575   primary purpose is to act as a factory for device objects.
3576 - Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as
3577   they've been deprecated.
3578 - Google has implemented a policy in their browsers that prevent automatic media output without
3579   first receiving some kind of user input. The following web page has additional details:
3580   https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting the device
3581   may fail if you try to start playback without first handling some kind of user input.
3582
3583
3584
3585 16. Optimization Tips
3586 =====================
3587
3588 16.1. High Level API
3589 --------------------
3590 - If a sound does not require doppler or pitch shifting, consider disabling pitching by
3591   initializing the sound with the `MA_SOUND_FLAG_NO_PITCH` flag.
3592 - If a sound does not require spatialization, disable it by initialzing the sound with the
3593   `MA_SOUND_FLAG_NO_SPATIALIZATION` flag. It can be renabled again post-initialization with
3594   `ma_sound_set_spatialization_enabled()`.
3595
3596
3597
3598 17. Miscellaneous Notes
3599 =======================
3600 - Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for
3601   WASAPI and Core Audio, however other backends such as PulseAudio may naturally support it, though
3602   not all have been tested.
3603 - The contents of the output buffer passed into the data callback will always be pre-initialized to
3604   silence unless the `noPreZeroedOutputBuffer` config variable in `ma_device_config` is set to true,
3605   in which case it'll be undefined which will require you to write something to the entire buffer.
3606 - By default miniaudio will automatically clip samples. This only applies when the playback sample
3607   format is configured as `ma_format_f32`. If you are doing clipping yourself, you can disable this
3608   overhead by setting `noClip` to true in the device config.
3609 - Note that GCC and Clang requires `-msse2`, `-mavx2`, etc. for SIMD optimizations.
3610 - The sndio backend is currently only enabled on OpenBSD builds.
3611 - The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can
3612   use it.
3613 - When compiling with VC6 and earlier, decoding is restricted to files less than 2GB in size. This
3614   is due to 64-bit file APIs not being available.
3615 */
3616
3617 #ifndef miniaudio_h
3618 #define miniaudio_h
3619
3620 #ifdef __cplusplus
3621 extern "C" {
3622 #endif
3623
3624 #define MA_STRINGIFY(x)     #x
3625 #define MA_XSTRINGIFY(x)    MA_STRINGIFY(x)
3626
3627 #define MA_VERSION_MAJOR    0
3628 #define MA_VERSION_MINOR    11
3629 #define MA_VERSION_REVISION 2
3630 #define MA_VERSION_STRING   MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
3631
3632 #if defined(_MSC_VER) && !defined(__clang__)
3633     #pragma warning(push)
3634     #pragma warning(disable:4201)   /* nonstandard extension used: nameless struct/union */
3635     #pragma warning(disable:4214)   /* nonstandard extension used: bit field types other than int */
3636     #pragma warning(disable:4324)   /* structure was padded due to alignment specifier */
3637 #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
3638     #pragma GCC diagnostic push
3639     #pragma GCC diagnostic ignored "-Wpedantic" /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
3640     #if defined(__clang__)
3641         #pragma GCC diagnostic ignored "-Wc11-extensions"   /* anonymous unions are a C11 extension */
3642     #endif
3643 #endif
3644   
3645
3646
3647 #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
3648     #define MA_SIZEOF_PTR   8
3649 #else
3650     #define MA_SIZEOF_PTR   4
3651 #endif
3652
3653 #include <stddef.h> /* For size_t. */
3654
3655 /* Sized types. */
3656 #if defined(MA_USE_STDINT)
3657     #include <stdint.h>
3658     typedef int8_t   ma_int8;
3659     typedef uint8_t  ma_uint8;
3660     typedef int16_t  ma_int16;
3661     typedef uint16_t ma_uint16;
3662     typedef int32_t  ma_int32;
3663     typedef uint32_t ma_uint32;
3664     typedef int64_t  ma_int64;
3665     typedef uint64_t ma_uint64;
3666 #else
3667     typedef   signed char           ma_int8;
3668     typedef unsigned char           ma_uint8;
3669     typedef   signed short          ma_int16;
3670     typedef unsigned short          ma_uint16;
3671     typedef   signed int            ma_int32;
3672     typedef unsigned int            ma_uint32;
3673     #if defined(_MSC_VER) && !defined(__clang__)
3674         typedef   signed __int64    ma_int64;
3675         typedef unsigned __int64    ma_uint64;
3676     #else
3677         #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
3678             #pragma GCC diagnostic push
3679             #pragma GCC diagnostic ignored "-Wlong-long"
3680             #if defined(__clang__)
3681                 #pragma GCC diagnostic ignored "-Wc++11-long-long"
3682             #endif
3683         #endif
3684         typedef   signed long long  ma_int64;
3685         typedef unsigned long long  ma_uint64;
3686         #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
3687             #pragma GCC diagnostic pop
3688         #endif
3689     #endif
3690 #endif  /* MA_USE_STDINT */
3691
3692 #if MA_SIZEOF_PTR == 8
3693     typedef ma_uint64           ma_uintptr;
3694 #else
3695     typedef ma_uint32           ma_uintptr;
3696 #endif
3697
3698 typedef ma_uint8    ma_bool8;
3699 typedef ma_uint32   ma_bool32;
3700 #define MA_TRUE     1
3701 #define MA_FALSE    0
3702
3703 typedef void* ma_handle;
3704 typedef void* ma_ptr;
3705 typedef void (* ma_proc)(void);
3706
3707 #if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED)
3708 typedef ma_uint16 wchar_t;
3709 #endif
3710
3711 /* Define NULL for some compilers. */
3712 #ifndef NULL
3713 #define NULL 0
3714 #endif
3715
3716 #if defined(SIZE_MAX)
3717     #define MA_SIZE_MAX    SIZE_MAX
3718 #else
3719     #define MA_SIZE_MAX    0xFFFFFFFF  /* When SIZE_MAX is not defined by the standard library just default to the maximum 32-bit unsigned integer. */
3720 #endif
3721
3722
3723 /* Platform/backend detection. */
3724 #ifdef _WIN32
3725     #define MA_WIN32
3726     #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
3727         #define MA_WIN32_UWP
3728     #else
3729         #define MA_WIN32_DESKTOP
3730     #endif
3731 #else
3732     #define MA_POSIX
3733
3734     /*
3735     Use the MA_NO_PTHREAD_IN_HEADER option at your own risk. This is intentionally undocumented.
3736     You can use this to avoid including pthread.h in the header section. The downside is that it
3737     results in some fixed sized structures being declared for the various types that are used in
3738     miniaudio. The risk here is that these types might be too small for a given platform. This
3739     risk is yours to take and no support will be offered if you enable this option.
3740     */
3741     #ifndef MA_NO_PTHREAD_IN_HEADER
3742         #include <pthread.h>    /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */
3743         typedef pthread_t       ma_pthread_t;
3744         typedef pthread_mutex_t ma_pthread_mutex_t;
3745         typedef pthread_cond_t  ma_pthread_cond_t;
3746     #else
3747         typedef ma_uintptr      ma_pthread_t;
3748         typedef union           ma_pthread_mutex_t { char __data[40]; ma_uint64 __alignment; } ma_pthread_mutex_t;
3749         typedef union           ma_pthread_cond_t  { char __data[48]; ma_uint64 __alignment; } ma_pthread_cond_t;
3750     #endif
3751
3752     #ifdef __unix__
3753         #define MA_UNIX
3754         #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
3755             #define MA_BSD
3756         #endif
3757     #endif
3758     #ifdef __linux__
3759         #define MA_LINUX
3760     #endif
3761     #ifdef __APPLE__
3762         #define MA_APPLE
3763     #endif
3764     #ifdef __ANDROID__
3765         #define MA_ANDROID
3766     #endif
3767     #ifdef __EMSCRIPTEN__
3768         #define MA_EMSCRIPTEN
3769     #endif
3770 #endif
3771
3772
3773 #ifdef _MSC_VER
3774     #define MA_INLINE __forceinline
3775 #elif defined(__GNUC__)
3776     /*
3777     I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
3778     the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
3779     case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
3780     command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
3781     I am using "__inline__" only when we're compiling in strict ANSI mode.
3782     */
3783     #if defined(__STRICT_ANSI__)
3784         #define MA_INLINE __inline__ __attribute__((always_inline))
3785     #else
3786         #define MA_INLINE inline __attribute__((always_inline))
3787     #endif
3788 #elif defined(__WATCOMC__)
3789     #define MA_INLINE __inline
3790 #else
3791     #define MA_INLINE
3792 #endif
3793
3794 #if !defined(MA_API)
3795     #if defined(MA_DLL)
3796         #if defined(_WIN32)
3797             #define MA_DLL_IMPORT  __declspec(dllimport)
3798             #define MA_DLL_EXPORT  __declspec(dllexport)
3799             #define MA_DLL_PRIVATE static
3800         #else
3801             #if defined(__GNUC__) && __GNUC__ >= 4
3802                 #define MA_DLL_IMPORT  __attribute__((visibility("default")))
3803                 #define MA_DLL_EXPORT  __attribute__((visibility("default")))
3804                 #define MA_DLL_PRIVATE __attribute__((visibility("hidden")))
3805             #else
3806                 #define MA_DLL_IMPORT
3807                 #define MA_DLL_EXPORT
3808                 #define MA_DLL_PRIVATE static
3809             #endif
3810         #endif
3811
3812         #if defined(MINIAUDIO_IMPLEMENTATION) || defined(MA_IMPLEMENTATION)
3813             #define MA_API  MA_DLL_EXPORT
3814         #else
3815             #define MA_API  MA_DLL_IMPORT
3816         #endif
3817         #define MA_PRIVATE MA_DLL_PRIVATE
3818     #else
3819         #define MA_API extern
3820         #define MA_PRIVATE static
3821     #endif
3822 #endif
3823
3824 /* SIMD alignment in bytes. Currently set to 32 bytes in preparation for future AVX optimizations. */
3825 #define MA_SIMD_ALIGNMENT  32
3826
3827
3828 /*
3829 Logging Levels
3830 ==============
3831 Log levels are only used to give logging callbacks some context as to the severity of a log message
3832 so they can do filtering. All log levels will be posted to registered logging callbacks, except for
3833 MA_LOG_LEVEL_DEBUG which will only get processed if MA_DEBUG_OUTPUT is enabled.
3834
3835 MA_LOG_LEVEL_DEBUG
3836     Used for debugging. These log messages are only posted when `MA_DEBUG_OUTPUT` is enabled.
3837
3838 MA_LOG_LEVEL_INFO
3839     Informational logging. Useful for debugging. This will also enable warning and error logs. This
3840     will never be called from within the data callback.
3841
3842 MA_LOG_LEVEL_WARNING
3843     Warnings. You should enable this in you development builds and action them when encounted. This
3844     will also enable error logs. These logs usually indicate a potential problem or
3845     misconfiguration, but still allow you to keep running. This will never be called from within
3846     the data callback.
3847
3848 MA_LOG_LEVEL_ERROR
3849     Error logging. This will be fired when an operation fails and is subsequently aborted. This can
3850     be fired from within the data callback, in which case the device will be stopped. You should
3851     always have this log level enabled.
3852 */
3853 #define MA_LOG_LEVEL_DEBUG      4
3854 #define MA_LOG_LEVEL_INFO       3
3855 #define MA_LOG_LEVEL_WARNING    2
3856 #define MA_LOG_LEVEL_ERROR      1
3857
3858 /*
3859 Variables needing to be accessed atomically should be declared with this macro for two reasons:
3860
3861     1) It allows people who read the code to identify a variable as such; and
3862     2) It forces alignment on platforms where it's required or optimal.
3863
3864 Note that for x86/64, alignment is not strictly necessary, but does have some performance
3865 implications. Where supported by the compiler, alignment will be used, but otherwise if the CPU
3866 architecture does not require it, it will simply leave it unaligned. This is the case with old
3867 versions of Visual Studio, which I've confirmed with at least VC6.
3868 */
3869 #if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
3870     #include <stdalign.h>
3871     #define MA_ATOMIC(alignment, type)            alignas(alignment) type
3872 #else
3873     #if defined(__GNUC__)
3874         /* GCC-style compilers. */
3875         #define MA_ATOMIC(alignment, type)        type __attribute__((aligned(alignment)))
3876     #elif defined(_MSC_VER) && _MSC_VER > 1200  /* 1200 = VC6. Alignment not supported, but not necessary because x86 is the only supported target. */
3877         /* MSVC. */
3878         #define MA_ATOMIC(alignment, type)        __declspec(align(alignment)) type
3879     #else
3880         /* Other compilers. */
3881         #define MA_ATOMIC(alignment, type)        type
3882     #endif
3883 #endif
3884
3885 typedef struct ma_context ma_context;
3886 typedef struct ma_device ma_device;
3887
3888 typedef ma_uint8 ma_channel;
3889 typedef enum
3890 {
3891     MA_CHANNEL_NONE               = 0,
3892     MA_CHANNEL_MONO               = 1,
3893     MA_CHANNEL_FRONT_LEFT         = 2,
3894     MA_CHANNEL_FRONT_RIGHT        = 3,
3895     MA_CHANNEL_FRONT_CENTER       = 4,
3896     MA_CHANNEL_LFE                = 5,
3897     MA_CHANNEL_BACK_LEFT          = 6,
3898     MA_CHANNEL_BACK_RIGHT         = 7,
3899     MA_CHANNEL_FRONT_LEFT_CENTER  = 8,
3900     MA_CHANNEL_FRONT_RIGHT_CENTER = 9,
3901     MA_CHANNEL_BACK_CENTER        = 10,
3902     MA_CHANNEL_SIDE_LEFT          = 11,
3903     MA_CHANNEL_SIDE_RIGHT         = 12,
3904     MA_CHANNEL_TOP_CENTER         = 13,
3905     MA_CHANNEL_TOP_FRONT_LEFT     = 14,
3906     MA_CHANNEL_TOP_FRONT_CENTER   = 15,
3907     MA_CHANNEL_TOP_FRONT_RIGHT    = 16,
3908     MA_CHANNEL_TOP_BACK_LEFT      = 17,
3909     MA_CHANNEL_TOP_BACK_CENTER    = 18,
3910     MA_CHANNEL_TOP_BACK_RIGHT     = 19,
3911     MA_CHANNEL_AUX_0              = 20,
3912     MA_CHANNEL_AUX_1              = 21,
3913     MA_CHANNEL_AUX_2              = 22,
3914     MA_CHANNEL_AUX_3              = 23,
3915     MA_CHANNEL_AUX_4              = 24,
3916     MA_CHANNEL_AUX_5              = 25,
3917     MA_CHANNEL_AUX_6              = 26,
3918     MA_CHANNEL_AUX_7              = 27,
3919     MA_CHANNEL_AUX_8              = 28,
3920     MA_CHANNEL_AUX_9              = 29,
3921     MA_CHANNEL_AUX_10             = 30,
3922     MA_CHANNEL_AUX_11             = 31,
3923     MA_CHANNEL_AUX_12             = 32,
3924     MA_CHANNEL_AUX_13             = 33,
3925     MA_CHANNEL_AUX_14             = 34,
3926     MA_CHANNEL_AUX_15             = 35,
3927     MA_CHANNEL_AUX_16             = 36,
3928     MA_CHANNEL_AUX_17             = 37,
3929     MA_CHANNEL_AUX_18             = 38,
3930     MA_CHANNEL_AUX_19             = 39,
3931     MA_CHANNEL_AUX_20             = 40,
3932     MA_CHANNEL_AUX_21             = 41,
3933     MA_CHANNEL_AUX_22             = 42,
3934     MA_CHANNEL_AUX_23             = 43,
3935     MA_CHANNEL_AUX_24             = 44,
3936     MA_CHANNEL_AUX_25             = 45,
3937     MA_CHANNEL_AUX_26             = 46,
3938     MA_CHANNEL_AUX_27             = 47,
3939     MA_CHANNEL_AUX_28             = 48,
3940     MA_CHANNEL_AUX_29             = 49,
3941     MA_CHANNEL_AUX_30             = 50,
3942     MA_CHANNEL_AUX_31             = 51,
3943     MA_CHANNEL_LEFT               = MA_CHANNEL_FRONT_LEFT,
3944     MA_CHANNEL_RIGHT              = MA_CHANNEL_FRONT_RIGHT,
3945     MA_CHANNEL_POSITION_COUNT     = (MA_CHANNEL_AUX_31 + 1)
3946 } _ma_channel_position; /* Do not use `_ma_channel_position` directly. Use `ma_channel` instead. */
3947
3948 typedef enum
3949 {
3950     MA_SUCCESS                        =  0,
3951     MA_ERROR                          = -1,  /* A generic error. */
3952     MA_INVALID_ARGS                   = -2,
3953     MA_INVALID_OPERATION              = -3,
3954     MA_OUT_OF_MEMORY                  = -4,
3955     MA_OUT_OF_RANGE                   = -5,
3956     MA_ACCESS_DENIED                  = -6,
3957     MA_DOES_NOT_EXIST                 = -7,
3958     MA_ALREADY_EXISTS                 = -8,
3959     MA_TOO_MANY_OPEN_FILES            = -9,
3960     MA_INVALID_FILE                   = -10,
3961     MA_TOO_BIG                        = -11,
3962     MA_PATH_TOO_LONG                  = -12,
3963     MA_NAME_TOO_LONG                  = -13,
3964     MA_NOT_DIRECTORY                  = -14,
3965     MA_IS_DIRECTORY                   = -15,
3966     MA_DIRECTORY_NOT_EMPTY            = -16,
3967     MA_AT_END                         = -17,
3968     MA_NO_SPACE                       = -18,
3969     MA_BUSY                           = -19,
3970     MA_IO_ERROR                       = -20,
3971     MA_INTERRUPT                      = -21,
3972     MA_UNAVAILABLE                    = -22,
3973     MA_ALREADY_IN_USE                 = -23,
3974     MA_BAD_ADDRESS                    = -24,
3975     MA_BAD_SEEK                       = -25,
3976     MA_BAD_PIPE                       = -26,
3977     MA_DEADLOCK                       = -27,
3978     MA_TOO_MANY_LINKS                 = -28,
3979     MA_NOT_IMPLEMENTED                = -29,
3980     MA_NO_MESSAGE                     = -30,
3981     MA_BAD_MESSAGE                    = -31,
3982     MA_NO_DATA_AVAILABLE              = -32,
3983     MA_INVALID_DATA                   = -33,
3984     MA_TIMEOUT                        = -34,
3985     MA_NO_NETWORK                     = -35,
3986     MA_NOT_UNIQUE                     = -36,
3987     MA_NOT_SOCKET                     = -37,
3988     MA_NO_ADDRESS                     = -38,
3989     MA_BAD_PROTOCOL                   = -39,
3990     MA_PROTOCOL_UNAVAILABLE           = -40,
3991     MA_PROTOCOL_NOT_SUPPORTED         = -41,
3992     MA_PROTOCOL_FAMILY_NOT_SUPPORTED  = -42,
3993     MA_ADDRESS_FAMILY_NOT_SUPPORTED   = -43,
3994     MA_SOCKET_NOT_SUPPORTED           = -44,
3995     MA_CONNECTION_RESET               = -45,
3996     MA_ALREADY_CONNECTED              = -46,
3997     MA_NOT_CONNECTED                  = -47,
3998     MA_CONNECTION_REFUSED             = -48,
3999     MA_NO_HOST                        = -49,
4000     MA_IN_PROGRESS                    = -50,
4001     MA_CANCELLED                      = -51,
4002     MA_MEMORY_ALREADY_MAPPED          = -52,
4003
4004     /* General miniaudio-specific errors. */
4005     MA_FORMAT_NOT_SUPPORTED           = -100,
4006     MA_DEVICE_TYPE_NOT_SUPPORTED      = -101,
4007     MA_SHARE_MODE_NOT_SUPPORTED       = -102,
4008     MA_NO_BACKEND                     = -103,
4009     MA_NO_DEVICE                      = -104,
4010     MA_API_NOT_FOUND                  = -105,
4011     MA_INVALID_DEVICE_CONFIG          = -106,
4012     MA_LOOP                           = -107,
4013
4014     /* State errors. */
4015     MA_DEVICE_NOT_INITIALIZED         = -200,
4016     MA_DEVICE_ALREADY_INITIALIZED     = -201,
4017     MA_DEVICE_NOT_STARTED             = -202,
4018     MA_DEVICE_NOT_STOPPED             = -203,
4019
4020     /* Operation errors. */
4021     MA_FAILED_TO_INIT_BACKEND         = -300,
4022     MA_FAILED_TO_OPEN_BACKEND_DEVICE  = -301,
4023     MA_FAILED_TO_START_BACKEND_DEVICE = -302,
4024     MA_FAILED_TO_STOP_BACKEND_DEVICE  = -303
4025 } ma_result;
4026
4027
4028 #define MA_MIN_CHANNELS                 1
4029 #ifndef MA_MAX_CHANNELS                 
4030 #define MA_MAX_CHANNELS                 254
4031 #endif
4032
4033 #ifndef MA_MAX_FILTER_ORDER
4034 #define MA_MAX_FILTER_ORDER             8
4035 #endif
4036
4037 typedef enum
4038 {
4039     ma_stream_format_pcm = 0
4040 } ma_stream_format;
4041
4042 typedef enum
4043 {
4044     ma_stream_layout_interleaved = 0,
4045     ma_stream_layout_deinterleaved
4046 } ma_stream_layout;
4047
4048 typedef enum
4049 {
4050     ma_dither_mode_none = 0,
4051     ma_dither_mode_rectangle,
4052     ma_dither_mode_triangle
4053 } ma_dither_mode;
4054
4055 typedef enum
4056 {
4057     /*
4058     I like to keep these explicitly defined because they're used as a key into a lookup table. When items are
4059     added to this, make sure there are no gaps and that they're added to the lookup table in ma_get_bytes_per_sample().
4060     */
4061     ma_format_unknown = 0,     /* Mainly used for indicating an error, but also used as the default for the output format for decoders. */
4062     ma_format_u8      = 1,
4063     ma_format_s16     = 2,     /* Seems to be the most widely supported format. */
4064     ma_format_s24     = 3,     /* Tightly packed. 3 bytes per sample. */
4065     ma_format_s32     = 4,
4066     ma_format_f32     = 5,
4067     ma_format_count
4068 } ma_format;
4069
4070 typedef enum
4071 {
4072     /* Standard rates need to be in priority order. */
4073     ma_standard_sample_rate_48000  = 48000,     /* Most common */
4074     ma_standard_sample_rate_44100  = 44100,
4075
4076     ma_standard_sample_rate_32000  = 32000,     /* Lows */
4077     ma_standard_sample_rate_24000  = 24000,
4078     ma_standard_sample_rate_22050  = 22050,
4079
4080     ma_standard_sample_rate_88200  = 88200,     /* Highs */
4081     ma_standard_sample_rate_96000  = 96000,
4082     ma_standard_sample_rate_176400 = 176400,
4083     ma_standard_sample_rate_192000 = 192000,
4084
4085     ma_standard_sample_rate_16000  = 16000,     /* Extreme lows */
4086     ma_standard_sample_rate_11025  = 11250,
4087     ma_standard_sample_rate_8000   = 8000,
4088
4089     ma_standard_sample_rate_352800 = 352800,    /* Extreme highs */
4090     ma_standard_sample_rate_384000 = 384000,
4091
4092     ma_standard_sample_rate_min    = ma_standard_sample_rate_8000,
4093     ma_standard_sample_rate_max    = ma_standard_sample_rate_384000,
4094     ma_standard_sample_rate_count  = 14         /* Need to maintain the count manually. Make sure this is updated if items are added to enum. */
4095 } ma_standard_sample_rate;
4096
4097
4098 typedef enum
4099 {
4100     ma_channel_mix_mode_rectangular = 0,   /* Simple averaging based on the plane(s) the channel is sitting on. */
4101     ma_channel_mix_mode_simple,            /* Drop excess channels; zeroed out extra channels. */
4102     ma_channel_mix_mode_custom_weights,    /* Use custom weights specified in ma_channel_router_config. */
4103     ma_channel_mix_mode_default = ma_channel_mix_mode_rectangular
4104 } ma_channel_mix_mode;
4105
4106 typedef enum
4107 {
4108     ma_standard_channel_map_microsoft,
4109     ma_standard_channel_map_alsa,
4110     ma_standard_channel_map_rfc3551,   /* Based off AIFF. */
4111     ma_standard_channel_map_flac,
4112     ma_standard_channel_map_vorbis,
4113     ma_standard_channel_map_sound4,    /* FreeBSD's sound(4). */
4114     ma_standard_channel_map_sndio,     /* www.sndio.org/tips.html */
4115     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. */
4116     ma_standard_channel_map_default = ma_standard_channel_map_microsoft
4117 } ma_standard_channel_map;
4118
4119 typedef enum
4120 {
4121     ma_performance_profile_low_latency = 0,
4122     ma_performance_profile_conservative
4123 } ma_performance_profile;
4124
4125
4126 typedef struct
4127 {
4128     void* pUserData;
4129     void* (* onMalloc)(size_t sz, void* pUserData);
4130     void* (* onRealloc)(void* p, size_t sz, void* pUserData);
4131     void  (* onFree)(void* p, void* pUserData);
4132 } ma_allocation_callbacks;
4133
4134 typedef struct
4135 {
4136     ma_int32 state;
4137 } ma_lcg;
4138
4139
4140 /* Spinlocks are 32-bit for compatibility reasons. */
4141 typedef ma_uint32 ma_spinlock;
4142
4143 #ifndef MA_NO_THREADING
4144 /* Thread priorities should be ordered such that the default priority of the worker thread is 0. */
4145 typedef enum
4146 {
4147     ma_thread_priority_idle     = -5,
4148     ma_thread_priority_lowest   = -4,
4149     ma_thread_priority_low      = -3,
4150     ma_thread_priority_normal   = -2,
4151     ma_thread_priority_high     = -1,
4152     ma_thread_priority_highest  =  0,
4153     ma_thread_priority_realtime =  1,
4154     ma_thread_priority_default  =  0
4155 } ma_thread_priority;
4156
4157 #if defined(MA_WIN32)
4158 typedef ma_handle ma_thread;
4159 #endif
4160 #if defined(MA_POSIX)
4161 typedef ma_pthread_t ma_thread;
4162 #endif
4163
4164 #if defined(MA_WIN32)
4165 typedef ma_handle ma_mutex;
4166 #endif
4167 #if defined(MA_POSIX)
4168 typedef ma_pthread_mutex_t ma_mutex;
4169 #endif
4170
4171 #if defined(MA_WIN32)
4172 typedef ma_handle ma_event;
4173 #endif
4174 #if defined(MA_POSIX)
4175 typedef struct
4176 {
4177     ma_uint32 value;
4178     ma_pthread_mutex_t lock;
4179     ma_pthread_cond_t cond;
4180 } ma_event;
4181 #endif  /* MA_POSIX */
4182
4183 #if defined(MA_WIN32)
4184 typedef ma_handle ma_semaphore;
4185 #endif
4186 #if defined(MA_POSIX)
4187 typedef struct
4188 {
4189     int value;
4190     ma_pthread_mutex_t lock;
4191     ma_pthread_cond_t cond;
4192 } ma_semaphore;
4193 #endif  /* MA_POSIX */
4194 #else
4195 /* MA_NO_THREADING is set which means threading is disabled. Threading is required by some API families. If any of these are enabled we need to throw an error. */
4196 #ifndef MA_NO_DEVICE_IO
4197 #error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
4198 #endif
4199 #endif  /* MA_NO_THREADING */
4200
4201
4202 /*
4203 Retrieves the version of miniaudio as separated integers. Each component can be NULL if it's not required.
4204 */
4205 MA_API void ma_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision);
4206
4207 /*
4208 Retrieves the version of miniaudio as a string which can be useful for logging purposes.
4209 */
4210 MA_API const char* ma_version_string(void);
4211
4212
4213 /**************************************************************************************************************************************************************
4214
4215 Logging
4216
4217 **************************************************************************************************************************************************************/
4218 #include <stdarg.h> /* For va_list. */
4219
4220 #if defined(__has_attribute)
4221     #if __has_attribute(format)
4222         #define MA_ATTRIBUTE_FORMAT(fmt, va) __attribute__((format(printf, fmt, va)))
4223     #endif
4224 #endif
4225 #ifndef MA_ATTRIBUTE_FORMAT
4226 #define MA_ATTRIBUTE_FORMAT(fmt,va)
4227 #endif
4228
4229 #ifndef MA_MAX_LOG_CALLBACKS
4230 #define MA_MAX_LOG_CALLBACKS    4
4231 #endif
4232
4233
4234 /*
4235 The callback for handling log messages.
4236
4237
4238 Parameters
4239 ----------
4240 pUserData (in)
4241     The user data pointer that was passed into ma_log_register_callback().
4242
4243 logLevel (in)
4244     The log level. This can be one of the following:
4245
4246     +----------------------+
4247     | Log Level            |
4248     +----------------------+
4249     | MA_LOG_LEVEL_DEBUG   |
4250     | MA_LOG_LEVEL_INFO    |
4251     | MA_LOG_LEVEL_WARNING |
4252     | MA_LOG_LEVEL_ERROR   |
4253     +----------------------+
4254
4255 pMessage (in)
4256     The log message.
4257
4258
4259 Remarks
4260 -------
4261 Do not modify the state of the device from inside the callback.
4262 */
4263 typedef void (* ma_log_callback_proc)(void* pUserData, ma_uint32 level, const char* pMessage);
4264
4265 typedef struct
4266 {
4267     ma_log_callback_proc onLog;
4268     void* pUserData;
4269 } ma_log_callback;
4270
4271 MA_API ma_log_callback ma_log_callback_init(ma_log_callback_proc onLog, void* pUserData);
4272
4273
4274 typedef struct
4275 {
4276     ma_log_callback callbacks[MA_MAX_LOG_CALLBACKS];
4277     ma_uint32 callbackCount;
4278     ma_allocation_callbacks allocationCallbacks;    /* Need to store these persistently because ma_log_postv() might need to allocate a buffer on the heap. */
4279 #ifndef MA_NO_THREADING
4280     ma_mutex lock;  /* For thread safety just to make it easier and safer for the logging implementation. */
4281 #endif
4282 } ma_log;
4283
4284 MA_API ma_result ma_log_init(const ma_allocation_callbacks* pAllocationCallbacks, ma_log* pLog);
4285 MA_API void ma_log_uninit(ma_log* pLog);
4286 MA_API ma_result ma_log_register_callback(ma_log* pLog, ma_log_callback callback);
4287 MA_API ma_result ma_log_unregister_callback(ma_log* pLog, ma_log_callback callback);
4288 MA_API ma_result ma_log_post(ma_log* pLog, ma_uint32 level, const char* pMessage);
4289 MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat, va_list args);
4290 MA_API ma_result ma_log_postf(ma_log* pLog, ma_uint32 level, const char* pFormat, ...) MA_ATTRIBUTE_FORMAT(3, 4);
4291
4292
4293 /**************************************************************************************************************************************************************
4294
4295 Biquad Filtering
4296
4297 **************************************************************************************************************************************************************/
4298 typedef union
4299 {
4300     float    f32;
4301     ma_int32 s32;
4302 } ma_biquad_coefficient;
4303
4304 typedef struct
4305 {
4306     ma_format format;
4307     ma_uint32 channels;
4308     double b0;
4309     double b1;
4310     double b2;
4311     double a0;
4312     double a1;
4313     double a2;
4314 } ma_biquad_config;
4315
4316 MA_API 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);
4317
4318 typedef struct
4319 {
4320     ma_format format;
4321     ma_uint32 channels;
4322     ma_biquad_coefficient b0;
4323     ma_biquad_coefficient b1;
4324     ma_biquad_coefficient b2;
4325     ma_biquad_coefficient a1;
4326     ma_biquad_coefficient a2;
4327     ma_biquad_coefficient* pR1;
4328     ma_biquad_coefficient* pR2;
4329
4330     /* Memory management. */
4331     void* _pHeap;
4332     ma_bool32 _ownsHeap;
4333 } ma_biquad;
4334
4335 MA_API ma_result ma_biquad_get_heap_size(const ma_biquad_config* pConfig, size_t* pHeapSizeInBytes);
4336 MA_API ma_result ma_biquad_init_preallocated(const ma_biquad_config* pConfig, void* pHeap, ma_biquad* pBQ);
4337 MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad* pBQ);
4338 MA_API void ma_biquad_uninit(ma_biquad* pBQ, const ma_allocation_callbacks* pAllocationCallbacks);
4339 MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pBQ);
4340 MA_API ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4341 MA_API ma_uint32 ma_biquad_get_latency(const ma_biquad* pBQ);
4342
4343
4344 /**************************************************************************************************************************************************************
4345
4346 Low-Pass Filtering
4347
4348 **************************************************************************************************************************************************************/
4349 typedef struct
4350 {
4351     ma_format format;
4352     ma_uint32 channels;
4353     ma_uint32 sampleRate;
4354     double cutoffFrequency;
4355     double q;
4356 } ma_lpf1_config, ma_lpf2_config;
4357
4358 MA_API ma_lpf1_config ma_lpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency);
4359 MA_API ma_lpf2_config ma_lpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q);
4360
4361 typedef struct
4362 {
4363     ma_format format;
4364     ma_uint32 channels;
4365     ma_biquad_coefficient a;
4366     ma_biquad_coefficient* pR1;
4367
4368     /* Memory management. */
4369     void* _pHeap;
4370     ma_bool32 _ownsHeap;
4371 } ma_lpf1;
4372
4373 MA_API ma_result ma_lpf1_get_heap_size(const ma_lpf1_config* pConfig, size_t* pHeapSizeInBytes);
4374 MA_API ma_result ma_lpf1_init_preallocated(const ma_lpf1_config* pConfig, void* pHeap, ma_lpf1* pLPF);
4375 MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf1* pLPF);
4376 MA_API void ma_lpf1_uninit(ma_lpf1* pLPF, const ma_allocation_callbacks* pAllocationCallbacks);
4377 MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF);
4378 MA_API ma_result ma_lpf1_process_pcm_frames(ma_lpf1* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4379 MA_API ma_uint32 ma_lpf1_get_latency(const ma_lpf1* pLPF);
4380
4381 typedef struct
4382 {
4383     ma_biquad bq;   /* The second order low-pass filter is implemented as a biquad filter. */
4384 } ma_lpf2;
4385
4386 MA_API ma_result ma_lpf2_get_heap_size(const ma_lpf2_config* pConfig, size_t* pHeapSizeInBytes);
4387 MA_API ma_result ma_lpf2_init_preallocated(const ma_lpf2_config* pConfig, void* pHeap, ma_lpf2* pHPF);
4388 MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf2* pLPF);
4389 MA_API void ma_lpf2_uninit(ma_lpf2* pLPF, const ma_allocation_callbacks* pAllocationCallbacks);
4390 MA_API ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF);
4391 MA_API ma_result ma_lpf2_process_pcm_frames(ma_lpf2* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4392 MA_API ma_uint32 ma_lpf2_get_latency(const ma_lpf2* pLPF);
4393
4394
4395 typedef struct
4396 {
4397     ma_format format;
4398     ma_uint32 channels;
4399     ma_uint32 sampleRate;
4400     double cutoffFrequency;
4401     ma_uint32 order;    /* If set to 0, will be treated as a passthrough (no filtering will be applied). */
4402 } ma_lpf_config;
4403
4404 MA_API ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order);
4405
4406 typedef struct
4407 {
4408     ma_format format;
4409     ma_uint32 channels;
4410     ma_uint32 sampleRate;
4411     ma_uint32 lpf1Count;
4412     ma_uint32 lpf2Count;
4413     ma_lpf1* pLPF1;
4414     ma_lpf2* pLPF2;
4415
4416     /* Memory management. */
4417     void* _pHeap;
4418     ma_bool32 _ownsHeap;
4419 } ma_lpf;
4420
4421 MA_API ma_result ma_lpf_get_heap_size(const ma_lpf_config* pConfig, size_t* pHeapSizeInBytes);
4422 MA_API ma_result ma_lpf_init_preallocated(const ma_lpf_config* pConfig, void* pHeap, ma_lpf* pLPF);
4423 MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf* pLPF);
4424 MA_API void ma_lpf_uninit(ma_lpf* pLPF, const ma_allocation_callbacks* pAllocationCallbacks);
4425 MA_API ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF);
4426 MA_API ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4427 MA_API ma_uint32 ma_lpf_get_latency(const ma_lpf* pLPF);
4428
4429
4430 /**************************************************************************************************************************************************************
4431
4432 High-Pass Filtering
4433
4434 **************************************************************************************************************************************************************/
4435 typedef struct
4436 {
4437     ma_format format;
4438     ma_uint32 channels;
4439     ma_uint32 sampleRate;
4440     double cutoffFrequency;
4441     double q;
4442 } ma_hpf1_config, ma_hpf2_config;
4443
4444 MA_API ma_hpf1_config ma_hpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency);
4445 MA_API ma_hpf2_config ma_hpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q);
4446
4447 typedef struct
4448 {
4449     ma_format format;
4450     ma_uint32 channels;
4451     ma_biquad_coefficient a;
4452     ma_biquad_coefficient* pR1;
4453
4454     /* Memory management. */
4455     void* _pHeap;
4456     ma_bool32 _ownsHeap;
4457 } ma_hpf1;
4458
4459 MA_API ma_result ma_hpf1_get_heap_size(const ma_hpf1_config* pConfig, size_t* pHeapSizeInBytes);
4460 MA_API ma_result ma_hpf1_init_preallocated(const ma_hpf1_config* pConfig, void* pHeap, ma_hpf1* pLPF);
4461 MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf1* pHPF);
4462 MA_API void ma_hpf1_uninit(ma_hpf1* pHPF, const ma_allocation_callbacks* pAllocationCallbacks);
4463 MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF);
4464 MA_API ma_result ma_hpf1_process_pcm_frames(ma_hpf1* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4465 MA_API ma_uint32 ma_hpf1_get_latency(const ma_hpf1* pHPF);
4466
4467 typedef struct
4468 {
4469     ma_biquad bq;   /* The second order high-pass filter is implemented as a biquad filter. */
4470 } ma_hpf2;
4471
4472 MA_API ma_result ma_hpf2_get_heap_size(const ma_hpf2_config* pConfig, size_t* pHeapSizeInBytes);
4473 MA_API ma_result ma_hpf2_init_preallocated(const ma_hpf2_config* pConfig, void* pHeap, ma_hpf2* pHPF);
4474 MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf2* pHPF);
4475 MA_API void ma_hpf2_uninit(ma_hpf2* pHPF, const ma_allocation_callbacks* pAllocationCallbacks);
4476 MA_API ma_result ma_hpf2_reinit(const ma_hpf2_config* pConfig, ma_hpf2* pHPF);
4477 MA_API ma_result ma_hpf2_process_pcm_frames(ma_hpf2* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4478 MA_API ma_uint32 ma_hpf2_get_latency(const ma_hpf2* pHPF);
4479
4480
4481 typedef struct
4482 {
4483     ma_format format;
4484     ma_uint32 channels;
4485     ma_uint32 sampleRate;
4486     double cutoffFrequency;
4487     ma_uint32 order;    /* If set to 0, will be treated as a passthrough (no filtering will be applied). */
4488 } ma_hpf_config;
4489
4490 MA_API ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order);
4491
4492 typedef struct
4493 {
4494     ma_format format;
4495     ma_uint32 channels;
4496     ma_uint32 sampleRate;
4497     ma_uint32 hpf1Count;
4498     ma_uint32 hpf2Count;
4499     ma_hpf1* pHPF1;
4500     ma_hpf2* pHPF2;
4501
4502     /* Memory management. */
4503     void* _pHeap;
4504     ma_bool32 _ownsHeap;
4505 } ma_hpf;
4506
4507 MA_API ma_result ma_hpf_get_heap_size(const ma_hpf_config* pConfig, size_t* pHeapSizeInBytes);
4508 MA_API ma_result ma_hpf_init_preallocated(const ma_hpf_config* pConfig, void* pHeap, ma_hpf* pLPF);
4509 MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf* pHPF);
4510 MA_API void ma_hpf_uninit(ma_hpf* pHPF, const ma_allocation_callbacks* pAllocationCallbacks);
4511 MA_API ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF);
4512 MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4513 MA_API ma_uint32 ma_hpf_get_latency(const ma_hpf* pHPF);
4514
4515
4516 /**************************************************************************************************************************************************************
4517
4518 Band-Pass Filtering
4519
4520 **************************************************************************************************************************************************************/
4521 typedef struct
4522 {
4523     ma_format format;
4524     ma_uint32 channels;
4525     ma_uint32 sampleRate;
4526     double cutoffFrequency;
4527     double q;
4528 } ma_bpf2_config;
4529
4530 MA_API ma_bpf2_config ma_bpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q);
4531
4532 typedef struct
4533 {
4534     ma_biquad bq;   /* The second order band-pass filter is implemented as a biquad filter. */
4535 } ma_bpf2;
4536
4537 MA_API ma_result ma_bpf2_get_heap_size(const ma_bpf2_config* pConfig, size_t* pHeapSizeInBytes);
4538 MA_API ma_result ma_bpf2_init_preallocated(const ma_bpf2_config* pConfig, void* pHeap, ma_bpf2* pBPF);
4539 MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf2* pBPF);
4540 MA_API void ma_bpf2_uninit(ma_bpf2* pBPF, const ma_allocation_callbacks* pAllocationCallbacks);
4541 MA_API ma_result ma_bpf2_reinit(const ma_bpf2_config* pConfig, ma_bpf2* pBPF);
4542 MA_API ma_result ma_bpf2_process_pcm_frames(ma_bpf2* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4543 MA_API ma_uint32 ma_bpf2_get_latency(const ma_bpf2* pBPF);
4544
4545
4546 typedef struct
4547 {
4548     ma_format format;
4549     ma_uint32 channels;
4550     ma_uint32 sampleRate;
4551     double cutoffFrequency;
4552     ma_uint32 order;    /* If set to 0, will be treated as a passthrough (no filtering will be applied). */
4553 } ma_bpf_config;
4554
4555 MA_API ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order);
4556
4557 typedef struct
4558 {
4559     ma_format format;
4560     ma_uint32 channels;
4561     ma_uint32 bpf2Count;
4562     ma_bpf2* pBPF2;
4563
4564     /* Memory management. */
4565     void* _pHeap;
4566     ma_bool32 _ownsHeap;
4567 } ma_bpf;
4568
4569 MA_API ma_result ma_bpf_get_heap_size(const ma_bpf_config* pConfig, size_t* pHeapSizeInBytes);
4570 MA_API ma_result ma_bpf_init_preallocated(const ma_bpf_config* pConfig, void* pHeap, ma_bpf* pBPF);
4571 MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf* pBPF);
4572 MA_API void ma_bpf_uninit(ma_bpf* pBPF, const ma_allocation_callbacks* pAllocationCallbacks);
4573 MA_API ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF);
4574 MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4575 MA_API ma_uint32 ma_bpf_get_latency(const ma_bpf* pBPF);
4576
4577
4578 /**************************************************************************************************************************************************************
4579
4580 Notching Filter
4581
4582 **************************************************************************************************************************************************************/
4583 typedef struct
4584 {
4585     ma_format format;
4586     ma_uint32 channels;
4587     ma_uint32 sampleRate;
4588     double q;
4589     double frequency;
4590 } ma_notch2_config, ma_notch_config;
4591
4592 MA_API ma_notch2_config ma_notch2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency);
4593
4594 typedef struct
4595 {
4596     ma_biquad bq;
4597 } ma_notch2;
4598
4599 MA_API ma_result ma_notch2_get_heap_size(const ma_notch2_config* pConfig, size_t* pHeapSizeInBytes);
4600 MA_API ma_result ma_notch2_init_preallocated(const ma_notch2_config* pConfig, void* pHeap, ma_notch2* pFilter);
4601 MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch2* pFilter);
4602 MA_API void ma_notch2_uninit(ma_notch2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks);
4603 MA_API ma_result ma_notch2_reinit(const ma_notch2_config* pConfig, ma_notch2* pFilter);
4604 MA_API ma_result ma_notch2_process_pcm_frames(ma_notch2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4605 MA_API ma_uint32 ma_notch2_get_latency(const ma_notch2* pFilter);
4606
4607
4608 /**************************************************************************************************************************************************************
4609
4610 Peaking EQ Filter
4611
4612 **************************************************************************************************************************************************************/
4613 typedef struct
4614 {
4615     ma_format format;
4616     ma_uint32 channels;
4617     ma_uint32 sampleRate;
4618     double gainDB;
4619     double q;
4620     double frequency;
4621 } ma_peak2_config, ma_peak_config;
4622
4623 MA_API ma_peak2_config ma_peak2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency);
4624
4625 typedef struct
4626 {
4627     ma_biquad bq;
4628 } ma_peak2;
4629
4630 MA_API ma_result ma_peak2_get_heap_size(const ma_peak2_config* pConfig, size_t* pHeapSizeInBytes);
4631 MA_API ma_result ma_peak2_init_preallocated(const ma_peak2_config* pConfig, void* pHeap, ma_peak2* pFilter);
4632 MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak2* pFilter);
4633 MA_API void ma_peak2_uninit(ma_peak2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks);
4634 MA_API ma_result ma_peak2_reinit(const ma_peak2_config* pConfig, ma_peak2* pFilter);
4635 MA_API ma_result ma_peak2_process_pcm_frames(ma_peak2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4636 MA_API ma_uint32 ma_peak2_get_latency(const ma_peak2* pFilter);
4637
4638
4639 /**************************************************************************************************************************************************************
4640
4641 Low Shelf Filter
4642
4643 **************************************************************************************************************************************************************/
4644 typedef struct
4645 {
4646     ma_format format;
4647     ma_uint32 channels;
4648     ma_uint32 sampleRate;
4649     double gainDB;
4650     double shelfSlope;
4651     double frequency;
4652 } ma_loshelf2_config, ma_loshelf_config;
4653
4654 MA_API ma_loshelf2_config ma_loshelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency);
4655
4656 typedef struct
4657 {
4658     ma_biquad bq;
4659 } ma_loshelf2;
4660
4661 MA_API ma_result ma_loshelf2_get_heap_size(const ma_loshelf2_config* pConfig, size_t* pHeapSizeInBytes);
4662 MA_API ma_result ma_loshelf2_init_preallocated(const ma_loshelf2_config* pConfig, void* pHeap, ma_loshelf2* pFilter);
4663 MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf2* pFilter);
4664 MA_API void ma_loshelf2_uninit(ma_loshelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks);
4665 MA_API ma_result ma_loshelf2_reinit(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter);
4666 MA_API ma_result ma_loshelf2_process_pcm_frames(ma_loshelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4667 MA_API ma_uint32 ma_loshelf2_get_latency(const ma_loshelf2* pFilter);
4668
4669
4670 /**************************************************************************************************************************************************************
4671
4672 High Shelf Filter
4673
4674 **************************************************************************************************************************************************************/
4675 typedef struct
4676 {
4677     ma_format format;
4678     ma_uint32 channels;
4679     ma_uint32 sampleRate;
4680     double gainDB;
4681     double shelfSlope;
4682     double frequency;
4683 } ma_hishelf2_config, ma_hishelf_config;
4684
4685 MA_API ma_hishelf2_config ma_hishelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency);
4686
4687 typedef struct
4688 {
4689     ma_biquad bq;
4690 } ma_hishelf2;
4691
4692 MA_API ma_result ma_hishelf2_get_heap_size(const ma_hishelf2_config* pConfig, size_t* pHeapSizeInBytes);
4693 MA_API ma_result ma_hishelf2_init_preallocated(const ma_hishelf2_config* pConfig, void* pHeap, ma_hishelf2* pFilter);
4694 MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf2* pFilter);
4695 MA_API void ma_hishelf2_uninit(ma_hishelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks);
4696 MA_API ma_result ma_hishelf2_reinit(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter);
4697 MA_API ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4698 MA_API ma_uint32 ma_hishelf2_get_latency(const ma_hishelf2* pFilter);
4699
4700
4701
4702 /*
4703 Delay
4704 */
4705 typedef struct
4706 {
4707     ma_uint32 channels;
4708     ma_uint32 sampleRate;
4709     ma_uint32 delayInFrames;
4710     ma_bool32 delayStart;       /* Set to true to delay the start of the output; false otherwise. */
4711     float wet;                  /* 0..1. Default = 1. */
4712     float dry;                  /* 0..1. Default = 1. */
4713     float decay;                /* 0..1. Default = 0 (no feedback). Feedback decay. Use this for echo. */
4714 } ma_delay_config;
4715
4716 MA_API ma_delay_config ma_delay_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay);
4717
4718
4719 typedef struct
4720 {
4721     ma_delay_config config;
4722     ma_uint32 cursor;               /* Feedback is written to this cursor. Always equal or in front of the read cursor. */
4723     ma_uint32 bufferSizeInFrames;   /* The maximum of config.startDelayInFrames and config.feedbackDelayInFrames. */
4724     float* pBuffer;
4725 } ma_delay;
4726
4727 MA_API ma_result ma_delay_init(const ma_delay_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay* pDelay);
4728 MA_API void ma_delay_uninit(ma_delay* pDelay, const ma_allocation_callbacks* pAllocationCallbacks);
4729 MA_API ma_result ma_delay_process_pcm_frames(ma_delay* pDelay, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount);
4730 MA_API void ma_delay_set_wet(ma_delay* pDelay, float value);
4731 MA_API float ma_delay_get_wet(const ma_delay* pDelay);
4732 MA_API void ma_delay_set_dry(ma_delay* pDelay, float value);
4733 MA_API float ma_delay_get_dry(const ma_delay* pDelay);
4734 MA_API void ma_delay_set_decay(ma_delay* pDelay, float value);
4735 MA_API float ma_delay_get_decay(const ma_delay* pDelay);
4736
4737
4738 /* Gainer for smooth volume changes. */
4739 typedef struct
4740 {
4741     ma_uint32 channels;
4742     ma_uint32 smoothTimeInFrames;
4743 } ma_gainer_config;
4744
4745 MA_API ma_gainer_config ma_gainer_config_init(ma_uint32 channels, ma_uint32 smoothTimeInFrames);
4746
4747
4748 typedef struct
4749 {
4750     ma_gainer_config config;
4751     ma_uint32 t;
4752     float* pOldGains;
4753     float* pNewGains;
4754
4755     /* Memory management. */
4756     void* _pHeap;
4757     ma_bool32 _ownsHeap;
4758 } ma_gainer;
4759
4760 MA_API ma_result ma_gainer_get_heap_size(const ma_gainer_config* pConfig, size_t* pHeapSizeInBytes);
4761 MA_API ma_result ma_gainer_init_preallocated(const ma_gainer_config* pConfig, void* pHeap, ma_gainer* pGainer);
4762 MA_API ma_result ma_gainer_init(const ma_gainer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_gainer* pGainer);
4763 MA_API void ma_gainer_uninit(ma_gainer* pGainer, const ma_allocation_callbacks* pAllocationCallbacks);
4764 MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4765 MA_API ma_result ma_gainer_set_gain(ma_gainer* pGainer, float newGain);
4766 MA_API ma_result ma_gainer_set_gains(ma_gainer* pGainer, float* pNewGains);
4767
4768
4769
4770 /* Stereo panner. */
4771 typedef enum
4772 {
4773     ma_pan_mode_balance = 0,    /* Does not blend one side with the other. Technically just a balance. Compatible with other popular audio engines and therefore the default. */
4774     ma_pan_mode_pan             /* A true pan. The sound from one side will "move" to the other side and blend with it. */
4775 } ma_pan_mode;
4776
4777 typedef struct
4778 {
4779     ma_format format;
4780     ma_uint32 channels;
4781     ma_pan_mode mode;
4782     float pan;
4783 } ma_panner_config;
4784
4785 MA_API ma_panner_config ma_panner_config_init(ma_format format, ma_uint32 channels);
4786
4787
4788 typedef struct
4789 {
4790     ma_format format;
4791     ma_uint32 channels;
4792     ma_pan_mode mode;
4793     float pan;  /* -1..1 where 0 is no pan, -1 is left side, +1 is right side. Defaults to 0. */
4794 } ma_panner;
4795
4796 MA_API ma_result ma_panner_init(const ma_panner_config* pConfig, ma_panner* pPanner);
4797 MA_API ma_result ma_panner_process_pcm_frames(ma_panner* pPanner, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4798 MA_API void ma_panner_set_mode(ma_panner* pPanner, ma_pan_mode mode);
4799 MA_API ma_pan_mode ma_panner_get_mode(const ma_panner* pPanner);
4800 MA_API void ma_panner_set_pan(ma_panner* pPanner, float pan);
4801 MA_API float ma_panner_get_pan(const ma_panner* pPanner);
4802
4803
4804
4805 /* Fader. */
4806 typedef struct
4807 {
4808     ma_format format;
4809     ma_uint32 channels;
4810     ma_uint32 sampleRate;
4811 } ma_fader_config;
4812
4813 MA_API ma_fader_config ma_fader_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate);
4814
4815 typedef struct
4816 {
4817     ma_fader_config config;
4818     float volumeBeg;            /* If volumeBeg and volumeEnd is equal to 1, no fading happens (ma_fader_process_pcm_frames() will run as a passthrough). */
4819     float volumeEnd;
4820     ma_uint64 lengthInFrames;   /* The total length of the fade. */
4821     ma_uint64 cursorInFrames;   /* The current time in frames. Incremented by ma_fader_process_pcm_frames(). */
4822 } ma_fader;
4823
4824 MA_API ma_result ma_fader_init(const ma_fader_config* pConfig, ma_fader* pFader);
4825 MA_API ma_result ma_fader_process_pcm_frames(ma_fader* pFader, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4826 MA_API void ma_fader_get_data_format(const ma_fader* pFader, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate);
4827 MA_API void ma_fader_set_fade(ma_fader* pFader, float volumeBeg, float volumeEnd, ma_uint64 lengthInFrames);
4828 MA_API float ma_fader_get_current_volume(ma_fader* pFader);
4829
4830
4831
4832 /* Spatializer. */
4833 typedef struct
4834 {
4835     float x;
4836     float y;
4837     float z;
4838 } ma_vec3f;
4839
4840 typedef enum
4841 {
4842     ma_attenuation_model_none,          /* No distance attenuation and no spatialization. */
4843     ma_attenuation_model_inverse,       /* Equivalent to OpenAL's AL_INVERSE_DISTANCE_CLAMPED. */
4844     ma_attenuation_model_linear,        /* Linear attenuation. Equivalent to OpenAL's AL_LINEAR_DISTANCE_CLAMPED. */
4845     ma_attenuation_model_exponential    /* Exponential attenuation. Equivalent to OpenAL's AL_EXPONENT_DISTANCE_CLAMPED. */
4846 } ma_attenuation_model;
4847
4848 typedef enum
4849 {
4850     ma_positioning_absolute,
4851     ma_positioning_relative
4852 } ma_positioning;
4853
4854 typedef enum
4855 {
4856     ma_handedness_right,
4857     ma_handedness_left
4858 } ma_handedness;
4859
4860
4861 typedef struct
4862 {
4863     ma_uint32 channelsOut;
4864     ma_channel* pChannelMapOut;
4865     ma_handedness handedness;   /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */
4866     float coneInnerAngleInRadians;
4867     float coneOuterAngleInRadians;
4868     float coneOuterGain;
4869     float speedOfSound;
4870     ma_vec3f worldUp;
4871 } ma_spatializer_listener_config;
4872
4873 MA_API ma_spatializer_listener_config ma_spatializer_listener_config_init(ma_uint32 channelsOut);
4874
4875
4876 typedef struct
4877 {
4878     ma_spatializer_listener_config config;
4879     ma_vec3f position;  /* The absolute position of the listener. */
4880     ma_vec3f direction; /* The direction the listener is facing. The world up vector is config.worldUp. */
4881     ma_vec3f velocity;
4882     ma_bool32 isEnabled;
4883
4884     /* Memory management. */
4885     ma_bool32 _ownsHeap;
4886     void* _pHeap;
4887 } ma_spatializer_listener;
4888
4889 MA_API ma_result ma_spatializer_listener_get_heap_size(const ma_spatializer_listener_config* pConfig, size_t* pHeapSizeInBytes);
4890 MA_API ma_result ma_spatializer_listener_init_preallocated(const ma_spatializer_listener_config* pConfig, void* pHeap, ma_spatializer_listener* pListener);
4891 MA_API ma_result ma_spatializer_listener_init(const ma_spatializer_listener_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer_listener* pListener);
4892 MA_API void ma_spatializer_listener_uninit(ma_spatializer_listener* pListener, const ma_allocation_callbacks* pAllocationCallbacks);
4893 MA_API ma_channel* ma_spatializer_listener_get_channel_map(ma_spatializer_listener* pListener);
4894 MA_API void ma_spatializer_listener_set_cone(ma_spatializer_listener* pListener, float innerAngleInRadians, float outerAngleInRadians, float outerGain);
4895 MA_API void ma_spatializer_listener_get_cone(const ma_spatializer_listener* pListener, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain);
4896 MA_API void ma_spatializer_listener_set_position(ma_spatializer_listener* pListener, float x, float y, float z);
4897 MA_API ma_vec3f ma_spatializer_listener_get_position(const ma_spatializer_listener* pListener);
4898 MA_API void ma_spatializer_listener_set_direction(ma_spatializer_listener* pListener, float x, float y, float z);
4899 MA_API ma_vec3f ma_spatializer_listener_get_direction(const ma_spatializer_listener* pListener);
4900 MA_API void ma_spatializer_listener_set_velocity(ma_spatializer_listener* pListener, float x, float y, float z);
4901 MA_API ma_vec3f ma_spatializer_listener_get_velocity(const ma_spatializer_listener* pListener);
4902 MA_API void ma_spatializer_listener_set_speed_of_sound(ma_spatializer_listener* pListener, float speedOfSound);
4903 MA_API float ma_spatializer_listener_get_speed_of_sound(const ma_spatializer_listener* pListener);
4904 MA_API void ma_spatializer_listener_set_world_up(ma_spatializer_listener* pListener, float x, float y, float z);
4905 MA_API ma_vec3f ma_spatializer_listener_get_world_up(const ma_spatializer_listener* pListener);
4906 MA_API void ma_spatializer_listener_set_enabled(ma_spatializer_listener* pListener, ma_bool32 isEnabled);
4907 MA_API ma_bool32 ma_spatializer_listener_is_enabled(const ma_spatializer_listener* pListener);
4908
4909
4910 typedef struct
4911 {
4912     ma_uint32 channelsIn;
4913     ma_uint32 channelsOut;
4914     ma_channel* pChannelMapIn;
4915     ma_attenuation_model attenuationModel;
4916     ma_positioning positioning;
4917     ma_handedness handedness;           /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */
4918     float minGain;
4919     float maxGain;
4920     float minDistance;
4921     float maxDistance;
4922     float rolloff;
4923     float coneInnerAngleInRadians;
4924     float coneOuterAngleInRadians;
4925     float coneOuterGain;
4926     float dopplerFactor;                /* Set to 0 to disable doppler effect. */
4927     float directionalAttenuationFactor; /* Set to 0 to disable directional attenuation. */
4928     ma_uint32 gainSmoothTimeInFrames;   /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */
4929 } ma_spatializer_config;
4930
4931 MA_API ma_spatializer_config ma_spatializer_config_init(ma_uint32 channelsIn, ma_uint32 channelsOut);
4932
4933
4934 typedef struct
4935 {
4936     ma_spatializer_config config;
4937     ma_vec3f position;
4938     ma_vec3f direction;
4939     ma_vec3f velocity;  /* For doppler effect. */
4940     float dopplerPitch; /* Will be updated by ma_spatializer_process_pcm_frames() and can be used by higher level functions to apply a pitch shift for doppler effect. */
4941     ma_gainer gainer;   /* For smooth gain transitions. */
4942     float* pNewChannelGainsOut; /* An offset of _pHeap. Used by ma_spatializer_process_pcm_frames() to store new channel gains. The number of elements in this array is equal to config.channelsOut. */
4943
4944     /* Memory management. */
4945     void* _pHeap;
4946     ma_bool32 _ownsHeap;
4947 } ma_spatializer;
4948
4949 MA_API ma_result ma_spatializer_get_heap_size(const ma_spatializer_config* pConfig, size_t* pHeapSizeInBytes);
4950 MA_API ma_result ma_spatializer_init_preallocated(const ma_spatializer_config* pConfig, void* pHeap, ma_spatializer* pSpatializer);
4951 MA_API ma_result ma_spatializer_init(const ma_spatializer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer* pSpatializer);
4952 MA_API void ma_spatializer_uninit(ma_spatializer* pSpatializer, const ma_allocation_callbacks* pAllocationCallbacks);
4953 MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ma_spatializer_listener* pListener, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
4954 MA_API ma_uint32 ma_spatializer_get_input_channels(const ma_spatializer* pSpatializer);
4955 MA_API ma_uint32 ma_spatializer_get_output_channels(const ma_spatializer* pSpatializer);
4956 MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, ma_attenuation_model attenuationModel);
4957 MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatializer* pSpatializer);
4958 MA_API void ma_spatializer_set_positioning(ma_spatializer* pSpatializer, ma_positioning positioning);
4959 MA_API ma_positioning ma_spatializer_get_positioning(const ma_spatializer* pSpatializer);
4960 MA_API void ma_spatializer_set_rolloff(ma_spatializer* pSpatializer, float rolloff);
4961 MA_API float ma_spatializer_get_rolloff(const ma_spatializer* pSpatializer);
4962 MA_API void ma_spatializer_set_min_gain(ma_spatializer* pSpatializer, float minGain);
4963 MA_API float ma_spatializer_get_min_gain(const ma_spatializer* pSpatializer);
4964 MA_API void ma_spatializer_set_max_gain(ma_spatializer* pSpatializer, float maxGain);
4965 MA_API float ma_spatializer_get_max_gain(const ma_spatializer* pSpatializer);
4966 MA_API void ma_spatializer_set_min_distance(ma_spatializer* pSpatializer, float minDistance);
4967 MA_API float ma_spatializer_get_min_distance(const ma_spatializer* pSpatializer);
4968 MA_API void ma_spatializer_set_max_distance(ma_spatializer* pSpatializer, float maxDistance);
4969 MA_API float ma_spatializer_get_max_distance(const ma_spatializer* pSpatializer);
4970 MA_API void ma_spatializer_set_cone(ma_spatializer* pSpatializer, float innerAngleInRadians, float outerAngleInRadians, float outerGain);
4971 MA_API void ma_spatializer_get_cone(const ma_spatializer* pSpatializer, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain);
4972 MA_API void ma_spatializer_set_doppler_factor(ma_spatializer* pSpatializer, float dopplerFactor);
4973 MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer* pSpatializer);
4974 MA_API void ma_spatializer_set_directional_attenuation_factor(ma_spatializer* pSpatializer, float directionalAttenuationFactor);
4975 MA_API float ma_spatializer_get_directional_attenuation_factor(const ma_spatializer* pSpatializer);
4976 MA_API void ma_spatializer_set_position(ma_spatializer* pSpatializer, float x, float y, float z);
4977 MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer* pSpatializer);
4978 MA_API void ma_spatializer_set_direction(ma_spatializer* pSpatializer, float x, float y, float z);
4979 MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer* pSpatializer);
4980 MA_API void ma_spatializer_set_velocity(ma_spatializer* pSpatializer, float x, float y, float z);
4981 MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer);
4982 MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatializer* pSpatializer, const ma_spatializer_listener* pListener, ma_vec3f* pRelativePos, ma_vec3f* pRelativeDir);
4983
4984
4985
4986 /************************************************************************************************************************************************************
4987 *************************************************************************************************************************************************************
4988
4989 DATA CONVERSION
4990 ===============
4991
4992 This section contains the APIs for data conversion. You will find everything here for channel mapping, sample format conversion, resampling, etc.
4993
4994 *************************************************************************************************************************************************************
4995 ************************************************************************************************************************************************************/
4996
4997 /**************************************************************************************************************************************************************
4998
4999 Resampling
5000
5001 **************************************************************************************************************************************************************/
5002 typedef struct
5003 {
5004     ma_format format;
5005     ma_uint32 channels;
5006     ma_uint32 sampleRateIn;
5007     ma_uint32 sampleRateOut;
5008     ma_uint32 lpfOrder;         /* The low-pass filter order. Setting this to 0 will disable low-pass filtering. */
5009     double    lpfNyquistFactor; /* 0..1. Defaults to 1. 1 = Half the sampling frequency (Nyquist Frequency), 0.5 = Quarter the sampling frequency (half Nyquest Frequency), etc. */
5010 } ma_linear_resampler_config;
5011
5012 MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
5013
5014 typedef struct
5015 {
5016     ma_linear_resampler_config config;
5017     ma_uint32 inAdvanceInt;
5018     ma_uint32 inAdvanceFrac;
5019     ma_uint32 inTimeInt;
5020     ma_uint32 inTimeFrac;
5021     union
5022     {
5023         float* f32;
5024         ma_int16* s16;
5025     } x0; /* The previous input frame. */
5026     union
5027     {
5028         float* f32;
5029         ma_int16* s16;
5030     } x1; /* The next input frame. */
5031     ma_lpf lpf;
5032
5033     /* Memory management. */
5034     void* _pHeap;
5035     ma_bool32 _ownsHeap;
5036 } ma_linear_resampler;
5037
5038 MA_API ma_result ma_linear_resampler_get_heap_size(const ma_linear_resampler_config* pConfig, size_t* pHeapSizeInBytes);
5039 MA_API ma_result ma_linear_resampler_init_preallocated(const ma_linear_resampler_config* pConfig, void* pHeap, ma_linear_resampler* pResampler);
5040 MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_linear_resampler* pResampler);
5041 MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks);
5042 MA_API ma_result ma_linear_resampler_process_pcm_frames(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
5043 MA_API ma_result ma_linear_resampler_set_rate(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
5044 MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResampler, float ratioInOut);
5045 MA_API ma_uint64 ma_linear_resampler_get_input_latency(const ma_linear_resampler* pResampler);
5046 MA_API ma_uint64 ma_linear_resampler_get_output_latency(const ma_linear_resampler* pResampler);
5047 MA_API ma_result ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount);
5048 MA_API ma_result ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount);
5049
5050
5051 typedef struct ma_resampler_config ma_resampler_config;
5052
5053 typedef void ma_resampling_backend;
5054 typedef struct
5055 {
5056     ma_result (* onGetHeapSize                )(void* pUserData, const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes);
5057     ma_result (* onInit                       )(void* pUserData, const ma_resampler_config* pConfig, void* pHeap, ma_resampling_backend** ppBackend);
5058     void      (* onUninit                     )(void* pUserData, ma_resampling_backend* pBackend, const ma_allocation_callbacks* pAllocationCallbacks);
5059     ma_result (* onProcess                    )(void* pUserData, ma_resampling_backend* pBackend, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
5060     ma_result (* onSetRate                    )(void* pUserData, ma_resampling_backend* pBackend, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);                 /* Optional. Rate changes will be disabled. */
5061     ma_uint64 (* onGetInputLatency            )(void* pUserData, const ma_resampling_backend* pBackend);                                                            /* Optional. Latency will be reported as 0. */
5062     ma_uint64 (* onGetOutputLatency           )(void* pUserData, const ma_resampling_backend* pBackend);                                                            /* Optional. Latency will be reported as 0. */
5063     ma_result (* onGetRequiredInputFrameCount )(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount);   /* Optional. Latency mitigation will be disabled. */
5064     ma_result (* onGetExpectedOutputFrameCount)(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount);   /* Optional. Latency mitigation will be disabled. */
5065 } ma_resampling_backend_vtable;
5066
5067 typedef enum
5068 {
5069     ma_resample_algorithm_linear = 0,    /* Fastest, lowest quality. Optional low-pass filtering. Default. */
5070     ma_resample_algorithm_custom,
5071 } ma_resample_algorithm;
5072
5073 struct ma_resampler_config
5074 {
5075     ma_format format;   /* Must be either ma_format_f32 or ma_format_s16. */
5076     ma_uint32 channels;
5077     ma_uint32 sampleRateIn;
5078     ma_uint32 sampleRateOut;
5079     ma_resample_algorithm algorithm;    /* When set to ma_resample_algorithm_custom, pBackendVTable will be used. */
5080     ma_resampling_backend_vtable* pBackendVTable;
5081     void* pBackendUserData;
5082     struct
5083     {
5084         ma_uint32 lpfOrder;
5085     } linear;
5086 };
5087
5088 MA_API ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_resample_algorithm algorithm);
5089
5090 typedef struct
5091 {
5092     ma_resampling_backend* pBackend;
5093     ma_resampling_backend_vtable* pBackendVTable;
5094     void* pBackendUserData;
5095     ma_format format;
5096     ma_uint32 channels;
5097     ma_uint32 sampleRateIn;
5098     ma_uint32 sampleRateOut;
5099     union
5100     {
5101         ma_linear_resampler linear;
5102     } state;    /* State for stock resamplers so we can avoid a malloc. For stock resamplers, pBackend will point here. */
5103
5104     /* Memory management. */
5105     void* _pHeap;
5106     ma_bool32 _ownsHeap;
5107 } ma_resampler;
5108
5109 MA_API ma_result ma_resampler_get_heap_size(const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes);
5110 MA_API ma_result ma_resampler_init_preallocated(const ma_resampler_config* pConfig, void* pHeap, ma_resampler* pResampler);
5111
5112 /*
5113 Initializes a new resampler object from a config.
5114 */
5115 MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_resampler* pResampler);
5116
5117 /*
5118 Uninitializes a resampler.
5119 */
5120 MA_API void ma_resampler_uninit(ma_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks);
5121
5122 /*
5123 Converts the given input data.
5124
5125 Both the input and output frames must be in the format specified in the config when the resampler was initilized.
5126
5127 On input, [pFrameCountOut] contains the number of output frames to process. On output it contains the number of output frames that
5128 were actually processed, which may be less than the requested amount which will happen if there's not enough input data. You can use
5129 ma_resampler_get_expected_output_frame_count() to know how many output frames will be processed for a given number of input frames.
5130
5131 On input, [pFrameCountIn] contains the number of input frames contained in [pFramesIn]. On output it contains the number of whole
5132 input frames that were actually processed. You can use ma_resampler_get_required_input_frame_count() to know how many input frames
5133 you should provide for a given number of output frames. [pFramesIn] can be NULL, in which case zeroes will be used instead.
5134
5135 If [pFramesOut] is NULL, a seek is performed. In this case, if [pFrameCountOut] is not NULL it will seek by the specified number of
5136 output frames. Otherwise, if [pFramesCountOut] is NULL and [pFrameCountIn] is not NULL, it will seek by the specified number of input
5137 frames. When seeking, [pFramesIn] is allowed to NULL, in which case the internal timing state will be updated, but no input will be
5138 processed. In this case, any internal filter state will be updated as if zeroes were passed in.
5139
5140 It is an error for [pFramesOut] to be non-NULL and [pFrameCountOut] to be NULL.
5141
5142 It is an error for both [pFrameCountOut] and [pFrameCountIn] to be NULL.
5143 */
5144 MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
5145
5146
5147 /*
5148 Sets the input and output sample sample rate.
5149 */
5150 MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
5151
5152 /*
5153 Sets the input and output sample rate as a ratio.
5154
5155 The ration is in/out.
5156 */
5157 MA_API ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio);
5158
5159 /*
5160 Retrieves the latency introduced by the resampler in input frames.
5161 */
5162 MA_API ma_uint64 ma_resampler_get_input_latency(const ma_resampler* pResampler);
5163
5164 /*
5165 Retrieves the latency introduced by the resampler in output frames.
5166 */
5167 MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler);
5168
5169 /*
5170 Calculates the number of whole input frames that would need to be read from the client in order to output the specified
5171 number of output frames.
5172
5173 The returned value does not include cached input frames. It only returns the number of extra frames that would need to be
5174 read from the input buffer in order to output the specified number of output frames.
5175 */
5176 MA_API ma_result ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount);
5177
5178 /*
5179 Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of
5180 input frames.
5181 */
5182 MA_API ma_result ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount);
5183
5184
5185 /**************************************************************************************************************************************************************
5186
5187 Channel Conversion
5188
5189 **************************************************************************************************************************************************************/
5190 typedef enum
5191 {
5192     ma_channel_conversion_path_unknown,
5193     ma_channel_conversion_path_passthrough,
5194     ma_channel_conversion_path_mono_out,    /* Converting to mono. */
5195     ma_channel_conversion_path_mono_in,     /* Converting from mono. */
5196     ma_channel_conversion_path_shuffle,     /* Simple shuffle. Will use this when all channels are present in both input and output channel maps, but just in a different order. */
5197     ma_channel_conversion_path_weights      /* Blended based on weights. */
5198 } ma_channel_conversion_path;
5199
5200 typedef enum
5201 {
5202     ma_mono_expansion_mode_duplicate = 0,   /* The default. */
5203     ma_mono_expansion_mode_average,         /* Average the mono channel across all channels. */
5204     ma_mono_expansion_mode_stereo_only,     /* Duplicate to the left and right channels only and ignore the others. */
5205     ma_mono_expansion_mode_default = ma_mono_expansion_mode_duplicate
5206 } ma_mono_expansion_mode;
5207
5208 typedef struct
5209 {
5210     ma_format format;
5211     ma_uint32 channelsIn;
5212     ma_uint32 channelsOut;
5213     const ma_channel* pChannelMapIn;
5214     const ma_channel* pChannelMapOut;
5215     ma_channel_mix_mode mixingMode;
5216     float** ppWeights;  /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */
5217 } ma_channel_converter_config;
5218
5219 MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format format, ma_uint32 channelsIn, const ma_channel* pChannelMapIn, ma_uint32 channelsOut, const ma_channel* pChannelMapOut, ma_channel_mix_mode mixingMode);
5220
5221 typedef struct
5222 {
5223     ma_format format;
5224     ma_uint32 channelsIn;
5225     ma_uint32 channelsOut;
5226     ma_channel_mix_mode mixingMode;
5227     ma_channel_conversion_path conversionPath;
5228     ma_channel* pChannelMapIn;
5229     ma_channel* pChannelMapOut;
5230     ma_uint8* pShuffleTable;    /* Indexed by output channel index. */
5231     union
5232     {
5233         float**    f32;
5234         ma_int32** s16;
5235     } weights;  /* [in][out] */
5236
5237     /* Memory management. */
5238     void* _pHeap;
5239     ma_bool32 _ownsHeap;
5240 } ma_channel_converter;
5241
5242 MA_API ma_result ma_channel_converter_get_heap_size(const ma_channel_converter_config* pConfig, size_t* pHeapSizeInBytes);
5243 MA_API ma_result ma_channel_converter_init_preallocated(const ma_channel_converter_config* pConfig, void* pHeap, ma_channel_converter* pConverter);
5244 MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_channel_converter* pConverter);
5245 MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks);
5246 MA_API ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
5247 MA_API ma_result ma_channel_converter_get_input_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap);
5248 MA_API ma_result ma_channel_converter_get_output_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap);
5249
5250
5251 /**************************************************************************************************************************************************************
5252
5253 Data Conversion
5254
5255 **************************************************************************************************************************************************************/
5256 typedef struct
5257 {
5258     ma_format formatIn;
5259     ma_format formatOut;
5260     ma_uint32 channelsIn;
5261     ma_uint32 channelsOut;
5262     ma_uint32 sampleRateIn;
5263     ma_uint32 sampleRateOut;
5264     ma_channel* pChannelMapIn;
5265     ma_channel* pChannelMapOut;
5266     ma_dither_mode ditherMode;
5267     ma_channel_mix_mode channelMixMode;
5268     float** ppChannelWeights;  /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */
5269     ma_bool32 allowDynamicSampleRate;
5270     ma_resampler_config resampling;
5271 } ma_data_converter_config;
5272
5273 MA_API ma_data_converter_config ma_data_converter_config_init_default(void);
5274 MA_API 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);
5275
5276
5277 typedef enum
5278 {
5279     ma_data_converter_execution_path_passthrough,       /* No conversion. */
5280     ma_data_converter_execution_path_format_only,       /* Only format conversion. */
5281     ma_data_converter_execution_path_channels_only,     /* Only channel conversion. */
5282     ma_data_converter_execution_path_resample_only,     /* Only resampling. */
5283     ma_data_converter_execution_path_resample_first,    /* All conversions, but resample as the first step. */
5284     ma_data_converter_execution_path_channels_first     /* All conversions, but channels as the first step. */
5285 } ma_data_converter_execution_path;
5286
5287 typedef struct
5288 {
5289     ma_format formatIn;
5290     ma_format formatOut;
5291     ma_uint32 channelsIn;
5292     ma_uint32 channelsOut;
5293     ma_uint32 sampleRateIn;
5294     ma_uint32 sampleRateOut;
5295     ma_dither_mode ditherMode;
5296     ma_data_converter_execution_path executionPath; /* The execution path the data converter will follow when processing. */
5297     ma_channel_converter channelConverter;
5298     ma_resampler resampler;
5299     ma_bool8 hasPreFormatConversion;
5300     ma_bool8 hasPostFormatConversion;
5301     ma_bool8 hasChannelConverter;
5302     ma_bool8 hasResampler;
5303     ma_bool8 isPassthrough;
5304
5305     /* Memory management. */
5306     ma_bool8 _ownsHeap;
5307     void* _pHeap;
5308 } ma_data_converter;
5309
5310 MA_API ma_result ma_data_converter_get_heap_size(const ma_data_converter_config* pConfig, size_t* pHeapSizeInBytes);
5311 MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_config* pConfig, void* pHeap, ma_data_converter* pConverter);
5312 MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_converter* pConverter);
5313 MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks);
5314 MA_API ma_result ma_data_converter_process_pcm_frames(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
5315 MA_API ma_result ma_data_converter_set_rate(ma_data_converter* pConverter, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
5316 MA_API ma_result ma_data_converter_set_rate_ratio(ma_data_converter* pConverter, float ratioInOut);
5317 MA_API ma_uint64 ma_data_converter_get_input_latency(const ma_data_converter* pConverter);
5318 MA_API ma_uint64 ma_data_converter_get_output_latency(const ma_data_converter* pConverter);
5319 MA_API ma_result ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount);
5320 MA_API ma_result ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount);
5321 MA_API ma_result ma_data_converter_get_input_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap);
5322 MA_API ma_result ma_data_converter_get_output_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap);
5323
5324
5325 /************************************************************************************************************************************************************
5326
5327 Format Conversion
5328
5329 ************************************************************************************************************************************************************/
5330 MA_API void ma_pcm_u8_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5331 MA_API void ma_pcm_u8_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5332 MA_API void ma_pcm_u8_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5333 MA_API void ma_pcm_u8_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5334 MA_API void ma_pcm_s16_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5335 MA_API void ma_pcm_s16_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5336 MA_API void ma_pcm_s16_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5337 MA_API void ma_pcm_s16_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5338 MA_API void ma_pcm_s24_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5339 MA_API void ma_pcm_s24_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5340 MA_API void ma_pcm_s24_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5341 MA_API void ma_pcm_s24_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5342 MA_API void ma_pcm_s32_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5343 MA_API void ma_pcm_s32_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5344 MA_API void ma_pcm_s32_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5345 MA_API void ma_pcm_s32_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5346 MA_API void ma_pcm_f32_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5347 MA_API void ma_pcm_f32_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5348 MA_API void ma_pcm_f32_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5349 MA_API void ma_pcm_f32_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
5350 MA_API void ma_pcm_convert(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 sampleCount, ma_dither_mode ditherMode);
5351 MA_API 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);
5352
5353 /*
5354 Deinterleaves an interleaved buffer.
5355 */
5356 MA_API void ma_deinterleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void* pInterleavedPCMFrames, void** ppDeinterleavedPCMFrames);
5357
5358 /*
5359 Interleaves a group of deinterleaved buffers.
5360 */
5361 MA_API void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames);
5362
5363
5364 /************************************************************************************************************************************************************
5365
5366 Channel Maps
5367
5368 ************************************************************************************************************************************************************/
5369 /*
5370 This is used in the shuffle table to indicate that the channel index is undefined and should be ignored.
5371 */
5372 #define MA_CHANNEL_INDEX_NULL   255
5373
5374 /*
5375 Retrieves the channel position of the specified channel in the given channel map.
5376
5377 The pChannelMap parameter can be null, in which case miniaudio's default channel map will be assumed.
5378 */
5379 MA_API ma_channel ma_channel_map_get_channel(const ma_channel* pChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex);
5380
5381 /*
5382 Initializes a blank channel map.
5383
5384 When a blank channel map is specified anywhere it indicates that the native channel map should be used.
5385 */
5386 MA_API void ma_channel_map_init_blank(ma_channel* pChannelMap, ma_uint32 channels);
5387
5388 /*
5389 Helper for retrieving a standard channel map.
5390
5391 The output channel map buffer must have a capacity of at least `channelMapCap`.
5392 */
5393 MA_API void ma_channel_map_init_standard(ma_standard_channel_map standardChannelMap, ma_channel* pChannelMap, size_t channelMapCap, ma_uint32 channels);
5394
5395 /*
5396 Copies a channel map.
5397
5398 Both input and output channel map buffers must have a capacity of at at least `channels`.
5399 */
5400 MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels);
5401
5402 /*
5403 Copies a channel map if one is specified, otherwise copies the default channel map.
5404
5405 The output buffer must have a capacity of at least `channels`. If not NULL, the input channel map must also have a capacity of at least `channels`.
5406 */
5407 MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, size_t channelMapCapOut, const ma_channel* pIn, ma_uint32 channels);
5408
5409
5410 /*
5411 Determines whether or not a channel map is valid.
5412
5413 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
5414 is usually treated as a passthrough.
5415
5416 Invalid channel maps:
5417   - A channel map with no channels
5418   - A channel map with more than one channel and a mono channel
5419
5420 The channel map buffer must have a capacity of at least `channels`.
5421 */
5422 MA_API ma_bool32 ma_channel_map_is_valid(const ma_channel* pChannelMap, ma_uint32 channels);
5423
5424 /*
5425 Helper for comparing two channel maps for equality.
5426
5427 This assumes the channel count is the same between the two.
5428
5429 Both channels map buffers must have a capacity of at least `channels`.
5430 */
5431 MA_API ma_bool32 ma_channel_map_is_equal(const ma_channel* pChannelMapA, const ma_channel* pChannelMapB, ma_uint32 channels);
5432
5433 /*
5434 Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE).
5435
5436 The channel map buffer must have a capacity of at least `channels`.
5437 */
5438 MA_API ma_bool32 ma_channel_map_is_blank(const ma_channel* pChannelMap, ma_uint32 channels);
5439
5440 /*
5441 Helper for determining whether or not a channel is present in the given channel map.
5442
5443 The channel map buffer must have a capacity of at least `channels`.
5444 */
5445 MA_API ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel* pChannelMap, ma_channel channelPosition);
5446
5447
5448 /************************************************************************************************************************************************************
5449
5450 Conversion Helpers
5451
5452 ************************************************************************************************************************************************************/
5453
5454 /*
5455 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
5456 determine the required size of the output buffer. frameCountOut should be set to the capacity of pOut. If pOut is NULL, frameCountOut is
5457 ignored.
5458
5459 A return value of 0 indicates an error.
5460
5461 This function is useful for one-off bulk conversions, but if you're streaming data you should use the ma_data_converter APIs instead.
5462 */
5463 MA_API 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);
5464 MA_API ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const void* pIn, ma_uint64 frameCountIn, const ma_data_converter_config* pConfig);
5465
5466
5467 /************************************************************************************************************************************************************
5468
5469 Ring Buffer
5470
5471 ************************************************************************************************************************************************************/
5472 typedef struct
5473 {
5474     void* pBuffer;
5475     ma_uint32 subbufferSizeInBytes;
5476     ma_uint32 subbufferCount;
5477     ma_uint32 subbufferStrideInBytes;
5478     MA_ATOMIC(4, ma_uint32) encodedReadOffset;  /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */
5479     MA_ATOMIC(4, ma_uint32) encodedWriteOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */
5480     ma_bool8 ownsBuffer;                        /* Used to know whether or not miniaudio is responsible for free()-ing the buffer. */
5481     ma_bool8 clearOnWriteAcquire;               /* When set, clears the acquired write buffer before returning from ma_rb_acquire_write(). */
5482     ma_allocation_callbacks allocationCallbacks;
5483 } ma_rb;
5484
5485 MA_API 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);
5486 MA_API ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB);
5487 MA_API void ma_rb_uninit(ma_rb* pRB);
5488 MA_API void ma_rb_reset(ma_rb* pRB);
5489 MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut);
5490 MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes);
5491 MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut);
5492 MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes);
5493 MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes);
5494 MA_API ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes);
5495 MA_API 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. */
5496 MA_API ma_uint32 ma_rb_available_read(ma_rb* pRB);
5497 MA_API ma_uint32 ma_rb_available_write(ma_rb* pRB);
5498 MA_API size_t ma_rb_get_subbuffer_size(ma_rb* pRB);
5499 MA_API size_t ma_rb_get_subbuffer_stride(ma_rb* pRB);
5500 MA_API size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex);
5501 MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer);
5502
5503
5504 typedef struct
5505 {
5506     ma_rb rb;
5507     ma_format format;
5508     ma_uint32 channels;
5509 } ma_pcm_rb;
5510
5511 MA_API 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);
5512 MA_API 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);
5513 MA_API void ma_pcm_rb_uninit(ma_pcm_rb* pRB);
5514 MA_API void ma_pcm_rb_reset(ma_pcm_rb* pRB);
5515 MA_API ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut);
5516 MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames);
5517 MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut);
5518 MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames);
5519 MA_API ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames);
5520 MA_API ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames);
5521 MA_API ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb* pRB); /* Return value is in frames. */
5522 MA_API ma_uint32 ma_pcm_rb_available_read(ma_pcm_rb* pRB);
5523 MA_API ma_uint32 ma_pcm_rb_available_write(ma_pcm_rb* pRB);
5524 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb* pRB);
5525 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb* pRB);
5526 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbufferIndex);
5527 MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer);
5528
5529
5530 /*
5531 The idea of the duplex ring buffer is to act as the intermediary buffer when running two asynchronous devices in a duplex set up. The
5532 capture device writes to it, and then a playback device reads from it.
5533
5534 At the moment this is just a simple naive implementation, but in the future I want to implement some dynamic resampling to seamlessly
5535 handle desyncs. Note that the API is work in progress and may change at any time in any version.
5536
5537 The size of the buffer is based on the capture side since that's what'll be written to the buffer. It is based on the capture period size
5538 in frames. The internal sample rate of the capture device is also needed in order to calculate the size.
5539 */
5540 typedef struct
5541 {
5542     ma_pcm_rb rb;
5543 } ma_duplex_rb;
5544
5545 MA_API ma_result ma_duplex_rb_init(ma_format captureFormat, ma_uint32 captureChannels, ma_uint32 sampleRate, ma_uint32 captureInternalSampleRate, ma_uint32 captureInternalPeriodSizeInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_duplex_rb* pRB);
5546 MA_API ma_result ma_duplex_rb_uninit(ma_duplex_rb* pRB);
5547
5548
5549 /************************************************************************************************************************************************************
5550
5551 Miscellaneous Helpers
5552
5553 ************************************************************************************************************************************************************/
5554 /*
5555 Retrieves a human readable description of the given result code.
5556 */
5557 MA_API const char* ma_result_description(ma_result result);
5558
5559 /*
5560 malloc()
5561 */
5562 MA_API void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks);
5563
5564 /*
5565 calloc()
5566 */
5567 MA_API void* ma_calloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks);
5568
5569 /*
5570 realloc()
5571 */
5572 MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks);
5573
5574 /*
5575 free()
5576 */
5577 MA_API void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks);
5578
5579 /*
5580 Performs an aligned malloc, with the assumption that the alignment is a power of 2.
5581 */
5582 MA_API void* ma_aligned_malloc(size_t sz, size_t alignment, const ma_allocation_callbacks* pAllocationCallbacks);
5583
5584 /*
5585 Free's an aligned malloc'd buffer.
5586 */
5587 MA_API void ma_aligned_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks);
5588
5589 /*
5590 Retrieves a friendly name for a format.
5591 */
5592 MA_API const char* ma_get_format_name(ma_format format);
5593
5594 /*
5595 Blends two frames in floating point format.
5596 */
5597 MA_API void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels);
5598
5599 /*
5600 Retrieves the size of a sample in bytes for the given format.
5601
5602 This API is efficient and is implemented using a lookup table.
5603
5604 Thread Safety: SAFE
5605   This API is pure.
5606 */
5607 MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format);
5608 static MA_INLINE ma_uint32 ma_get_bytes_per_frame(ma_format format, ma_uint32 channels) { return ma_get_bytes_per_sample(format) * channels; }
5609
5610 /*
5611 Converts a log level to a string.
5612 */
5613 MA_API const char* ma_log_level_to_string(ma_uint32 logLevel);
5614
5615
5616
5617 /************************************************************************************************************************************************************
5618 *************************************************************************************************************************************************************
5619
5620 DEVICE I/O
5621 ==========
5622
5623 This section contains the APIs for device playback and capture. Here is where you'll find ma_device_init(), etc.
5624
5625 *************************************************************************************************************************************************************
5626 ************************************************************************************************************************************************************/
5627 #ifndef MA_NO_DEVICE_IO
5628 /* Some backends are only supported on certain platforms. */
5629 #if defined(MA_WIN32)
5630     #define MA_SUPPORT_WASAPI
5631     #if defined(MA_WIN32_DESKTOP)  /* DirectSound and WinMM backends are only supported on desktops. */
5632         #define MA_SUPPORT_DSOUND
5633         #define MA_SUPPORT_WINMM
5634         #define MA_SUPPORT_JACK    /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */
5635     #endif
5636 #endif
5637 #if defined(MA_UNIX)
5638     #if defined(MA_LINUX)
5639         #if !defined(MA_ANDROID)   /* ALSA is not supported on Android. */
5640             #define MA_SUPPORT_ALSA
5641         #endif
5642     #endif
5643     #if !defined(MA_BSD) && !defined(MA_ANDROID) && !defined(MA_EMSCRIPTEN)
5644         #define MA_SUPPORT_PULSEAUDIO
5645         #define MA_SUPPORT_JACK
5646     #endif
5647     #if defined(MA_ANDROID)
5648         #define MA_SUPPORT_AAUDIO
5649         #define MA_SUPPORT_OPENSL
5650     #endif
5651     #if defined(__OpenBSD__)        /* <-- Change this to "#if defined(MA_BSD)" to enable sndio on all BSD flavors. */
5652         #define MA_SUPPORT_SNDIO    /* sndio is only supported on OpenBSD for now. May be expanded later if there's demand. */
5653     #endif
5654     #if defined(__NetBSD__) || defined(__OpenBSD__)
5655         #define MA_SUPPORT_AUDIO4   /* Only support audio(4) on platforms with known support. */
5656     #endif
5657     #if defined(__FreeBSD__) || defined(__DragonFly__)
5658         #define MA_SUPPORT_OSS      /* Only support OSS on specific platforms with known support. */
5659     #endif
5660 #endif
5661 #if defined(MA_APPLE)
5662     #define MA_SUPPORT_COREAUDIO
5663 #endif
5664 #if defined(MA_EMSCRIPTEN)
5665     #define MA_SUPPORT_WEBAUDIO
5666 #endif
5667
5668 /* All platforms should support custom backends. */
5669 #define MA_SUPPORT_CUSTOM
5670
5671 /* Explicitly disable the Null backend for Emscripten because it uses a background thread which is not properly supported right now. */
5672 #if !defined(MA_EMSCRIPTEN)
5673 #define MA_SUPPORT_NULL
5674 #endif
5675
5676
5677 #if defined(MA_SUPPORT_WASAPI) && !defined(MA_NO_WASAPI) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WASAPI))
5678     #define MA_HAS_WASAPI
5679 #endif
5680 #if defined(MA_SUPPORT_DSOUND) && !defined(MA_NO_DSOUND) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_DSOUND))
5681     #define MA_HAS_DSOUND
5682 #endif
5683 #if defined(MA_SUPPORT_WINMM) && !defined(MA_NO_WINMM) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WINMM))
5684     #define MA_HAS_WINMM
5685 #endif
5686 #if defined(MA_SUPPORT_ALSA) && !defined(MA_NO_ALSA) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_ALSA))
5687     #define MA_HAS_ALSA
5688 #endif
5689 #if defined(MA_SUPPORT_PULSEAUDIO) && !defined(MA_NO_PULSEAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_PULSEAUDIO))
5690     #define MA_HAS_PULSEAUDIO
5691 #endif
5692 #if defined(MA_SUPPORT_JACK) && !defined(MA_NO_JACK) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_JACK))
5693     #define MA_HAS_JACK
5694 #endif
5695 #if defined(MA_SUPPORT_COREAUDIO) && !defined(MA_NO_COREAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_COREAUDIO))
5696     #define MA_HAS_COREAUDIO
5697 #endif
5698 #if defined(MA_SUPPORT_SNDIO) && !defined(MA_NO_SNDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_SNDIO))
5699     #define MA_HAS_SNDIO
5700 #endif
5701 #if defined(MA_SUPPORT_AUDIO4) && !defined(MA_NO_AUDIO4) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_AUDIO4))
5702     #define MA_HAS_AUDIO4
5703 #endif
5704 #if defined(MA_SUPPORT_OSS) && !defined(MA_NO_OSS) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_OSS))
5705     #define MA_HAS_OSS
5706 #endif
5707 #if defined(MA_SUPPORT_AAUDIO) && !defined(MA_NO_AAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_AAUDIO))
5708     #define MA_HAS_AAUDIO
5709 #endif
5710 #if defined(MA_SUPPORT_OPENSL) && !defined(MA_NO_OPENSL) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_OPENSL))
5711     #define MA_HAS_OPENSL
5712 #endif
5713 #if defined(MA_SUPPORT_WEBAUDIO) && !defined(MA_NO_WEBAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WEBAUDIO))
5714     #define MA_HAS_WEBAUDIO
5715 #endif
5716 #if defined(MA_SUPPORT_CUSTOM) && !defined(MA_NO_CUSTOM) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_CUSTOM))
5717     #define MA_HAS_CUSTOM
5718 #endif
5719 #if defined(MA_SUPPORT_NULL) && !defined(MA_NO_NULL) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_NULL))
5720     #define MA_HAS_NULL
5721 #endif
5722
5723 typedef enum
5724 {
5725     ma_device_state_uninitialized = 0,
5726     ma_device_state_stopped       = 1,  /* The device's default state after initialization. */
5727     ma_device_state_started       = 2,  /* The device is started and is requesting and/or delivering audio data. */
5728     ma_device_state_starting      = 3,  /* Transitioning from a stopped state to started. */
5729     ma_device_state_stopping      = 4   /* Transitioning from a started state to stopped. */
5730 } ma_device_state;
5731
5732 #ifdef MA_SUPPORT_WASAPI
5733 /* We need a IMMNotificationClient object for WASAPI. */
5734 typedef struct
5735 {
5736     void* lpVtbl;
5737     ma_uint32 counter;
5738     ma_device* pDevice;
5739 } ma_IMMNotificationClient;
5740 #endif
5741
5742 /* Backend enums must be in priority order. */
5743 typedef enum
5744 {
5745     ma_backend_wasapi,
5746     ma_backend_dsound,
5747     ma_backend_winmm,
5748     ma_backend_coreaudio,
5749     ma_backend_sndio,
5750     ma_backend_audio4,
5751     ma_backend_oss,
5752     ma_backend_pulseaudio,
5753     ma_backend_alsa,
5754     ma_backend_jack,
5755     ma_backend_aaudio,
5756     ma_backend_opensl,
5757     ma_backend_webaudio,
5758     ma_backend_custom,  /* <-- Custom backend, with callbacks defined by the context config. */
5759     ma_backend_null     /* <-- Must always be the last item. Lowest priority, and used as the terminator for backend enumeration. */
5760 } ma_backend;
5761
5762 #define MA_BACKEND_COUNT (ma_backend_null+1)
5763
5764
5765 /* Device notification types. */
5766 typedef enum
5767 {
5768     ma_device_notification_type_started,
5769     ma_device_notification_type_stopped,
5770     ma_device_notification_type_rerouted,
5771     ma_device_notification_type_interruption_began,
5772     ma_device_notification_type_interruption_ended
5773 } ma_device_notification_type;
5774
5775 typedef struct
5776 {
5777     ma_device* pDevice;
5778     ma_device_notification_type type;
5779     union
5780     {
5781         struct
5782         {
5783             int _unused;
5784         } started;
5785         struct
5786         {
5787             int _unused;
5788         } stopped;
5789         struct
5790         {
5791             int _unused;
5792         } rerouted;
5793         struct
5794         {
5795             int _unused;
5796         } interruption;
5797     } data;
5798 } ma_device_notification;
5799
5800 /*
5801 The notification callback for when the application should be notified of a change to the device.
5802
5803 This callback is used for notifying the application of changes such as when the device has started,
5804 stopped, rerouted or an interruption has occurred. Note that not all backends will post all
5805 notification types. For example, some backends will perform automatic stream routing without any
5806 kind of notification to the host program which means miniaudio will never know about it and will
5807 never be able to fire the rerouted notification. You should keep this in mind when designing your
5808 program.
5809
5810 The stopped notification will *not* get fired when a device is rerouted.
5811
5812
5813 Parameters
5814 ----------
5815 pNotification (in)
5816     A pointer to a structure containing information about the event. Use the `pDevice` member of
5817     this object to retrieve the relevant device. The `type` member can be used to discriminate
5818     against each of the notification types.
5819
5820
5821 Remarks
5822 -------
5823 Do not restart or uninitialize the device from the callback.
5824
5825 Not all notifications will be triggered by all backends, however the started and stopped events
5826 should be reliable for all backends. Some backends do not have a good way to detect device
5827 stoppages due to unplugging the device which may result in the stopped callback not getting
5828 fired. This has been observed with at least one BSD variant.
5829
5830 The rerouted notification is fired *after* the reroute has occurred. The stopped notification will
5831 *not* get fired when a device is rerouted. The following backends are known to do automatic stream
5832 rerouting, but do not have a way to be notified of the change:
5833
5834   * DirectSound
5835
5836 The interruption notifications are used on mobile platforms for detecting when audio is interrupted
5837 due to things like an incoming phone call. Currently this is only implemented on iOS. None of the
5838 Android backends will report this notification.
5839 */
5840 typedef void (* ma_device_notification_proc)(const ma_device_notification* pNotification);
5841
5842
5843 /*
5844 The callback for processing audio data from the device.
5845
5846 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
5847 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
5848 callback will be fired with a consistent frame count.
5849
5850
5851 Parameters
5852 ----------
5853 pDevice (in)
5854     A pointer to the relevant device.
5855
5856 pOutput (out)
5857     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
5858     full-duplex device and null for a capture and loopback device.
5859
5860 pInput (in)
5861     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
5862     playback device.
5863
5864 frameCount (in)
5865     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
5866     `periodSizeInFrames` and `periodSizeInMilliseconds` members of the device config are just hints, and are not necessarily exactly what you'll get. You must
5867     not assume this will always be the same value each time the callback is fired.
5868
5869
5870 Remarks
5871 -------
5872 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
5873 callback. The following APIs cannot be called from inside the callback:
5874
5875     ma_device_init()
5876     ma_device_init_ex()
5877     ma_device_uninit()
5878     ma_device_start()
5879     ma_device_stop()
5880
5881 The proper way to stop the device is to call `ma_device_stop()` from a different thread, normally the main application thread.
5882 */
5883 typedef void (* ma_device_data_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
5884
5885
5886
5887
5888 /*
5889 DEPRECATED. Use ma_device_notification_proc instead.
5890
5891 The callback for when the device has been stopped.
5892
5893 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
5894 such as being unplugged or an internal error occuring.
5895
5896
5897 Parameters
5898 ----------
5899 pDevice (in)
5900     A pointer to the device that has just stopped.
5901
5902
5903 Remarks
5904 -------
5905 Do not restart or uninitialize the device from the callback.
5906 */
5907 typedef void (* ma_stop_proc)(ma_device* pDevice);  /* DEPRECATED. Use ma_device_notification_proc instead. */
5908
5909 typedef enum
5910 {
5911     ma_device_type_playback = 1,
5912     ma_device_type_capture  = 2,
5913     ma_device_type_duplex   = ma_device_type_playback | ma_device_type_capture, /* 3 */
5914     ma_device_type_loopback = 4
5915 } ma_device_type;
5916
5917 typedef enum
5918 {
5919     ma_share_mode_shared = 0,
5920     ma_share_mode_exclusive
5921 } ma_share_mode;
5922
5923 /* iOS/tvOS/watchOS session categories. */
5924 typedef enum
5925 {
5926     ma_ios_session_category_default = 0,        /* AVAudioSessionCategoryPlayAndRecord with AVAudioSessionCategoryOptionDefaultToSpeaker. */
5927     ma_ios_session_category_none,               /* Leave the session category unchanged. */
5928     ma_ios_session_category_ambient,            /* AVAudioSessionCategoryAmbient */
5929     ma_ios_session_category_solo_ambient,       /* AVAudioSessionCategorySoloAmbient */
5930     ma_ios_session_category_playback,           /* AVAudioSessionCategoryPlayback */
5931     ma_ios_session_category_record,             /* AVAudioSessionCategoryRecord */
5932     ma_ios_session_category_play_and_record,    /* AVAudioSessionCategoryPlayAndRecord */
5933     ma_ios_session_category_multi_route         /* AVAudioSessionCategoryMultiRoute */
5934 } ma_ios_session_category;
5935
5936 /* iOS/tvOS/watchOS session category options */
5937 typedef enum
5938 {
5939     ma_ios_session_category_option_mix_with_others                            = 0x01,   /* AVAudioSessionCategoryOptionMixWithOthers */
5940     ma_ios_session_category_option_duck_others                                = 0x02,   /* AVAudioSessionCategoryOptionDuckOthers */
5941     ma_ios_session_category_option_allow_bluetooth                            = 0x04,   /* AVAudioSessionCategoryOptionAllowBluetooth */
5942     ma_ios_session_category_option_default_to_speaker                         = 0x08,   /* AVAudioSessionCategoryOptionDefaultToSpeaker */
5943     ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others = 0x11,   /* AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers */
5944     ma_ios_session_category_option_allow_bluetooth_a2dp                       = 0x20,   /* AVAudioSessionCategoryOptionAllowBluetoothA2DP */
5945     ma_ios_session_category_option_allow_air_play                             = 0x40,   /* AVAudioSessionCategoryOptionAllowAirPlay */
5946 } ma_ios_session_category_option;
5947
5948 /* OpenSL stream types. */
5949 typedef enum
5950 {
5951     ma_opensl_stream_type_default = 0,              /* Leaves the stream type unset. */
5952     ma_opensl_stream_type_voice,                    /* SL_ANDROID_STREAM_VOICE */
5953     ma_opensl_stream_type_system,                   /* SL_ANDROID_STREAM_SYSTEM */
5954     ma_opensl_stream_type_ring,                     /* SL_ANDROID_STREAM_RING */
5955     ma_opensl_stream_type_media,                    /* SL_ANDROID_STREAM_MEDIA */
5956     ma_opensl_stream_type_alarm,                    /* SL_ANDROID_STREAM_ALARM */
5957     ma_opensl_stream_type_notification              /* SL_ANDROID_STREAM_NOTIFICATION */
5958 } ma_opensl_stream_type;
5959
5960 /* OpenSL recording presets. */
5961 typedef enum
5962 {
5963     ma_opensl_recording_preset_default = 0,         /* Leaves the input preset unset. */
5964     ma_opensl_recording_preset_generic,             /* SL_ANDROID_RECORDING_PRESET_GENERIC */
5965     ma_opensl_recording_preset_camcorder,           /* SL_ANDROID_RECORDING_PRESET_CAMCORDER */
5966     ma_opensl_recording_preset_voice_recognition,   /* SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION */
5967     ma_opensl_recording_preset_voice_communication, /* SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION */
5968     ma_opensl_recording_preset_voice_unprocessed    /* SL_ANDROID_RECORDING_PRESET_UNPROCESSED */
5969 } ma_opensl_recording_preset;
5970
5971 /* AAudio usage types. */
5972 typedef enum
5973 {
5974     ma_aaudio_usage_default = 0,                    /* Leaves the usage type unset. */
5975     ma_aaudio_usage_announcement,                   /* AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT */
5976     ma_aaudio_usage_emergency,                      /* AAUDIO_SYSTEM_USAGE_EMERGENCY */
5977     ma_aaudio_usage_safety,                         /* AAUDIO_SYSTEM_USAGE_SAFETY */
5978     ma_aaudio_usage_vehicle_status,                 /* AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS */
5979     ma_aaudio_usage_alarm,                          /* AAUDIO_USAGE_ALARM */
5980     ma_aaudio_usage_assistance_accessibility,       /* AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY */
5981     ma_aaudio_usage_assistance_navigation_guidance, /* AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE */
5982     ma_aaudio_usage_assistance_sonification,        /* AAUDIO_USAGE_ASSISTANCE_SONIFICATION */
5983     ma_aaudio_usage_assitant,                       /* AAUDIO_USAGE_ASSISTANT */
5984     ma_aaudio_usage_game,                           /* AAUDIO_USAGE_GAME */
5985     ma_aaudio_usage_media,                          /* AAUDIO_USAGE_MEDIA */
5986     ma_aaudio_usage_notification,                   /* AAUDIO_USAGE_NOTIFICATION */
5987     ma_aaudio_usage_notification_event,             /* AAUDIO_USAGE_NOTIFICATION_EVENT */
5988     ma_aaudio_usage_notification_ringtone,          /* AAUDIO_USAGE_NOTIFICATION_RINGTONE */
5989     ma_aaudio_usage_voice_communication,            /* AAUDIO_USAGE_VOICE_COMMUNICATION */
5990     ma_aaudio_usage_voice_communication_signalling  /* AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING */
5991 } ma_aaudio_usage;
5992
5993 /* AAudio content types. */
5994 typedef enum
5995 {
5996     ma_aaudio_content_type_default = 0,             /* Leaves the content type unset. */
5997     ma_aaudio_content_type_movie,                   /* AAUDIO_CONTENT_TYPE_MOVIE */
5998     ma_aaudio_content_type_music,                   /* AAUDIO_CONTENT_TYPE_MUSIC */
5999     ma_aaudio_content_type_sonification,            /* AAUDIO_CONTENT_TYPE_SONIFICATION */
6000     ma_aaudio_content_type_speech                   /* AAUDIO_CONTENT_TYPE_SPEECH */
6001 } ma_aaudio_content_type;
6002
6003 /* AAudio input presets. */
6004 typedef enum
6005 {
6006     ma_aaudio_input_preset_default = 0,             /* Leaves the input preset unset. */
6007     ma_aaudio_input_preset_generic,                 /* AAUDIO_INPUT_PRESET_GENERIC */
6008     ma_aaudio_input_preset_camcorder,               /* AAUDIO_INPUT_PRESET_CAMCORDER */
6009     ma_aaudio_input_preset_unprocessed,             /* AAUDIO_INPUT_PRESET_UNPROCESSED */
6010     ma_aaudio_input_preset_voice_recognition,       /* AAUDIO_INPUT_PRESET_VOICE_RECOGNITION */
6011     ma_aaudio_input_preset_voice_communication,     /* AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION */
6012     ma_aaudio_input_preset_voice_performance        /* AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE */
6013 } ma_aaudio_input_preset;
6014
6015
6016 typedef union
6017 {
6018     ma_int64 counter;
6019     double counterD;
6020 } ma_timer;
6021
6022 typedef union
6023 {
6024     wchar_t wasapi[64];             /* WASAPI uses a wchar_t string for identification. */
6025     ma_uint8 dsound[16];            /* DirectSound uses a GUID for identification. */
6026     /*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. */
6027     char alsa[256];                 /* ALSA uses a name string for identification. */
6028     char pulse[256];                /* PulseAudio uses a name string for identification. */
6029     int jack;                       /* JACK always uses default devices. */
6030     char coreaudio[256];            /* Core Audio uses a string for identification. */
6031     char sndio[256];                /* "snd/0", etc. */
6032     char audio4[256];               /* "/dev/audio", etc. */
6033     char oss[64];                   /* "dev/dsp0", etc. "dev/dsp" for the default device. */
6034     ma_int32 aaudio;                /* AAudio uses a 32-bit integer for identification. */
6035     ma_uint32 opensl;               /* OpenSL|ES uses a 32-bit unsigned integer for identification. */
6036     char webaudio[32];              /* Web Audio always uses default devices for now, but if this changes it'll be a GUID. */
6037     union
6038     {
6039         int i;
6040         char s[256];
6041         void* p;
6042     } custom;                       /* The custom backend could be anything. Give them a few options. */
6043     int nullbackend;                /* The null backend uses an integer for device IDs. */
6044 } ma_device_id;
6045
6046
6047 typedef struct ma_context_config    ma_context_config;
6048 typedef struct ma_device_config     ma_device_config;
6049 typedef struct ma_backend_callbacks ma_backend_callbacks;
6050
6051 #define MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE (1U << 1)    /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */
6052
6053 #ifndef MA_MAX_DEVICE_NAME_LENGTH
6054 #define MA_MAX_DEVICE_NAME_LENGTH   255
6055 #endif
6056
6057 typedef struct
6058 {
6059     /* Basic info. This is the only information guaranteed to be filled in during device enumeration. */
6060     ma_device_id id;
6061     char name[MA_MAX_DEVICE_NAME_LENGTH + 1];   /* +1 for null terminator. */
6062     ma_bool32 isDefault;
6063
6064     ma_uint32 nativeDataFormatCount;
6065     struct
6066     {
6067         ma_format format;       /* Sample format. If set to ma_format_unknown, all sample formats are supported. */
6068         ma_uint32 channels;     /* If set to 0, all channels are supported. */
6069         ma_uint32 sampleRate;   /* If set to 0, all sample rates are supported. */
6070         ma_uint32 flags;        /* A combination of MA_DATA_FORMAT_FLAG_* flags. */
6071     } nativeDataFormats[/*ma_format_count * ma_standard_sample_rate_count * MA_MAX_CHANNELS*/ 64];  /* Not sure how big to make this. There can be *many* permutations for virtual devices which can support anything. */
6072 } ma_device_info;
6073
6074 struct ma_device_config
6075 {
6076     ma_device_type deviceType;
6077     ma_uint32 sampleRate;
6078     ma_uint32 periodSizeInFrames;
6079     ma_uint32 periodSizeInMilliseconds;
6080     ma_uint32 periods;
6081     ma_performance_profile performanceProfile;
6082     ma_bool8 noPreSilencedOutputBuffer; /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to silence. */
6083     ma_bool8 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. */
6084     ma_bool8 noDisableDenormals;        /* Do not disable denormals when firing the data callback. */
6085     ma_device_data_proc dataCallback;
6086     ma_device_notification_proc notificationCallback;
6087     ma_stop_proc stopCallback;
6088     void* pUserData;
6089     ma_resampler_config resampling;
6090     struct
6091     {
6092         const ma_device_id* pDeviceID;
6093         ma_format format;
6094         ma_uint32 channels;
6095         ma_channel* pChannelMap;
6096         ma_channel_mix_mode channelMixMode;
6097         ma_share_mode shareMode;
6098     } playback;
6099     struct
6100     {
6101         const ma_device_id* pDeviceID;
6102         ma_format format;
6103         ma_uint32 channels;
6104         ma_channel* pChannelMap;
6105         ma_channel_mix_mode channelMixMode;
6106         ma_share_mode shareMode;
6107     } capture;
6108
6109     struct
6110     {
6111         ma_bool8 noAutoConvertSRC;     /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */
6112         ma_bool8 noDefaultQualitySRC;  /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */
6113         ma_bool8 noAutoStreamRouting;  /* Disables automatic stream routing. */
6114         ma_bool8 noHardwareOffloading; /* Disables WASAPI's hardware offloading feature. */
6115     } wasapi;
6116     struct
6117     {
6118         ma_bool32 noMMap;           /* Disables MMap mode. */
6119         ma_bool32 noAutoFormat;     /* Opens the ALSA device with SND_PCM_NO_AUTO_FORMAT. */
6120         ma_bool32 noAutoChannels;   /* Opens the ALSA device with SND_PCM_NO_AUTO_CHANNELS. */
6121         ma_bool32 noAutoResample;   /* Opens the ALSA device with SND_PCM_NO_AUTO_RESAMPLE. */
6122     } alsa;
6123     struct
6124     {
6125         const char* pStreamNamePlayback;
6126         const char* pStreamNameCapture;
6127     } pulse;
6128     struct
6129     {
6130         ma_bool32 allowNominalSampleRateChange; /* Desktop only. When enabled, allows changing of the sample rate at the operating system level. */
6131     } coreaudio;
6132     struct
6133     {
6134         ma_opensl_stream_type streamType;
6135         ma_opensl_recording_preset recordingPreset;
6136     } opensl;
6137     struct
6138     {
6139         ma_aaudio_usage usage;
6140         ma_aaudio_content_type contentType;
6141         ma_aaudio_input_preset inputPreset;
6142     } aaudio;
6143 };
6144
6145
6146 /*
6147 The callback for handling device enumeration. This is fired from `ma_context_enumerated_devices()`.
6148
6149
6150 Parameters
6151 ----------
6152 pContext (in)
6153     A pointer to the context performing the enumeration.
6154
6155 deviceType (in)
6156     The type of the device being enumerated. This will always be either `ma_device_type_playback` or `ma_device_type_capture`.
6157
6158 pInfo (in)
6159     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,
6160     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
6161     is too inefficient.
6162
6163 pUserData (in)
6164     The user data pointer passed into `ma_context_enumerate_devices()`.
6165 */
6166 typedef ma_bool32 (* ma_enum_devices_callback_proc)(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData);
6167
6168
6169 /*
6170 Describes some basic details about a playback or capture device.
6171 */
6172 typedef struct
6173 {
6174     const ma_device_id* pDeviceID;
6175     ma_share_mode shareMode;
6176     ma_format format;
6177     ma_uint32 channels;
6178     ma_uint32 sampleRate;
6179     ma_channel channelMap[MA_MAX_CHANNELS];
6180     ma_uint32 periodSizeInFrames;
6181     ma_uint32 periodSizeInMilliseconds;
6182     ma_uint32 periodCount;
6183 } ma_device_descriptor;
6184
6185 /*
6186 These are the callbacks required to be implemented for a backend. These callbacks are grouped into two parts: context and device. There is one context
6187 to many devices. A device is created from a context.
6188
6189 The general flow goes like this:
6190
6191   1) A context is created with `onContextInit()`
6192      1a) Available devices can be enumerated with `onContextEnumerateDevices()` if required.
6193      1b) Detailed information about a device can be queried with `onContextGetDeviceInfo()` if required.
6194   2) A device is created from the context that was created in the first step using `onDeviceInit()`, and optionally a device ID that was
6195      selected from device enumeration via `onContextEnumerateDevices()`.
6196   3) A device is started or stopped with `onDeviceStart()` / `onDeviceStop()`
6197   4) Data is delivered to and from the device by the backend. This is always done based on the native format returned by the prior call
6198      to `onDeviceInit()`. Conversion between the device's native format and the format requested by the application will be handled by
6199      miniaudio internally.
6200
6201 Initialization of the context is quite simple. You need to do any necessary initialization of internal objects and then output the
6202 callbacks defined in this structure.
6203
6204 Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which
6205 physical devices are available. This is where `onContextEnumerateDevices()` comes in. This is fairly simple. For each device, fire the
6206 given callback with, at a minimum, the basic information filled out in `ma_device_info`. When the callback returns `MA_FALSE`, enumeration
6207 needs to stop and the `onContextEnumerateDevices()` function returns with a success code.
6208
6209 Detailed device information can be retrieved from a device ID using `onContextGetDeviceInfo()`. This takes as input the device type and ID,
6210 and on output returns detailed information about the device in `ma_device_info`. The `onContextGetDeviceInfo()` callback must handle the
6211 case when the device ID is NULL, in which case information about the default device needs to be retrieved.
6212
6213 Once the context has been created and the device ID retrieved (if using anything other than the default device), the device can be created.
6214 This is a little bit more complicated than initialization of the context due to it's more complicated configuration. When initializing a
6215 device, a duplex device may be requested. This means a separate data format needs to be specified for both playback and capture. On input,
6216 the data format is set to what the application wants. On output it's set to the native format which should match as closely as possible to
6217 the requested format. The conversion between the format requested by the application and the device's native format will be handled
6218 internally by miniaudio.
6219
6220 On input, if the sample format is set to `ma_format_unknown`, the backend is free to use whatever sample format it desires, so long as it's
6221 supported by miniaudio. When the channel count is set to 0, the backend should use the device's native channel count. The same applies for
6222 sample rate. For the channel map, the default should be used when `ma_channel_map_is_blank()` returns true (all channels set to
6223 `MA_CHANNEL_NONE`). On input, the `periodSizeInFrames` or `periodSizeInMilliseconds` option should always be set. The backend should
6224 inspect both of these variables. If `periodSizeInFrames` is set, it should take priority, otherwise it needs to be derived from the period
6225 size in milliseconds (`periodSizeInMilliseconds`) and the sample rate, keeping in mind that the sample rate may be 0, in which case the
6226 sample rate will need to be determined before calculating the period size in frames. On output, all members of the `ma_device_data_format`
6227 object should be set to a valid value, except for `periodSizeInMilliseconds` which is optional (`periodSizeInFrames` *must* be set).
6228
6229 Starting and stopping of the device is done with `onDeviceStart()` and `onDeviceStop()` and should be self-explanatory. If the backend uses
6230 asynchronous reading and writing, `onDeviceStart()` and `onDeviceStop()` should always be implemented.
6231
6232 The handling of data delivery between the application and the device is the most complicated part of the process. To make this a bit
6233 easier, some helper callbacks are available. If the backend uses a blocking read/write style of API, the `onDeviceRead()` and
6234 `onDeviceWrite()` callbacks can optionally be implemented. These are blocking and work just like reading and writing from a file. If the
6235 backend uses a callback for data delivery, that callback must call `ma_device_handle_backend_data_callback()` from within it's callback.
6236 This allows miniaudio to then process any necessary data conversion and then pass it to the miniaudio data callback.
6237
6238 If the backend requires absolute flexibility with it's data delivery, it can optionally implement the `onDeviceDataLoop()` callback
6239 which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional.
6240
6241 The audio thread should run data delivery logic in a loop while `ma_device_get_state() == ma_device_state_started` and no errors have been
6242 encounted. Do not start or stop the device here. That will be handled from outside the `onDeviceDataLoop()` callback.
6243
6244 The invocation of the `onDeviceDataLoop()` callback will be handled by miniaudio. When you start the device, miniaudio will fire this
6245 callback. When the device is stopped, the `ma_device_get_state() == ma_device_state_started` condition will fail and the loop will be terminated
6246 which will then fall through to the part that stops the device. For an example on how to implement the `onDeviceDataLoop()` callback,
6247 look at `ma_device_audio_thread__default_read_write()`. Implement the `onDeviceDataLoopWakeup()` callback if you need a mechanism to
6248 wake up the audio thread.
6249
6250 If the backend supports an optimized retrieval of device information from an initialized `ma_device` object, it should implement the
6251 `onDeviceGetInfo()` callback. This is optional, in which case it will fall back to `onContextGetDeviceInfo()` which is less efficient.
6252 */
6253 struct ma_backend_callbacks
6254 {
6255     ma_result (* onContextInit)(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks);
6256     ma_result (* onContextUninit)(ma_context* pContext);
6257     ma_result (* onContextEnumerateDevices)(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData);
6258     ma_result (* onContextGetDeviceInfo)(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo);
6259     ma_result (* onDeviceInit)(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture);
6260     ma_result (* onDeviceUninit)(ma_device* pDevice);
6261     ma_result (* onDeviceStart)(ma_device* pDevice);
6262     ma_result (* onDeviceStop)(ma_device* pDevice);
6263     ma_result (* onDeviceRead)(ma_device* pDevice, void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesRead);
6264     ma_result (* onDeviceWrite)(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten);
6265     ma_result (* onDeviceDataLoop)(ma_device* pDevice);
6266     ma_result (* onDeviceDataLoopWakeup)(ma_device* pDevice);
6267     ma_result (* onDeviceGetInfo)(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo);
6268 };
6269
6270 struct ma_context_config
6271 {
6272     ma_log* pLog;
6273     ma_thread_priority threadPriority;
6274     size_t threadStackSize;
6275     void* pUserData;
6276     ma_allocation_callbacks allocationCallbacks;
6277     struct
6278     {
6279         ma_bool32 useVerboseDeviceEnumeration;
6280     } alsa;
6281     struct
6282     {
6283         const char* pApplicationName;
6284         const char* pServerName;
6285         ma_bool32 tryAutoSpawn; /* Enables autospawning of the PulseAudio daemon if necessary. */
6286     } pulse;
6287     struct
6288     {
6289         ma_ios_session_category sessionCategory;
6290         ma_uint32 sessionCategoryOptions;
6291         ma_bool32 noAudioSessionActivate;   /* iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:true] on initialization. */
6292         ma_bool32 noAudioSessionDeactivate; /* iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:false] on uninitialization. */
6293     } coreaudio;
6294     struct
6295     {
6296         const char* pClientName;
6297         ma_bool32 tryStartServer;
6298     } jack;
6299     ma_backend_callbacks custom;
6300 };
6301
6302 /* WASAPI specific structure for some commands which must run on a common thread due to bugs in WASAPI. */
6303 typedef struct
6304 {
6305     int code;
6306     ma_event* pEvent;   /* This will be signalled when the event is complete. */
6307     union
6308     {
6309         struct
6310         {
6311             int _unused;
6312         } quit;
6313         struct
6314         {
6315             ma_device_type deviceType;
6316             void* pAudioClient;
6317             void** ppAudioClientService;
6318             ma_result* pResult; /* The result from creating the audio client service. */
6319         } createAudioClient;
6320         struct
6321         {
6322             ma_device* pDevice;
6323             ma_device_type deviceType;
6324         } releaseAudioClient;
6325     } data;
6326 } ma_context_command__wasapi;
6327
6328 struct ma_context
6329 {
6330     ma_backend_callbacks callbacks;
6331     ma_backend backend;                 /* DirectSound, ALSA, etc. */
6332     ma_log* pLog;
6333     ma_log log; /* Only used if the log is owned by the context. The pLog member will be set to &log in this case. */
6334     ma_thread_priority threadPriority;
6335     size_t threadStackSize;
6336     void* pUserData;
6337     ma_allocation_callbacks allocationCallbacks;
6338     ma_mutex deviceEnumLock;            /* Used to make ma_context_get_devices() thread safe. */
6339     ma_mutex deviceInfoLock;            /* Used to make ma_context_get_device_info() thread safe. */
6340     ma_uint32 deviceInfoCapacity;       /* Total capacity of pDeviceInfos. */
6341     ma_uint32 playbackDeviceInfoCount;
6342     ma_uint32 captureDeviceInfoCount;
6343     ma_device_info* pDeviceInfos;       /* Playback devices first, then capture. */
6344
6345     union
6346     {
6347 #ifdef MA_SUPPORT_WASAPI
6348         struct
6349         {
6350             ma_thread commandThread;
6351             ma_mutex commandLock;
6352             ma_semaphore commandSem;
6353             ma_uint32 commandIndex;
6354             ma_uint32 commandCount;
6355             ma_context_command__wasapi commands[4];
6356         } wasapi;
6357 #endif
6358 #ifdef MA_SUPPORT_DSOUND
6359         struct
6360         {
6361             ma_handle hDSoundDLL;
6362             ma_proc DirectSoundCreate;
6363             ma_proc DirectSoundEnumerateA;
6364             ma_proc DirectSoundCaptureCreate;
6365             ma_proc DirectSoundCaptureEnumerateA;
6366         } dsound;
6367 #endif
6368 #ifdef MA_SUPPORT_WINMM
6369         struct
6370         {
6371             ma_handle hWinMM;
6372             ma_proc waveOutGetNumDevs;
6373             ma_proc waveOutGetDevCapsA;
6374             ma_proc waveOutOpen;
6375             ma_proc waveOutClose;
6376             ma_proc waveOutPrepareHeader;
6377             ma_proc waveOutUnprepareHeader;
6378             ma_proc waveOutWrite;
6379             ma_proc waveOutReset;
6380             ma_proc waveInGetNumDevs;
6381             ma_proc waveInGetDevCapsA;
6382             ma_proc waveInOpen;
6383             ma_proc waveInClose;
6384             ma_proc waveInPrepareHeader;
6385             ma_proc waveInUnprepareHeader;
6386             ma_proc waveInAddBuffer;
6387             ma_proc waveInStart;
6388             ma_proc waveInReset;
6389         } winmm;
6390 #endif
6391 #ifdef MA_SUPPORT_ALSA
6392         struct
6393         {
6394             ma_handle asoundSO;
6395             ma_proc snd_pcm_open;
6396             ma_proc snd_pcm_close;
6397             ma_proc snd_pcm_hw_params_sizeof;
6398             ma_proc snd_pcm_hw_params_any;
6399             ma_proc snd_pcm_hw_params_set_format;
6400             ma_proc snd_pcm_hw_params_set_format_first;
6401             ma_proc snd_pcm_hw_params_get_format_mask;
6402             ma_proc snd_pcm_hw_params_set_channels;
6403             ma_proc snd_pcm_hw_params_set_channels_near;
6404             ma_proc snd_pcm_hw_params_set_channels_minmax;
6405             ma_proc snd_pcm_hw_params_set_rate_resample;
6406             ma_proc snd_pcm_hw_params_set_rate;
6407             ma_proc snd_pcm_hw_params_set_rate_near;
6408             ma_proc snd_pcm_hw_params_set_buffer_size_near;
6409             ma_proc snd_pcm_hw_params_set_periods_near;
6410             ma_proc snd_pcm_hw_params_set_access;
6411             ma_proc snd_pcm_hw_params_get_format;
6412             ma_proc snd_pcm_hw_params_get_channels;
6413             ma_proc snd_pcm_hw_params_get_channels_min;
6414             ma_proc snd_pcm_hw_params_get_channels_max;
6415             ma_proc snd_pcm_hw_params_get_rate;
6416             ma_proc snd_pcm_hw_params_get_rate_min;
6417             ma_proc snd_pcm_hw_params_get_rate_max;
6418             ma_proc snd_pcm_hw_params_get_buffer_size;
6419             ma_proc snd_pcm_hw_params_get_periods;
6420             ma_proc snd_pcm_hw_params_get_access;
6421             ma_proc snd_pcm_hw_params_test_format;
6422             ma_proc snd_pcm_hw_params_test_channels;
6423             ma_proc snd_pcm_hw_params_test_rate;
6424             ma_proc snd_pcm_hw_params;
6425             ma_proc snd_pcm_sw_params_sizeof;
6426             ma_proc snd_pcm_sw_params_current;
6427             ma_proc snd_pcm_sw_params_get_boundary;
6428             ma_proc snd_pcm_sw_params_set_avail_min;
6429             ma_proc snd_pcm_sw_params_set_start_threshold;
6430             ma_proc snd_pcm_sw_params_set_stop_threshold;
6431             ma_proc snd_pcm_sw_params;
6432             ma_proc snd_pcm_format_mask_sizeof;
6433             ma_proc snd_pcm_format_mask_test;
6434             ma_proc snd_pcm_get_chmap;
6435             ma_proc snd_pcm_state;
6436             ma_proc snd_pcm_prepare;
6437             ma_proc snd_pcm_start;
6438             ma_proc snd_pcm_drop;
6439             ma_proc snd_pcm_drain;
6440             ma_proc snd_pcm_reset;
6441             ma_proc snd_device_name_hint;
6442             ma_proc snd_device_name_get_hint;
6443             ma_proc snd_card_get_index;
6444             ma_proc snd_device_name_free_hint;
6445             ma_proc snd_pcm_mmap_begin;
6446             ma_proc snd_pcm_mmap_commit;
6447             ma_proc snd_pcm_recover;
6448             ma_proc snd_pcm_readi;
6449             ma_proc snd_pcm_writei;
6450             ma_proc snd_pcm_avail;
6451             ma_proc snd_pcm_avail_update;
6452             ma_proc snd_pcm_wait;
6453             ma_proc snd_pcm_nonblock;
6454             ma_proc snd_pcm_info;
6455             ma_proc snd_pcm_info_sizeof;
6456             ma_proc snd_pcm_info_get_name;
6457             ma_proc snd_pcm_poll_descriptors;
6458             ma_proc snd_pcm_poll_descriptors_count;
6459             ma_proc snd_pcm_poll_descriptors_revents;
6460             ma_proc snd_config_update_free_global;
6461
6462             ma_mutex internalDeviceEnumLock;
6463             ma_bool32 useVerboseDeviceEnumeration;
6464         } alsa;
6465 #endif
6466 #ifdef MA_SUPPORT_PULSEAUDIO
6467         struct
6468         {
6469             ma_handle pulseSO;
6470             ma_proc pa_mainloop_new;
6471             ma_proc pa_mainloop_free;
6472             ma_proc pa_mainloop_quit;
6473             ma_proc pa_mainloop_get_api;
6474             ma_proc pa_mainloop_iterate;
6475             ma_proc pa_mainloop_wakeup;
6476             ma_proc pa_threaded_mainloop_new;
6477             ma_proc pa_threaded_mainloop_free;
6478             ma_proc pa_threaded_mainloop_start;
6479             ma_proc pa_threaded_mainloop_stop;
6480             ma_proc pa_threaded_mainloop_lock;
6481             ma_proc pa_threaded_mainloop_unlock;
6482             ma_proc pa_threaded_mainloop_wait;
6483             ma_proc pa_threaded_mainloop_signal;
6484             ma_proc pa_threaded_mainloop_accept;
6485             ma_proc pa_threaded_mainloop_get_retval;
6486             ma_proc pa_threaded_mainloop_get_api;
6487             ma_proc pa_threaded_mainloop_in_thread;
6488             ma_proc pa_threaded_mainloop_set_name;
6489             ma_proc pa_context_new;
6490             ma_proc pa_context_unref;
6491             ma_proc pa_context_connect;
6492             ma_proc pa_context_disconnect;
6493             ma_proc pa_context_set_state_callback;
6494             ma_proc pa_context_get_state;
6495             ma_proc pa_context_get_sink_info_list;
6496             ma_proc pa_context_get_source_info_list;
6497             ma_proc pa_context_get_sink_info_by_name;
6498             ma_proc pa_context_get_source_info_by_name;
6499             ma_proc pa_operation_unref;
6500             ma_proc pa_operation_get_state;
6501             ma_proc pa_channel_map_init_extend;
6502             ma_proc pa_channel_map_valid;
6503             ma_proc pa_channel_map_compatible;
6504             ma_proc pa_stream_new;
6505             ma_proc pa_stream_unref;
6506             ma_proc pa_stream_connect_playback;
6507             ma_proc pa_stream_connect_record;
6508             ma_proc pa_stream_disconnect;
6509             ma_proc pa_stream_get_state;
6510             ma_proc pa_stream_get_sample_spec;
6511             ma_proc pa_stream_get_channel_map;
6512             ma_proc pa_stream_get_buffer_attr;
6513             ma_proc pa_stream_set_buffer_attr;
6514             ma_proc pa_stream_get_device_name;
6515             ma_proc pa_stream_set_write_callback;
6516             ma_proc pa_stream_set_read_callback;
6517             ma_proc pa_stream_set_suspended_callback;
6518             ma_proc pa_stream_set_moved_callback;
6519             ma_proc pa_stream_is_suspended;
6520             ma_proc pa_stream_flush;
6521             ma_proc pa_stream_drain;
6522             ma_proc pa_stream_is_corked;
6523             ma_proc pa_stream_cork;
6524             ma_proc pa_stream_trigger;
6525             ma_proc pa_stream_begin_write;
6526             ma_proc pa_stream_write;
6527             ma_proc pa_stream_peek;
6528             ma_proc pa_stream_drop;
6529             ma_proc pa_stream_writable_size;
6530             ma_proc pa_stream_readable_size;
6531
6532             /*pa_mainloop**/ ma_ptr pMainLoop;
6533             /*pa_context**/ ma_ptr pPulseContext;
6534             char* pApplicationName; /* Set when the context is initialized. Used by devices for their local pa_context objects. */
6535             char* pServerName;      /* Set when the context is initialized. Used by devices for their local pa_context objects. */
6536         } pulse;
6537 #endif
6538 #ifdef MA_SUPPORT_JACK
6539         struct
6540         {
6541             ma_handle jackSO;
6542             ma_proc jack_client_open;
6543             ma_proc jack_client_close;
6544             ma_proc jack_client_name_size;
6545             ma_proc jack_set_process_callback;
6546             ma_proc jack_set_buffer_size_callback;
6547             ma_proc jack_on_shutdown;
6548             ma_proc jack_get_sample_rate;
6549             ma_proc jack_get_buffer_size;
6550             ma_proc jack_get_ports;
6551             ma_proc jack_activate;
6552             ma_proc jack_deactivate;
6553             ma_proc jack_connect;
6554             ma_proc jack_port_register;
6555             ma_proc jack_port_name;
6556             ma_proc jack_port_get_buffer;
6557             ma_proc jack_free;
6558
6559             char* pClientName;
6560             ma_bool32 tryStartServer;
6561         } jack;
6562 #endif
6563 #ifdef MA_SUPPORT_COREAUDIO
6564         struct
6565         {
6566             ma_handle hCoreFoundation;
6567             ma_proc CFStringGetCString;
6568             ma_proc CFRelease;
6569
6570             ma_handle hCoreAudio;
6571             ma_proc AudioObjectGetPropertyData;
6572             ma_proc AudioObjectGetPropertyDataSize;
6573             ma_proc AudioObjectSetPropertyData;
6574             ma_proc AudioObjectAddPropertyListener;
6575             ma_proc AudioObjectRemovePropertyListener;
6576
6577             ma_handle hAudioUnit;  /* Could possibly be set to AudioToolbox on later versions of macOS. */
6578             ma_proc AudioComponentFindNext;
6579             ma_proc AudioComponentInstanceDispose;
6580             ma_proc AudioComponentInstanceNew;
6581             ma_proc AudioOutputUnitStart;
6582             ma_proc AudioOutputUnitStop;
6583             ma_proc AudioUnitAddPropertyListener;
6584             ma_proc AudioUnitGetPropertyInfo;
6585             ma_proc AudioUnitGetProperty;
6586             ma_proc AudioUnitSetProperty;
6587             ma_proc AudioUnitInitialize;
6588             ma_proc AudioUnitRender;
6589
6590             /*AudioComponent*/ ma_ptr component;
6591             ma_bool32 noAudioSessionDeactivate; /* For tracking whether or not the iOS audio session should be explicitly deactivated. Set from the config in ma_context_init__coreaudio(). */
6592         } coreaudio;
6593 #endif
6594 #ifdef MA_SUPPORT_SNDIO
6595         struct
6596         {
6597             ma_handle sndioSO;
6598             ma_proc sio_open;
6599             ma_proc sio_close;
6600             ma_proc sio_setpar;
6601             ma_proc sio_getpar;
6602             ma_proc sio_getcap;
6603             ma_proc sio_start;
6604             ma_proc sio_stop;
6605             ma_proc sio_read;
6606             ma_proc sio_write;
6607             ma_proc sio_onmove;
6608             ma_proc sio_nfds;
6609             ma_proc sio_pollfd;
6610             ma_proc sio_revents;
6611             ma_proc sio_eof;
6612             ma_proc sio_setvol;
6613             ma_proc sio_onvol;
6614             ma_proc sio_initpar;
6615         } sndio;
6616 #endif
6617 #ifdef MA_SUPPORT_AUDIO4
6618         struct
6619         {
6620             int _unused;
6621         } audio4;
6622 #endif
6623 #ifdef MA_SUPPORT_OSS
6624         struct
6625         {
6626             int versionMajor;
6627             int versionMinor;
6628         } oss;
6629 #endif
6630 #ifdef MA_SUPPORT_AAUDIO
6631         struct
6632         {
6633             ma_handle hAAudio; /* libaaudio.so */
6634             ma_proc AAudio_createStreamBuilder;
6635             ma_proc AAudioStreamBuilder_delete;
6636             ma_proc AAudioStreamBuilder_setDeviceId;
6637             ma_proc AAudioStreamBuilder_setDirection;
6638             ma_proc AAudioStreamBuilder_setSharingMode;
6639             ma_proc AAudioStreamBuilder_setFormat;
6640             ma_proc AAudioStreamBuilder_setChannelCount;
6641             ma_proc AAudioStreamBuilder_setSampleRate;
6642             ma_proc AAudioStreamBuilder_setBufferCapacityInFrames;
6643             ma_proc AAudioStreamBuilder_setFramesPerDataCallback;
6644             ma_proc AAudioStreamBuilder_setDataCallback;
6645             ma_proc AAudioStreamBuilder_setErrorCallback;
6646             ma_proc AAudioStreamBuilder_setPerformanceMode;
6647             ma_proc AAudioStreamBuilder_setUsage;
6648             ma_proc AAudioStreamBuilder_setContentType;
6649             ma_proc AAudioStreamBuilder_setInputPreset;
6650             ma_proc AAudioStreamBuilder_openStream;
6651             ma_proc AAudioStream_close;
6652             ma_proc AAudioStream_getState;
6653             ma_proc AAudioStream_waitForStateChange;
6654             ma_proc AAudioStream_getFormat;
6655             ma_proc AAudioStream_getChannelCount;
6656             ma_proc AAudioStream_getSampleRate;
6657             ma_proc AAudioStream_getBufferCapacityInFrames;
6658             ma_proc AAudioStream_getFramesPerDataCallback;
6659             ma_proc AAudioStream_getFramesPerBurst;
6660             ma_proc AAudioStream_requestStart;
6661             ma_proc AAudioStream_requestStop;
6662         } aaudio;
6663 #endif
6664 #ifdef MA_SUPPORT_OPENSL
6665         struct
6666         {
6667             ma_handle libOpenSLES;
6668             ma_handle SL_IID_ENGINE;
6669             ma_handle SL_IID_AUDIOIODEVICECAPABILITIES;
6670             ma_handle SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
6671             ma_handle SL_IID_RECORD;
6672             ma_handle SL_IID_PLAY;
6673             ma_handle SL_IID_OUTPUTMIX;
6674             ma_handle SL_IID_ANDROIDCONFIGURATION;
6675             ma_proc   slCreateEngine;
6676         } opensl;
6677 #endif
6678 #ifdef MA_SUPPORT_WEBAUDIO
6679         struct
6680         {
6681             int _unused;
6682         } webaudio;
6683 #endif
6684 #ifdef MA_SUPPORT_NULL
6685         struct
6686         {
6687             int _unused;
6688         } null_backend;
6689 #endif
6690     };
6691
6692     union
6693     {
6694 #ifdef MA_WIN32
6695         struct
6696         {
6697             /*HMODULE*/ ma_handle hOle32DLL;
6698             ma_proc CoInitializeEx;
6699             ma_proc CoUninitialize;
6700             ma_proc CoCreateInstance;
6701             ma_proc CoTaskMemFree;
6702             ma_proc PropVariantClear;
6703             ma_proc StringFromGUID2;
6704
6705             /*HMODULE*/ ma_handle hUser32DLL;
6706             ma_proc GetForegroundWindow;
6707             ma_proc GetDesktopWindow;
6708
6709             /*HMODULE*/ ma_handle hAdvapi32DLL;
6710             ma_proc RegOpenKeyExA;
6711             ma_proc RegCloseKey;
6712             ma_proc RegQueryValueExA;
6713         } win32;
6714 #endif
6715 #ifdef MA_POSIX
6716         struct
6717         {
6718             ma_handle pthreadSO;
6719             ma_proc pthread_create;
6720             ma_proc pthread_join;
6721             ma_proc pthread_mutex_init;
6722             ma_proc pthread_mutex_destroy;
6723             ma_proc pthread_mutex_lock;
6724             ma_proc pthread_mutex_unlock;
6725             ma_proc pthread_cond_init;
6726             ma_proc pthread_cond_destroy;
6727             ma_proc pthread_cond_wait;
6728             ma_proc pthread_cond_signal;
6729             ma_proc pthread_attr_init;
6730             ma_proc pthread_attr_destroy;
6731             ma_proc pthread_attr_setschedpolicy;
6732             ma_proc pthread_attr_getschedparam;
6733             ma_proc pthread_attr_setschedparam;
6734         } posix;
6735 #endif
6736         int _unused;
6737     };
6738 };
6739
6740 struct ma_device
6741 {
6742     ma_context* pContext;
6743     ma_device_type type;
6744     ma_uint32 sampleRate;
6745     MA_ATOMIC(4, ma_device_state) state;        /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */
6746     ma_device_data_proc onData;                 /* Set once at initialization time and should not be changed after. */
6747     ma_device_notification_proc onNotification; /* Set once at initialization time and should not be changed after. */
6748     ma_stop_proc onStop;                        /* DEPRECATED. Use the notification callback instead. Set once at initialization time and should not be changed after. */
6749     void* pUserData;                            /* Application defined data. */
6750     ma_mutex startStopLock;
6751     ma_event wakeupEvent;
6752     ma_event startEvent;
6753     ma_event stopEvent;
6754     ma_thread thread;
6755     ma_result workResult;                       /* This is set by the worker thread after it's finished doing a job. */
6756     ma_bool8 isOwnerOfContext;                  /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */
6757     ma_bool8 noPreSilencedOutputBuffer;
6758     ma_bool8 noClip;
6759     ma_bool8 noDisableDenormals;
6760     MA_ATOMIC(4, float) masterVolumeFactor;     /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */
6761     ma_duplex_rb duplexRB;                      /* Intermediary buffer for duplex device on asynchronous backends. */
6762     struct
6763     {
6764         ma_resample_algorithm algorithm;
6765         ma_resampling_backend_vtable* pBackendVTable;
6766         void* pBackendUserData;
6767         struct
6768         {
6769             ma_uint32 lpfOrder;
6770         } linear;
6771     } resampling;
6772     struct
6773     {
6774         ma_device_id id;                    /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
6775         char name[MA_MAX_DEVICE_NAME_LENGTH + 1];                     /* Maybe temporary. Likely to be replaced with a query API. */
6776         ma_share_mode shareMode;            /* Set to whatever was passed in when the device was initialized. */
6777         ma_format format;
6778         ma_uint32 channels;
6779         ma_channel channelMap[MA_MAX_CHANNELS];
6780         ma_format internalFormat;
6781         ma_uint32 internalChannels;
6782         ma_uint32 internalSampleRate;
6783         ma_channel internalChannelMap[MA_MAX_CHANNELS];
6784         ma_uint32 internalPeriodSizeInFrames;
6785         ma_uint32 internalPeriods;
6786         ma_channel_mix_mode channelMixMode;
6787         ma_data_converter converter;
6788         void* pInputCache;                  /* In external format. Can be null. */
6789         ma_uint64 inputCacheCap;
6790         ma_uint64 inputCacheConsumed;
6791         ma_uint64 inputCacheRemaining;
6792     } playback;
6793     struct
6794     {
6795         ma_device_id id;                    /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
6796         char name[MA_MAX_DEVICE_NAME_LENGTH + 1];                     /* Maybe temporary. Likely to be replaced with a query API. */
6797         ma_share_mode shareMode;            /* Set to whatever was passed in when the device was initialized. */
6798         ma_format format;
6799         ma_uint32 channels;
6800         ma_channel channelMap[MA_MAX_CHANNELS];
6801         ma_format internalFormat;
6802         ma_uint32 internalChannels;
6803         ma_uint32 internalSampleRate;
6804         ma_channel internalChannelMap[MA_MAX_CHANNELS];
6805         ma_uint32 internalPeriodSizeInFrames;
6806         ma_uint32 internalPeriods;
6807         ma_channel_mix_mode channelMixMode;
6808         ma_data_converter converter;
6809     } capture;
6810
6811     union
6812     {
6813 #ifdef MA_SUPPORT_WASAPI
6814         struct
6815         {
6816             /*IAudioClient**/ ma_ptr pAudioClientPlayback;
6817             /*IAudioClient**/ ma_ptr pAudioClientCapture;
6818             /*IAudioRenderClient**/ ma_ptr pRenderClient;
6819             /*IAudioCaptureClient**/ ma_ptr pCaptureClient;
6820             /*IMMDeviceEnumerator**/ ma_ptr pDeviceEnumerator;      /* Used for IMMNotificationClient notifications. Required for detecting default device changes. */
6821             ma_IMMNotificationClient notificationClient;
6822             /*HANDLE*/ ma_handle hEventPlayback;                    /* Auto reset. Initialized to signaled. */
6823             /*HANDLE*/ ma_handle hEventCapture;                     /* Auto reset. Initialized to unsignaled. */
6824             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. */
6825             ma_uint32 actualPeriodSizeInFramesCapture;
6826             ma_uint32 originalPeriodSizeInFrames;
6827             ma_uint32 originalPeriodSizeInMilliseconds;
6828             ma_uint32 originalPeriods;
6829             ma_performance_profile originalPerformanceProfile;
6830             ma_uint32 periodSizeInFramesPlayback;
6831             ma_uint32 periodSizeInFramesCapture;
6832             MA_ATOMIC(4, ma_bool32) isStartedCapture;               /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
6833             MA_ATOMIC(4, ma_bool32) isStartedPlayback;              /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
6834             ma_bool8 noAutoConvertSRC;                              /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */
6835             ma_bool8 noDefaultQualitySRC;                           /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */
6836             ma_bool8 noHardwareOffloading;
6837             ma_bool8 allowCaptureAutoStreamRouting;
6838             ma_bool8 allowPlaybackAutoStreamRouting;
6839             ma_bool8 isDetachedPlayback;
6840             ma_bool8 isDetachedCapture;
6841         } wasapi;
6842 #endif
6843 #ifdef MA_SUPPORT_DSOUND
6844         struct
6845         {
6846             /*LPDIRECTSOUND*/ ma_ptr pPlayback;
6847             /*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackPrimaryBuffer;
6848             /*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackBuffer;
6849             /*LPDIRECTSOUNDCAPTURE*/ ma_ptr pCapture;
6850             /*LPDIRECTSOUNDCAPTUREBUFFER*/ ma_ptr pCaptureBuffer;
6851         } dsound;
6852 #endif
6853 #ifdef MA_SUPPORT_WINMM
6854         struct
6855         {
6856             /*HWAVEOUT*/ ma_handle hDevicePlayback;
6857             /*HWAVEIN*/ ma_handle hDeviceCapture;
6858             /*HANDLE*/ ma_handle hEventPlayback;
6859             /*HANDLE*/ ma_handle hEventCapture;
6860             ma_uint32 fragmentSizeInFrames;
6861             ma_uint32 iNextHeaderPlayback;             /* [0,periods). Used as an index into pWAVEHDRPlayback. */
6862             ma_uint32 iNextHeaderCapture;              /* [0,periods). Used as an index into pWAVEHDRCapture. */
6863             ma_uint32 headerFramesConsumedPlayback;    /* The number of PCM frames consumed in the buffer in pWAVEHEADER[iNextHeader]. */
6864             ma_uint32 headerFramesConsumedCapture;     /* ^^^ */
6865             /*WAVEHDR**/ ma_uint8* pWAVEHDRPlayback;   /* One instantiation for each period. */
6866             /*WAVEHDR**/ ma_uint8* pWAVEHDRCapture;    /* One instantiation for each period. */
6867             ma_uint8* pIntermediaryBufferPlayback;
6868             ma_uint8* pIntermediaryBufferCapture;
6869             ma_uint8* _pHeapData;                      /* Used internally and is used for the heap allocated data for the intermediary buffer and the WAVEHDR structures. */
6870         } winmm;
6871 #endif
6872 #ifdef MA_SUPPORT_ALSA
6873         struct
6874         {
6875             /*snd_pcm_t**/ ma_ptr pPCMPlayback;
6876             /*snd_pcm_t**/ ma_ptr pPCMCapture;
6877             /*struct pollfd**/ void* pPollDescriptorsPlayback;
6878             /*struct pollfd**/ void* pPollDescriptorsCapture;
6879             int pollDescriptorCountPlayback;
6880             int pollDescriptorCountCapture;
6881             int wakeupfdPlayback;   /* eventfd for waking up from poll() when the playback device is stopped. */
6882             int wakeupfdCapture;    /* eventfd for waking up from poll() when the capture device is stopped. */
6883             ma_bool8 isUsingMMapPlayback;
6884             ma_bool8 isUsingMMapCapture;
6885         } alsa;
6886 #endif
6887 #ifdef MA_SUPPORT_PULSEAUDIO
6888         struct
6889         {
6890             /*pa_mainloop**/ ma_ptr pMainLoop;
6891             /*pa_context**/ ma_ptr pPulseContext;
6892             /*pa_stream**/ ma_ptr pStreamPlayback;
6893             /*pa_stream**/ ma_ptr pStreamCapture;
6894         } pulse;
6895 #endif
6896 #ifdef MA_SUPPORT_JACK
6897         struct
6898         {
6899             /*jack_client_t**/ ma_ptr pClient;
6900             /*jack_port_t**/ ma_ptr* ppPortsPlayback;
6901             /*jack_port_t**/ ma_ptr* ppPortsCapture;
6902             float* pIntermediaryBufferPlayback; /* Typed as a float because JACK is always floating point. */
6903             float* pIntermediaryBufferCapture;
6904         } jack;
6905 #endif
6906 #ifdef MA_SUPPORT_COREAUDIO
6907         struct
6908         {
6909             ma_uint32 deviceObjectIDPlayback;
6910             ma_uint32 deviceObjectIDCapture;
6911             /*AudioUnit*/ ma_ptr audioUnitPlayback;
6912             /*AudioUnit*/ ma_ptr audioUnitCapture;
6913             /*AudioBufferList**/ ma_ptr pAudioBufferList;   /* Only used for input devices. */
6914             ma_uint32 audioBufferCapInFrames;               /* Only used for input devices. The capacity in frames of each buffer in pAudioBufferList. */
6915             ma_event stopEvent;
6916             ma_uint32 originalPeriodSizeInFrames;
6917             ma_uint32 originalPeriodSizeInMilliseconds;
6918             ma_uint32 originalPeriods;
6919             ma_performance_profile originalPerformanceProfile;
6920             ma_bool32 isDefaultPlaybackDevice;
6921             ma_bool32 isDefaultCaptureDevice;
6922             ma_bool32 isSwitchingPlaybackDevice;   /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */
6923             ma_bool32 isSwitchingCaptureDevice;    /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */
6924             void* pNotificationHandler;             /* Only used on mobile platforms. Obj-C object for handling route changes. */
6925         } coreaudio;
6926 #endif
6927 #ifdef MA_SUPPORT_SNDIO
6928         struct
6929         {
6930             ma_ptr handlePlayback;
6931             ma_ptr handleCapture;
6932             ma_bool32 isStartedPlayback;
6933             ma_bool32 isStartedCapture;
6934         } sndio;
6935 #endif
6936 #ifdef MA_SUPPORT_AUDIO4
6937         struct
6938         {
6939             int fdPlayback;
6940             int fdCapture;
6941         } audio4;
6942 #endif
6943 #ifdef MA_SUPPORT_OSS
6944         struct
6945         {
6946             int fdPlayback;
6947             int fdCapture;
6948         } oss;
6949 #endif
6950 #ifdef MA_SUPPORT_AAUDIO
6951         struct
6952         {
6953             /*AAudioStream**/ ma_ptr pStreamPlayback;
6954             /*AAudioStream**/ ma_ptr pStreamCapture;
6955         } aaudio;
6956 #endif
6957 #ifdef MA_SUPPORT_OPENSL
6958         struct
6959         {
6960             /*SLObjectItf*/ ma_ptr pOutputMixObj;
6961             /*SLOutputMixItf*/ ma_ptr pOutputMix;
6962             /*SLObjectItf*/ ma_ptr pAudioPlayerObj;
6963             /*SLPlayItf*/ ma_ptr pAudioPlayer;
6964             /*SLObjectItf*/ ma_ptr pAudioRecorderObj;
6965             /*SLRecordItf*/ ma_ptr pAudioRecorder;
6966             /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueuePlayback;
6967             /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueueCapture;
6968             ma_bool32 isDrainingCapture;
6969             ma_bool32 isDrainingPlayback;
6970             ma_uint32 currentBufferIndexPlayback;
6971             ma_uint32 currentBufferIndexCapture;
6972             ma_uint8* pBufferPlayback;      /* This is malloc()'d and is used for storing audio data. Typed as ma_uint8 for easy offsetting. */
6973             ma_uint8* pBufferCapture;
6974         } opensl;
6975 #endif
6976 #ifdef MA_SUPPORT_WEBAUDIO
6977         struct
6978         {
6979             int indexPlayback;              /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */
6980             int indexCapture;
6981         } webaudio;
6982 #endif
6983 #ifdef MA_SUPPORT_NULL
6984         struct
6985         {
6986             ma_thread deviceThread;
6987             ma_event operationEvent;
6988             ma_event operationCompletionEvent;
6989             ma_semaphore operationSemaphore;
6990             ma_uint32 operation;
6991             ma_result operationResult;
6992             ma_timer timer;
6993             double priorRunTime;
6994             ma_uint32 currentPeriodFramesRemainingPlayback;
6995             ma_uint32 currentPeriodFramesRemainingCapture;
6996             ma_uint64 lastProcessedFramePlayback;
6997             ma_uint64 lastProcessedFrameCapture;
6998             MA_ATOMIC(4, ma_bool32) isStarted;  /* Read and written by multiple threads. Must be used atomically, and must be 32-bit for compiler compatibility. */
6999         } null_device;
7000 #endif
7001     };
7002 };
7003 #if defined(_MSC_VER) && !defined(__clang__)
7004     #pragma warning(pop)
7005 #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
7006     #pragma GCC diagnostic pop  /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
7007 #endif
7008
7009 /*
7010 Initializes a `ma_context_config` object.
7011
7012
7013 Return Value
7014 ------------
7015 A `ma_context_config` initialized to defaults.
7016
7017
7018 Remarks
7019 -------
7020 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
7021 is updated and new members are added to `ma_context_config`. It also sets logical defaults.
7022
7023 You can override members of the returned object by changing it's members directly.
7024
7025
7026 See Also
7027 --------
7028 ma_context_init()
7029 */
7030 MA_API ma_context_config ma_context_config_init(void);
7031
7032 /*
7033 Initializes a context.
7034
7035 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
7036 device. There is one context to many devices, and a device is created from a context. A context is required to enumerate devices.
7037
7038
7039 Parameters
7040 ----------
7041 backends (in, optional)
7042     A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order.
7043
7044 backendCount (in, optional)
7045     The number of items in `backend`. Ignored if `backend` is NULL.
7046
7047 pConfig (in, optional)
7048     The context configuration.
7049
7050 pContext (in)
7051     A pointer to the context object being initialized.
7052
7053
7054 Return Value
7055 ------------
7056 MA_SUCCESS if successful; any other error code otherwise.
7057
7058
7059 Thread Safety
7060 -------------
7061 Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
7062
7063
7064 Remarks
7065 -------
7066 When `backends` is NULL, the default priority order will be used. Below is a list of backends in priority order:
7067
7068     |-------------|-----------------------|--------------------------------------------------------|
7069     | Name        | Enum Name             | Supported Operating Systems                            |
7070     |-------------|-----------------------|--------------------------------------------------------|
7071     | WASAPI      | ma_backend_wasapi     | Windows Vista+                                         |
7072     | DirectSound | ma_backend_dsound     | Windows XP+                                            |
7073     | WinMM       | ma_backend_winmm      | Windows XP+ (may work on older versions, but untested) |
7074     | Core Audio  | ma_backend_coreaudio  | macOS, iOS                                             |
7075     | ALSA        | ma_backend_alsa       | Linux                                                  |
7076     | PulseAudio  | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android)  |
7077     | JACK        | ma_backend_jack       | Cross Platform (disabled on BSD and Android)           |
7078     | sndio       | ma_backend_sndio      | OpenBSD                                                |
7079     | audio(4)    | ma_backend_audio4     | NetBSD, OpenBSD                                        |
7080     | OSS         | ma_backend_oss        | FreeBSD                                                |
7081     | AAudio      | ma_backend_aaudio     | Android 8+                                             |
7082     | OpenSL|ES   | ma_backend_opensl     | Android (API level 16+)                                |
7083     | Web Audio   | ma_backend_webaudio   | Web (via Emscripten)                                   |
7084     | Null        | ma_backend_null       | Cross Platform (not used on Web)                       |
7085     |-------------|-----------------------|--------------------------------------------------------|
7086
7087 The context can be configured via the `pConfig` argument. The config object is initialized with `ma_context_config_init()`. Individual configuration settings
7088 can then be set directly on the structure. Below are the members of the `ma_context_config` object.
7089
7090     pLog
7091         A pointer to the `ma_log` to post log messages to. Can be NULL if the application does not
7092         require logging. See the `ma_log` API for details on how to use the logging system.
7093
7094     threadPriority
7095         The desired priority to use for the audio thread. Allowable values include the following:
7096
7097         |--------------------------------------|
7098         | Thread Priority                      |
7099         |--------------------------------------|
7100         | ma_thread_priority_idle              |
7101         | ma_thread_priority_lowest            |
7102         | ma_thread_priority_low               |
7103         | ma_thread_priority_normal            |
7104         | ma_thread_priority_high              |
7105         | ma_thread_priority_highest (default) |
7106         | ma_thread_priority_realtime          |
7107         | ma_thread_priority_default           |
7108         |--------------------------------------|
7109
7110     threadStackSize
7111         The desired size of the stack for the audio thread. Defaults to the operating system's default.
7112
7113     pUserData
7114         A pointer to application-defined data. This can be accessed from the context object directly such as `context.pUserData`.
7115
7116     allocationCallbacks
7117         Structure containing custom allocation callbacks. Leaving this at defaults will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. These allocation
7118         callbacks will be used for anything tied to the context, including devices.
7119
7120     alsa.useVerboseDeviceEnumeration
7121         ALSA will typically enumerate many different devices which can be intrusive and not user-friendly. To combat this, miniaudio will enumerate only unique
7122         card/device pairs by default. The problem with this is that you lose a bit of flexibility and control. Setting alsa.useVerboseDeviceEnumeration makes
7123         it so the ALSA backend includes all devices. Defaults to false.
7124
7125     pulse.pApplicationName
7126         PulseAudio only. The application name to use when initializing the PulseAudio context with `pa_context_new()`.
7127
7128     pulse.pServerName
7129         PulseAudio only. The name of the server to connect to with `pa_context_connect()`.
7130
7131     pulse.tryAutoSpawn
7132         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
7133         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
7134         intrusive for the end user.
7135
7136     coreaudio.sessionCategory
7137         iOS only. The session category to use for the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents.
7138
7139         |-----------------------------------------|-------------------------------------|
7140         | miniaudio Token                         | Core Audio Token                    |
7141         |-----------------------------------------|-------------------------------------|
7142         | ma_ios_session_category_ambient         | AVAudioSessionCategoryAmbient       |
7143         | ma_ios_session_category_solo_ambient    | AVAudioSessionCategorySoloAmbient   |
7144         | ma_ios_session_category_playback        | AVAudioSessionCategoryPlayback      |
7145         | ma_ios_session_category_record          | AVAudioSessionCategoryRecord        |
7146         | ma_ios_session_category_play_and_record | AVAudioSessionCategoryPlayAndRecord |
7147         | ma_ios_session_category_multi_route     | AVAudioSessionCategoryMultiRoute    |
7148         | ma_ios_session_category_none            | AVAudioSessionCategoryAmbient       |
7149         | ma_ios_session_category_default         | AVAudioSessionCategoryAmbient       |
7150         |-----------------------------------------|-------------------------------------|
7151
7152     coreaudio.sessionCategoryOptions
7153         iOS only. Session category options to use with the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents.
7154
7155         |---------------------------------------------------------------------------|------------------------------------------------------------------|
7156         | miniaudio Token                                                           | Core Audio Token                                                 |
7157         |---------------------------------------------------------------------------|------------------------------------------------------------------|
7158         | ma_ios_session_category_option_mix_with_others                            | AVAudioSessionCategoryOptionMixWithOthers                        |
7159         | ma_ios_session_category_option_duck_others                                | AVAudioSessionCategoryOptionDuckOthers                           |
7160         | ma_ios_session_category_option_allow_bluetooth                            | AVAudioSessionCategoryOptionAllowBluetooth                       |
7161         | ma_ios_session_category_option_default_to_speaker                         | AVAudioSessionCategoryOptionDefaultToSpeaker                     |
7162         | ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers |
7163         | ma_ios_session_category_option_allow_bluetooth_a2dp                       | AVAudioSessionCategoryOptionAllowBluetoothA2DP                   |
7164         | ma_ios_session_category_option_allow_air_play                             | AVAudioSessionCategoryOptionAllowAirPlay                         |
7165         |---------------------------------------------------------------------------|------------------------------------------------------------------|
7166
7167     coreaudio.noAudioSessionActivate
7168         iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:true] on initialization.
7169
7170     coreaudio.noAudioSessionDeactivate
7171         iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:false] on uninitialization.
7172
7173     jack.pClientName
7174         The name of the client to pass to `jack_client_open()`.
7175
7176     jack.tryStartServer
7177         Whether or not to try auto-starting the JACK server. Defaults to false.
7178
7179
7180 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
7181 relevant backends every time it's initialized.
7182
7183 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
7184 reason for this is that a pointer to the context is stored in the `ma_device` structure.
7185
7186
7187 Example 1 - Default Initialization
7188 ----------------------------------
7189 The example below shows how to initialize the context using the default configuration.
7190
7191 ```c
7192 ma_context context;
7193 ma_result result = ma_context_init(NULL, 0, NULL, &context);
7194 if (result != MA_SUCCESS) {
7195     // Error.
7196 }
7197 ```
7198
7199
7200 Example 2 - Custom Configuration
7201 --------------------------------
7202 The example below shows how to initialize the context using custom backend priorities and a custom configuration. In this hypothetical example, the program
7203 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
7204 want an error to be returned if no valid backend is available which they achieve by excluding the Null backend.
7205
7206 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.
7207
7208 ```c
7209 ma_backend backends[] = {
7210     ma_backend_alsa,
7211     ma_backend_pulseaudio,
7212     ma_backend_wasapi,
7213     ma_backend_dsound
7214 };
7215
7216 ma_log log;
7217 ma_log_init(&log);
7218 ma_log_register_callback(&log, ma_log_callback_init(my_log_callbac, pMyLogUserData));
7219
7220 ma_context_config config = ma_context_config_init();
7221 config.pLog = &log; // Specify a custom log object in the config so any logs that are posted from ma_context_init() are captured.
7222
7223 ma_context context;
7224 ma_result result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &config, &context);
7225 if (result != MA_SUCCESS) {
7226     // Error.
7227     if (result == MA_NO_BACKEND) {
7228         // Couldn't find an appropriate backend.
7229     }
7230 }
7231
7232 // You could also attach a log callback post-initialization:
7233 ma_log_register_callback(ma_context_get_log(&context), ma_log_callback_init(my_log_callback, pMyLogUserData));
7234 ```
7235
7236
7237 See Also
7238 --------
7239 ma_context_config_init()
7240 ma_context_uninit()
7241 */
7242 MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext);
7243
7244 /*
7245 Uninitializes a context.
7246
7247
7248 Return Value
7249 ------------
7250 MA_SUCCESS if successful; any other error code otherwise.
7251
7252
7253 Thread Safety
7254 -------------
7255 Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
7256
7257
7258 Remarks
7259 -------
7260 Results are undefined if you call this while any device created by this context is still active.
7261
7262
7263 See Also
7264 --------
7265 ma_context_init()
7266 */
7267 MA_API ma_result ma_context_uninit(ma_context* pContext);
7268
7269 /*
7270 Retrieves the size of the ma_context object.
7271
7272 This is mainly for the purpose of bindings to know how much memory to allocate.
7273 */
7274 MA_API size_t ma_context_sizeof(void);
7275
7276 /*
7277 Retrieves a pointer to the log object associated with this context.
7278
7279
7280 Remarks
7281 -------
7282 Pass the returned pointer to `ma_log_post()`, `ma_log_postv()` or `ma_log_postf()` to post a log
7283 message.
7284
7285 You can attach your own logging callback to the log with `ma_log_register_callback()`
7286
7287
7288 Return Value
7289 ------------
7290 A pointer to the `ma_log` object that the context uses to post log messages. If some error occurs,
7291 NULL will be returned.
7292 */
7293 MA_API ma_log* ma_context_get_log(ma_context* pContext);
7294
7295 /*
7296 Enumerates over every device (both playback and capture).
7297
7298 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
7299 an internal heap allocation, or it simply suits your code better.
7300
7301 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
7302 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,
7303 but don't call it from within the enumeration callback.
7304
7305 Returning false from the callback will stop enumeration. Returning true will continue enumeration.
7306
7307
7308 Parameters
7309 ----------
7310 pContext (in)
7311     A pointer to the context performing the enumeration.
7312
7313 callback (in)
7314     The callback to fire for each enumerated device.
7315
7316 pUserData (in)
7317     A pointer to application-defined data passed to the callback.
7318
7319
7320 Return Value
7321 ------------
7322 MA_SUCCESS if successful; any other error code otherwise.
7323
7324
7325 Thread Safety
7326 -------------
7327 Safe. This is guarded using a simple mutex lock.
7328
7329
7330 Remarks
7331 -------
7332 Do _not_ assume the first enumerated device of a given type is the default device.
7333
7334 Some backends and platforms may only support default playback and capture devices.
7335
7336 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,
7337 do not try to call `ma_context_get_device_info()` from within the callback.
7338
7339 Consider using `ma_context_get_devices()` for a simpler and safer API, albeit at the expense of an internal heap allocation.
7340
7341
7342 Example 1 - Simple Enumeration
7343 ------------------------------
7344 ma_bool32 ma_device_enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData)
7345 {
7346     printf("Device Name: %s\n", pInfo->name);
7347     return MA_TRUE;
7348 }
7349
7350 ma_result result = ma_context_enumerate_devices(&context, my_device_enum_callback, pMyUserData);
7351 if (result != MA_SUCCESS) {
7352     // Error.
7353 }
7354
7355
7356 See Also
7357 --------
7358 ma_context_get_devices()
7359 */
7360 MA_API ma_result ma_context_enumerate_devices(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData);
7361
7362 /*
7363 Retrieves basic information about every active playback and/or capture device.
7364
7365 This function will allocate memory internally for the device lists and return a pointer to them through the `ppPlaybackDeviceInfos` and `ppCaptureDeviceInfos`
7366 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.
7367
7368
7369 Parameters
7370 ----------
7371 pContext (in)
7372     A pointer to the context performing the enumeration.
7373
7374 ppPlaybackDeviceInfos (out)
7375     A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for playback devices.
7376
7377 pPlaybackDeviceCount (out)
7378     A pointer to an unsigned integer that will receive the number of playback devices.
7379
7380 ppCaptureDeviceInfos (out)
7381     A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for capture devices.
7382
7383 pCaptureDeviceCount (out)
7384     A pointer to an unsigned integer that will receive the number of capture devices.
7385
7386
7387 Return Value
7388 ------------
7389 MA_SUCCESS if successful; any other error code otherwise.
7390
7391
7392 Thread Safety
7393 -------------
7394 Unsafe. Since each call to this function invalidates the pointers from the previous call, you should not be calling this simultaneously across multiple
7395 threads. Instead, you need to make a copy of the returned data with your own higher level synchronization.
7396
7397
7398 Remarks
7399 -------
7400 It is _not_ safe to assume the first device in the list is the default device.
7401
7402 You can pass in NULL for the playback or capture lists in which case they'll be ignored.
7403
7404 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.
7405
7406
7407 See Also
7408 --------
7409 ma_context_get_devices()
7410 */
7411 MA_API ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** ppPlaybackDeviceInfos, ma_uint32* pPlaybackDeviceCount, ma_device_info** ppCaptureDeviceInfos, ma_uint32* pCaptureDeviceCount);
7412
7413 /*
7414 Retrieves information about a device of the given type, with the specified ID and share mode.
7415
7416
7417 Parameters
7418 ----------
7419 pContext (in)
7420     A pointer to the context performing the query.
7421
7422 deviceType (in)
7423     The type of the device being queried. Must be either `ma_device_type_playback` or `ma_device_type_capture`.
7424
7425 pDeviceID (in)
7426     The ID of the device being queried.
7427
7428 pDeviceInfo (out)
7429     A pointer to the `ma_device_info` structure that will receive the device information.
7430
7431
7432 Return Value
7433 ------------
7434 MA_SUCCESS if successful; any other error code otherwise.
7435
7436
7437 Thread Safety
7438 -------------
7439 Safe. This is guarded using a simple mutex lock.
7440
7441
7442 Remarks
7443 -------
7444 Do _not_ call this from within the `ma_context_enumerate_devices()` callback.
7445
7446 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
7447 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
7448 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
7449 the requested share mode is unsupported.
7450
7451 This leaves pDeviceInfo unmodified in the result of an error.
7452 */
7453 MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo);
7454
7455 /*
7456 Determines if the given context supports loopback mode.
7457
7458
7459 Parameters
7460 ----------
7461 pContext (in)
7462     A pointer to the context getting queried.
7463
7464
7465 Return Value
7466 ------------
7467 MA_TRUE if the context supports loopback mode; MA_FALSE otherwise.
7468 */
7469 MA_API ma_bool32 ma_context_is_loopback_supported(ma_context* pContext);
7470
7471
7472
7473 /*
7474 Initializes a device config with default settings.
7475
7476
7477 Parameters
7478 ----------
7479 deviceType (in)
7480     The type of the device this config is being initialized for. This must set to one of the following:
7481
7482     |-------------------------|
7483     | Device Type             |
7484     |-------------------------|
7485     | ma_device_type_playback |
7486     | ma_device_type_capture  |
7487     | ma_device_type_duplex   |
7488     | ma_device_type_loopback |
7489     |-------------------------|
7490
7491
7492 Return Value
7493 ------------
7494 A new device config object with default settings. You will typically want to adjust the config after this function returns. See remarks.
7495
7496
7497 Thread Safety
7498 -------------
7499 Safe.
7500
7501
7502 Callback Safety
7503 ---------------
7504 Safe, but don't try initializing a device in a callback.
7505
7506
7507 Remarks
7508 -------
7509 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
7510 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
7511 before initializing the device.
7512
7513 See `ma_device_init()` for details on specific configuration options.
7514
7515
7516 Example 1 - Simple Configuration
7517 --------------------------------
7518 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
7519 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
7520 to the `ma_device_config` structure.
7521
7522 ```c
7523 ma_device_config config = ma_device_config_init(ma_device_type_playback);
7524 config.playback.format   = ma_format_f32;
7525 config.playback.channels = 2;
7526 config.sampleRate        = 48000;
7527 config.dataCallback      = ma_data_callback;
7528 config.pUserData         = pMyUserData;
7529 ```
7530
7531
7532 See Also
7533 --------
7534 ma_device_init()
7535 ma_device_init_ex()
7536 */
7537 MA_API ma_device_config ma_device_config_init(ma_device_type deviceType);
7538
7539
7540 /*
7541 Initializes a device.
7542
7543 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
7544 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
7545 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
7546 device is done via a callback which is fired by miniaudio at periodic time intervals.
7547
7548 The frequency at which data is delivered to and from a device depends on the size of it's period. The size of the period can be defined in terms of PCM frames
7549 or milliseconds, whichever is more convenient. Generally speaking, the smaller the period, the lower the latency at the expense of higher CPU usage and
7550 increased risk of glitching due to the more frequent and granular data deliver intervals. The size of a period will depend on your requirements, but
7551 miniaudio's defaults should work fine for most scenarios. If you're building a game you should leave this fairly small, whereas if you're building a simple
7552 media player you can make it larger. Note that the period size you request is actually just a hint - miniaudio will tell the backend what you want, but the
7553 backend is ultimately responsible for what it gives you. You cannot assume you will get exactly what you ask for.
7554
7555 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
7556 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
7557 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.
7558
7559
7560 Parameters
7561 ----------
7562 pContext (in, optional)
7563     A pointer to the context that owns the device. This can be null, in which case it creates a default context internally.
7564
7565 pConfig (in)
7566     A pointer to the device configuration. Cannot be null. See remarks for details.
7567
7568 pDevice (out)
7569     A pointer to the device object being initialized.
7570
7571
7572 Return Value
7573 ------------
7574 MA_SUCCESS if successful; any other error code otherwise.
7575
7576
7577 Thread Safety
7578 -------------
7579 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
7580 calling this at the same time as `ma_device_uninit()`.
7581
7582
7583 Callback Safety
7584 ---------------
7585 Unsafe. It is not safe to call this inside any callback.
7586
7587
7588 Remarks
7589 -------
7590 Setting `pContext` to NULL will result in miniaudio creating a default context internally and is equivalent to passing in a context initialized like so:
7591
7592     ```c
7593     ma_context_init(NULL, 0, NULL, &context);
7594     ```
7595
7596 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
7597 device.pContext for the initialization of other devices.
7598
7599 The device can be configured via the `pConfig` argument. The config object is initialized with `ma_device_config_init()`. Individual configuration settings can
7600 then be set directly on the structure. Below are the members of the `ma_device_config` object.
7601
7602     deviceType
7603         Must be `ma_device_type_playback`, `ma_device_type_capture`, `ma_device_type_duplex` of `ma_device_type_loopback`.
7604
7605     sampleRate
7606         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.
7607
7608     periodSizeInFrames
7609         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
7610         be used depending on the selected performance profile. This value affects latency. See below for details.
7611
7612     periodSizeInMilliseconds
7613         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
7614         used depending on the selected performance profile. The value affects latency. See below for details.
7615
7616     periods
7617         The number of periods making up the device's entire buffer. The total buffer size is `periodSizeInFrames` or `periodSizeInMilliseconds` multiplied by
7618         this value. This is just a hint as backends will be the ones who ultimately decide how your periods will be configured.
7619
7620     performanceProfile
7621         A hint to miniaudio as to the performance requirements of your program. Can be either `ma_performance_profile_low_latency` (default) or
7622         `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at it's default value.
7623
7624     noPreSilencedOutputBuffer
7625         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
7626         the output buffer will be cleared the zero. You can use this to avoid the overhead of zeroing out the buffer if you can guarantee that your data
7627         callback will write to every sample in the output buffer, or if you are doing your own clearing.
7628
7629     noClip
7630         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
7631         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
7632         applies when the playback sample format is f32.
7633
7634     noDisableDenormals
7635         By default, miniaudio will disable denormals when the data callback is called. Setting this to true will prevent the disabling of denormals.
7636
7637     dataCallback
7638         The callback to fire whenever data is ready to be delivered to or from the device.
7639
7640     notificationCallback
7641         The callback to fire when something has changed with the device, such as whether or not it has been started or stopped.
7642
7643     pUserData
7644         The user data pointer to use with the device. You can access this directly from the device object like `device.pUserData`.
7645
7646     resampling.algorithm
7647         The resampling algorithm to use when miniaudio needs to perform resampling between the rate specified by `sampleRate` and the device's native rate. The
7648         default value is `ma_resample_algorithm_linear`, and the quality can be configured with `resampling.linear.lpfOrder`.
7649
7650     resampling.pBackendVTable
7651         A pointer to an optional vtable that can be used for plugging in a custom resampler.
7652
7653     resampling.pBackendUserData
7654         A pointer that will passed to callbacks in pBackendVTable.
7655
7656     resampling.linear.lpfOrder
7657         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
7658         the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is
7659         `MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`.
7660
7661     playback.pDeviceID
7662         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
7663         default playback device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration.
7664
7665     playback.format
7666         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
7667         initialization from the device object directly with `device.playback.format`.
7668
7669     playback.channels
7670         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
7671         from the device object directly with `device.playback.channels`.
7672
7673     playback.pChannelMap
7674         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
7675         device object direct with `device.playback.pChannelMap`. When set, the buffer should contain `channels` items.
7676
7677     playback.shareMode
7678         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
7679         exclusive mode, but it's not supported by the backend, initialization will fail. You can then fall back to shared mode if desired by changing this to
7680         ma_share_mode_shared and reinitializing.
7681
7682     capture.pDeviceID
7683         A pointer to a `ma_device_id` structure containing the ID of the capture device to initialize. Setting this NULL (default) will use the system's
7684         default capture device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration.
7685
7686     capture.format
7687         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
7688         initialization from the device object directly with `device.capture.format`.
7689
7690     capture.channels
7691         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
7692         from the device object directly with `device.capture.channels`.
7693
7694     capture.pChannelMap
7695         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
7696         device object direct with `device.capture.pChannelMap`. When set, the buffer should contain `channels` items.
7697
7698     capture.shareMode
7699         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
7700         exclusive mode, but it's not supported by the backend, initialization will fail. You can then fall back to shared mode if desired by changing this to
7701         ma_share_mode_shared and reinitializing.
7702
7703     wasapi.noAutoConvertSRC
7704         WASAPI only. When set to true, disables WASAPI's automatic resampling and forces the use of miniaudio's resampler. Defaults to false.
7705
7706     wasapi.noDefaultQualitySRC
7707         WASAPI only. Only used when `wasapi.noAutoConvertSRC` is set to false. When set to true, disables the use of `AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY`.
7708         You should usually leave this set to false, which is the default.
7709
7710     wasapi.noAutoStreamRouting
7711         WASAPI only. When set to true, disables automatic stream routing on the WASAPI backend. Defaults to false.
7712
7713     wasapi.noHardwareOffloading
7714         WASAPI only. When set to true, disables the use of WASAPI's hardware offloading feature. Defaults to false.
7715
7716     alsa.noMMap
7717         ALSA only. When set to true, disables MMap mode. Defaults to false.
7718
7719     alsa.noAutoFormat
7720         ALSA only. When set to true, disables ALSA's automatic format conversion by including the SND_PCM_NO_AUTO_FORMAT flag. Defaults to false.
7721
7722     alsa.noAutoChannels
7723         ALSA only. When set to true, disables ALSA's automatic channel conversion by including the SND_PCM_NO_AUTO_CHANNELS flag. Defaults to false.
7724
7725     alsa.noAutoResample
7726         ALSA only. When set to true, disables ALSA's automatic resampling by including the SND_PCM_NO_AUTO_RESAMPLE flag. Defaults to false.
7727
7728     pulse.pStreamNamePlayback
7729         PulseAudio only. Sets the stream name for playback.
7730
7731     pulse.pStreamNameCapture
7732         PulseAudio only. Sets the stream name for capture.
7733
7734     coreaudio.allowNominalSampleRateChange
7735         Core Audio only. Desktop only. When enabled, allows the sample rate of the device to be changed at the operating system level. This
7736         is disabled by default in order to prevent intrusive changes to the user's system. This is useful if you want to use a sample rate
7737         that is known to be natively supported by the hardware thereby avoiding the cost of resampling. When set to true, miniaudio will
7738         find the closest match between the sample rate requested in the device config and the sample rates natively supported by the
7739         hardware. When set to false, the sample rate currently set by the operating system will always be used.
7740
7741     opensl.streamType
7742         OpenSL only. Explicitly sets the stream type. If left unset (`ma_opensl_stream_type_default`), the
7743         stream type will be left unset. Think of this as the type of audio you're playing.
7744
7745     opensl.recordingPreset
7746         OpenSL only. Explicitly sets the type of recording your program will be doing. When left
7747         unset, the recording preset will be left unchanged.
7748
7749     aaudio.usage
7750         AAudio only. Explicitly sets the nature of the audio the program will be consuming. When
7751         left unset, the usage will be left unchanged.
7752
7753     aaudio.contentType
7754         AAudio only. Sets the content type. When left unset, the content type will be left unchanged.
7755
7756     aaudio.inputPreset
7757         AAudio only. Explicitly sets the type of recording your program will be doing. When left
7758         unset, the input preset will be left unchanged.
7759
7760
7761 Once initialized, the device's config is immutable. If you need to change the config you will need to initialize a new device.
7762
7763 After initializing the device it will be in a stopped state. To start it, use `ma_device_start()`.
7764
7765 If both `periodSizeInFrames` and `periodSizeInMilliseconds` are set to zero, it will default to `MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY` or
7766 `MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE`, depending on whether or not `performanceProfile` is set to `ma_performance_profile_low_latency` or
7767 `ma_performance_profile_conservative`.
7768
7769 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
7770 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
7771 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,
7772 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.
7773 Starting with Windows 10, miniaudio will use low-latency shared mode where possible which may make exclusive mode unnecessary.
7774
7775 When sending or receiving data to/from a device, miniaudio will internally perform a format conversion to convert between the format specified by the config
7776 and 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
7777 on an optimized pass-through fast path. You can retrieve the format, channel count and sample rate by inspecting the `playback/capture.format`,
7778 `playback/capture.channels` and `sampleRate` members of the device object.
7779
7780 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
7781 asking for permissions. Please refer to the official documentation for ActivateAudioInterfaceAsync() for more information.
7782
7783 ALSA Specific: When initializing the default device, requesting shared mode will try using the "dmix" device for playback and the "dsnoop" device for capture.
7784 If these fail it will try falling back to the "hw" device.
7785
7786
7787 Example 1 - Simple Initialization
7788 ---------------------------------
7789 This example shows how to initialize a simple playback device using a standard configuration. If you are just needing to do simple playback from the default
7790 playback device this is usually all you need.
7791
7792 ```c
7793 ma_device_config config = ma_device_config_init(ma_device_type_playback);
7794 config.playback.format   = ma_format_f32;
7795 config.playback.channels = 2;
7796 config.sampleRate        = 48000;
7797 config.dataCallback      = ma_data_callback;
7798 config.pMyUserData       = pMyUserData;
7799
7800 ma_device device;
7801 ma_result result = ma_device_init(NULL, &config, &device);
7802 if (result != MA_SUCCESS) {
7803     // Error
7804 }
7805 ```
7806
7807
7808 Example 2 - Advanced Initialization
7809 -----------------------------------
7810 This example shows how you might do some more advanced initialization. In this hypothetical example we want to control the latency by setting the buffer size
7811 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
7812 enumeration.
7813
7814 ```c
7815 ma_context context;
7816 ma_result result = ma_context_init(NULL, 0, NULL, &context);
7817 if (result != MA_SUCCESS) {
7818     // Error
7819 }
7820
7821 ma_device_info* pPlaybackDeviceInfos;
7822 ma_uint32 playbackDeviceCount;
7823 result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL);
7824 if (result != MA_SUCCESS) {
7825     // Error
7826 }
7827
7828 // ... choose a device from pPlaybackDeviceInfos ...
7829
7830 ma_device_config config = ma_device_config_init(ma_device_type_playback);
7831 config.playback.pDeviceID       = pMyChosenDeviceID;    // <-- Get this from the `id` member of one of the `ma_device_info` objects returned by ma_context_get_devices().
7832 config.playback.format          = ma_format_f32;
7833 config.playback.channels        = 2;
7834 config.sampleRate               = 48000;
7835 config.dataCallback             = ma_data_callback;
7836 config.pUserData                = pMyUserData;
7837 config.periodSizeInMilliseconds = 10;
7838 config.periods                  = 3;
7839
7840 ma_device device;
7841 result = ma_device_init(&context, &config, &device);
7842 if (result != MA_SUCCESS) {
7843     // Error
7844 }
7845 ```
7846
7847
7848 See Also
7849 --------
7850 ma_device_config_init()
7851 ma_device_uninit()
7852 ma_device_start()
7853 ma_context_init()
7854 ma_context_get_devices()
7855 ma_context_enumerate_devices()
7856 */
7857 MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice);
7858
7859 /*
7860 Initializes a device without a context, with extra parameters for controlling the configuration of the internal self-managed context.
7861
7862 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
7863 allows you to configure the internally created context.
7864
7865
7866 Parameters
7867 ----------
7868 backends (in, optional)
7869     A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order.
7870
7871 backendCount (in, optional)
7872     The number of items in `backend`. Ignored if `backend` is NULL.
7873
7874 pContextConfig (in, optional)
7875     The context configuration.
7876
7877 pConfig (in)
7878     A pointer to the device configuration. Cannot be null. See remarks for details.
7879
7880 pDevice (out)
7881     A pointer to the device object being initialized.
7882
7883
7884 Return Value
7885 ------------
7886 MA_SUCCESS if successful; any other error code otherwise.
7887
7888
7889 Thread Safety
7890 -------------
7891 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
7892 calling this at the same time as `ma_device_uninit()`.
7893
7894
7895 Callback Safety
7896 ---------------
7897 Unsafe. It is not safe to call this inside any callback.
7898
7899
7900 Remarks
7901 -------
7902 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
7903 your own context.
7904
7905 See the documentation for `ma_context_init()` for information on the different context configuration options.
7906
7907
7908 See Also
7909 --------
7910 ma_device_init()
7911 ma_device_uninit()
7912 ma_device_config_init()
7913 ma_context_init()
7914 */
7915 MA_API 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);
7916
7917 /*
7918 Uninitializes a device.
7919
7920 This will explicitly stop the device. You do not need to call `ma_device_stop()` beforehand, but it's harmless if you do.
7921
7922
7923 Parameters
7924 ----------
7925 pDevice (in)
7926     A pointer to the device to stop.
7927
7928
7929 Return Value
7930 ------------
7931 Nothing
7932
7933
7934 Thread Safety
7935 -------------
7936 Unsafe. As soon as this API is called the device should be considered undefined.
7937
7938
7939 Callback Safety
7940 ---------------
7941 Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock.
7942
7943
7944 See Also
7945 --------
7946 ma_device_init()
7947 ma_device_stop()
7948 */
7949 MA_API void ma_device_uninit(ma_device* pDevice);
7950
7951
7952 /*
7953 Retrieves a pointer to the context that owns the given device.
7954 */
7955 MA_API ma_context* ma_device_get_context(ma_device* pDevice);
7956
7957 /*
7958 Helper function for retrieving the log object associated with the context that owns this device.
7959 */
7960 MA_API ma_log* ma_device_get_log(ma_device* pDevice);
7961
7962
7963 /*
7964 Retrieves information about the device.
7965
7966
7967 Parameters
7968 ----------
7969 pDevice (in)
7970     A pointer to the device whose information is being retrieved.
7971
7972 type (in)
7973     The device type. This parameter is required for duplex devices. When retrieving device
7974     information, you are doing so for an individual playback or capture device.
7975
7976 pDeviceInfo (out)
7977     A pointer to the `ma_device_info` that will receive the device information.
7978
7979
7980 Return Value
7981 ------------
7982 MA_SUCCESS if successful; any other error code otherwise.
7983
7984
7985 Thread Safety
7986 -------------
7987 Unsafe. This should be considered unsafe because it may be calling into the backend which may or
7988 may not be safe.
7989
7990
7991 Callback Safety
7992 ---------------
7993 Unsafe. You should avoid calling this in the data callback because it may call into the backend
7994 which may or may not be safe.
7995 */
7996 MA_API ma_result ma_device_get_info(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo);
7997
7998
7999 /*
8000 Retrieves the name of the device.
8001
8002
8003 Parameters
8004 ----------
8005 pDevice (in)
8006     A pointer to the device whose information is being retrieved.
8007
8008 type (in)
8009     The device type. This parameter is required for duplex devices. When retrieving device
8010     information, you are doing so for an individual playback or capture device.
8011
8012 pName (out)
8013     A pointer to the buffer that will receive the name.
8014
8015 nameCap (in)
8016     The capacity of the output buffer, including space for the null terminator.
8017
8018 pLengthNotIncludingNullTerminator (out, optional)
8019     A pointer to the variable that will receive the length of the name, not including the null
8020     terminator.
8021
8022
8023 Return Value
8024 ------------
8025 MA_SUCCESS if successful; any other error code otherwise.
8026
8027
8028 Thread Safety
8029 -------------
8030 Unsafe. This should be considered unsafe because it may be calling into the backend which may or
8031 may not be safe.
8032
8033
8034 Callback Safety
8035 ---------------
8036 Unsafe. You should avoid calling this in the data callback because it may call into the backend
8037 which may or may not be safe.
8038
8039
8040 Remarks
8041 -------
8042 If the name does not fully fit into the output buffer, it'll be truncated. You can pass in NULL to
8043 `pName` if you want to first get the length of the name for the purpose of memory allocation of the
8044 output buffer. Allocating a buffer of size `MA_MAX_DEVICE_NAME_LENGTH + 1` should be enough for
8045 most cases and will avoid the need for the inefficiency of calling this function twice.
8046
8047 This is implemented in terms of `ma_device_get_info()`.
8048 */
8049 MA_API ma_result ma_device_get_name(ma_device* pDevice, ma_device_type type, char* pName, size_t nameCap, size_t* pLengthNotIncludingNullTerminator);
8050
8051
8052 /*
8053 Starts the device. For playback devices this begins playback. For capture devices it begins recording.
8054
8055 Use `ma_device_stop()` to stop the device.
8056
8057
8058 Parameters
8059 ----------
8060 pDevice (in)
8061     A pointer to the device to start.
8062
8063
8064 Return Value
8065 ------------
8066 MA_SUCCESS if successful; any other error code otherwise.
8067
8068
8069 Thread Safety
8070 -------------
8071 Safe. It's safe to call this from any thread with the exception of the callback thread.
8072
8073
8074 Callback Safety
8075 ---------------
8076 Unsafe. It is not safe to call this inside any callback.
8077
8078
8079 Remarks
8080 -------
8081 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
8082 audio data in the buffer, which needs to be done before the device begins playback.
8083
8084 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.
8085
8086 Do not call this in any callback.
8087
8088
8089 See Also
8090 --------
8091 ma_device_stop()
8092 */
8093 MA_API ma_result ma_device_start(ma_device* pDevice);
8094
8095 /*
8096 Stops the device. For playback devices this stops playback. For capture devices it stops recording.
8097
8098 Use `ma_device_start()` to start the device again.
8099
8100
8101 Parameters
8102 ----------
8103 pDevice (in)
8104     A pointer to the device to stop.
8105
8106
8107 Return Value
8108 ------------
8109 MA_SUCCESS if successful; any other error code otherwise.
8110
8111
8112 Thread Safety
8113 -------------
8114 Safe. It's safe to call this from any thread with the exception of the callback thread.
8115
8116
8117 Callback Safety
8118 ---------------
8119 Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock.
8120
8121
8122 Remarks
8123 -------
8124 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
8125 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
8126 that was specified at initialization time).
8127
8128 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
8129 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
8130 speakers or received from the microphone which can in turn result in de-syncs.
8131
8132 Do not call this in any callback.
8133
8134 This will be called implicitly by `ma_device_uninit()`.
8135
8136
8137 See Also
8138 --------
8139 ma_device_start()
8140 */
8141 MA_API ma_result ma_device_stop(ma_device* pDevice);
8142
8143 /*
8144 Determines whether or not the device is started.
8145
8146
8147 Parameters
8148 ----------
8149 pDevice (in)
8150     A pointer to the device whose start state is being retrieved.
8151
8152
8153 Return Value
8154 ------------
8155 True if the device is started, false otherwise.
8156
8157
8158 Thread Safety
8159 -------------
8160 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
8161 value will be out of sync.
8162
8163
8164 Callback Safety
8165 ---------------
8166 Safe. This is implemented as a simple accessor.
8167
8168
8169 See Also
8170 --------
8171 ma_device_start()
8172 ma_device_stop()
8173 */
8174 MA_API ma_bool32 ma_device_is_started(const ma_device* pDevice);
8175
8176
8177 /*
8178 Retrieves the state of the device.
8179
8180
8181 Parameters
8182 ----------
8183 pDevice (in)
8184     A pointer to the device whose state is being retrieved.
8185
8186
8187 Return Value
8188 ------------
8189 The current state of the device. The return value will be one of the following:
8190
8191     +-------------------------------+------------------------------------------------------------------------------+
8192     | ma_device_state_uninitialized | Will only be returned if the device is in the middle of initialization.      |
8193     +-------------------------------+------------------------------------------------------------------------------+
8194     | ma_device_state_stopped       | The device is stopped. The initial state of the device after initialization. |
8195     +-------------------------------+------------------------------------------------------------------------------+
8196     | ma_device_state_started       | The device started and requesting and/or delivering audio data.              |
8197     +-------------------------------+------------------------------------------------------------------------------+
8198     | ma_device_state_starting      | The device is in the process of starting.                                    |
8199     +-------------------------------+------------------------------------------------------------------------------+
8200     | ma_device_state_stopping      | The device is in the process of stopping.                                    |
8201     +-------------------------------+------------------------------------------------------------------------------+
8202
8203
8204 Thread Safety
8205 -------------
8206 Safe. This is implemented as a simple accessor. Note that if the device is started or stopped at the same time as this function is called,
8207 there's a possibility the return value could be out of sync. See remarks.
8208
8209
8210 Callback Safety
8211 ---------------
8212 Safe. This is implemented as a simple accessor.
8213
8214
8215 Remarks
8216 -------
8217 The general flow of a devices state goes like this:
8218
8219     ```
8220     ma_device_init()  -> ma_device_state_uninitialized -> ma_device_state_stopped
8221     ma_device_start() -> ma_device_state_starting      -> ma_device_state_started
8222     ma_device_stop()  -> ma_device_state_stopping      -> ma_device_state_stopped
8223     ```
8224
8225 When the state of the device is changed with `ma_device_start()` or `ma_device_stop()` at this same time as this function is called, the
8226 value returned by this function could potentially be out of sync. If this is significant to your program you need to implement your own
8227 synchronization.
8228 */
8229 MA_API ma_device_state ma_device_get_state(const ma_device* pDevice);
8230
8231
8232 /*
8233 Sets the master volume factor for the device.
8234
8235 The volume factor must be between 0 (silence) and 1 (full volume). Use `ma_device_set_master_volume_db()` to use decibel notation, where 0 is full volume and
8236 values less than 0 decreases the volume.
8237
8238
8239 Parameters
8240 ----------
8241 pDevice (in)
8242     A pointer to the device whose volume is being set.
8243
8244 volume (in)
8245     The new volume factor. Must be >= 0.
8246
8247
8248 Return Value
8249 ------------
8250 MA_SUCCESS if the volume was set successfully.
8251 MA_INVALID_ARGS if pDevice is NULL.
8252 MA_INVALID_ARGS if volume is negative.
8253
8254
8255 Thread Safety
8256 -------------
8257 Safe. This just sets a local member of the device object.
8258
8259
8260 Callback Safety
8261 ---------------
8262 Safe. If you set the volume in the data callback, that data written to the output buffer will have the new volume applied.
8263
8264
8265 Remarks
8266 -------
8267 This applies the volume factor across all channels.
8268
8269 This does not change the operating system's volume. It only affects the volume for the given `ma_device` object's audio stream.
8270
8271
8272 See Also
8273 --------
8274 ma_device_get_master_volume()
8275 ma_device_set_master_volume_db()
8276 ma_device_get_master_volume_db()
8277 */
8278 MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume);
8279
8280 /*
8281 Retrieves the master volume factor for the device.
8282
8283
8284 Parameters
8285 ----------
8286 pDevice (in)
8287     A pointer to the device whose volume factor is being retrieved.
8288
8289 pVolume (in)
8290     A pointer to the variable that will receive the volume factor. The returned value will be in the range of [0, 1].
8291
8292
8293 Return Value
8294 ------------
8295 MA_SUCCESS if successful.
8296 MA_INVALID_ARGS if pDevice is NULL.
8297 MA_INVALID_ARGS if pVolume is NULL.
8298
8299
8300 Thread Safety
8301 -------------
8302 Safe. This just a simple member retrieval.
8303
8304
8305 Callback Safety
8306 ---------------
8307 Safe.
8308
8309
8310 Remarks
8311 -------
8312 If an error occurs, `*pVolume` will be set to 0.
8313
8314
8315 See Also
8316 --------
8317 ma_device_set_master_volume()
8318 ma_device_set_master_volume_gain_db()
8319 ma_device_get_master_volume_gain_db()
8320 */
8321 MA_API ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume);
8322
8323 /*
8324 Sets the master volume for the device as gain in decibels.
8325
8326 A gain of 0 is full volume, whereas a gain of < 0 will decrease the volume.
8327
8328
8329 Parameters
8330 ----------
8331 pDevice (in)
8332     A pointer to the device whose gain is being set.
8333
8334 gainDB (in)
8335     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.
8336
8337
8338 Return Value
8339 ------------
8340 MA_SUCCESS if the volume was set successfully.
8341 MA_INVALID_ARGS if pDevice is NULL.
8342 MA_INVALID_ARGS if the gain is > 0.
8343
8344
8345 Thread Safety
8346 -------------
8347 Safe. This just sets a local member of the device object.
8348
8349
8350 Callback Safety
8351 ---------------
8352 Safe. If you set the volume in the data callback, that data written to the output buffer will have the new volume applied.
8353
8354
8355 Remarks
8356 -------
8357 This applies the gain across all channels.
8358
8359 This does not change the operating system's volume. It only affects the volume for the given `ma_device` object's audio stream.
8360
8361
8362 See Also
8363 --------
8364 ma_device_get_master_volume_gain_db()
8365 ma_device_set_master_volume()
8366 ma_device_get_master_volume()
8367 */
8368 MA_API ma_result ma_device_set_master_volume_db(ma_device* pDevice, float gainDB);
8369
8370 /*
8371 Retrieves the master gain in decibels.
8372
8373
8374 Parameters
8375 ----------
8376 pDevice (in)
8377     A pointer to the device whose gain is being retrieved.
8378
8379 pGainDB (in)
8380     A pointer to the variable that will receive the gain in decibels. The returned value will be <= 0.
8381
8382
8383 Return Value
8384 ------------
8385 MA_SUCCESS if successful.
8386 MA_INVALID_ARGS if pDevice is NULL.
8387 MA_INVALID_ARGS if pGainDB is NULL.
8388
8389
8390 Thread Safety
8391 -------------
8392 Safe. This just a simple member retrieval.
8393
8394
8395 Callback Safety
8396 ---------------
8397 Safe.
8398
8399
8400 Remarks
8401 -------
8402 If an error occurs, `*pGainDB` will be set to 0.
8403
8404
8405 See Also
8406 --------
8407 ma_device_set_master_volume_db()
8408 ma_device_set_master_volume()
8409 ma_device_get_master_volume()
8410 */
8411 MA_API ma_result ma_device_get_master_volume_db(ma_device* pDevice, float* pGainDB);
8412
8413
8414 /*
8415 Called from the data callback of asynchronous backends to allow miniaudio to process the data and fire the miniaudio data callback.
8416
8417
8418 Parameters
8419 ----------
8420 pDevice (in)
8421     A pointer to device whose processing the data callback.
8422
8423 pOutput (out)
8424     A pointer to the buffer that will receive the output PCM frame data. On a playback device this must not be NULL. On a duplex device
8425     this can be NULL, in which case pInput must not be NULL.
8426
8427 pInput (in)
8428     A pointer to the buffer containing input PCM frame data. On a capture device this must not be NULL. On a duplex device this can be
8429     NULL, in which case `pOutput` must not be NULL.
8430
8431 frameCount (in)
8432     The number of frames being processed.
8433
8434
8435 Return Value
8436 ------------
8437 MA_SUCCESS if successful; any other result code otherwise.
8438
8439
8440 Thread Safety
8441 -------------
8442 This function should only ever be called from the internal data callback of the backend. It is safe to call this simultaneously between a
8443 playback and capture device in duplex setups.
8444
8445
8446 Callback Safety
8447 ---------------
8448 Do not call this from the miniaudio data callback. It should only ever be called from the internal data callback of the backend.
8449
8450
8451 Remarks
8452 -------
8453 If both `pOutput` and `pInput` are NULL, and error will be returned. In duplex scenarios, both `pOutput` and `pInput` can be non-NULL, in
8454 which case `pInput` will be processed first, followed by `pOutput`.
8455
8456 If you are implementing a custom backend, and that backend uses a callback for data delivery, you'll need to call this from inside that
8457 callback.
8458 */
8459 MA_API ma_result ma_device_handle_backend_data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
8460
8461
8462 /*
8463 Calculates an appropriate buffer size from a descriptor, native sample rate and performance profile.
8464
8465 This function is used by backends for helping determine an appropriately sized buffer to use with
8466 the device depending on the values of `periodSizeInFrames` and `periodSizeInMilliseconds` in the
8467 `pDescriptor` object. Since buffer size calculations based on time depends on the sample rate, a
8468 best guess at the device's native sample rate is also required which is where `nativeSampleRate`
8469 comes in. In addition, the performance profile is also needed for cases where both the period size
8470 in frames and milliseconds are both zero.
8471
8472
8473 Parameters
8474 ----------
8475 pDescriptor (in)
8476     A pointer to device descriptor whose `periodSizeInFrames` and `periodSizeInMilliseconds` members
8477     will be used for the calculation of the buffer size.
8478
8479 nativeSampleRate (in)
8480     The device's native sample rate. This is only ever used when the `periodSizeInFrames` member of
8481     `pDescriptor` is zero. In this case, `periodSizeInMilliseconds` will be used instead, in which
8482     case a sample rate is required to convert to a size in frames.
8483
8484 performanceProfile (in)
8485     When both the `periodSizeInFrames` and `periodSizeInMilliseconds` members of `pDescriptor` are
8486     zero, miniaudio will fall back to a buffer size based on the performance profile. The profile
8487     to use for this calculation is determine by this parameter.
8488
8489
8490 Return Value
8491 ------------
8492 The calculated buffer size in frames.
8493
8494
8495 Thread Safety
8496 -------------
8497 This is safe so long as nothing modifies `pDescriptor` at the same time. However, this function
8498 should only ever be called from within the backend's device initialization routine and therefore
8499 shouldn't have any multithreading concerns.
8500
8501
8502 Callback Safety
8503 ---------------
8504 This is safe to call within the data callback, but there is no reason to ever do this.
8505
8506
8507 Remarks
8508 -------
8509 If `nativeSampleRate` is zero, this function will fall back to `pDescriptor->sampleRate`. If that
8510 is also zero, `MA_DEFAULT_SAMPLE_RATE` will be used instead.
8511 */
8512 MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile);
8513
8514
8515
8516 /*
8517 Retrieves a friendly name for a backend.
8518 */
8519 MA_API const char* ma_get_backend_name(ma_backend backend);
8520
8521 /*
8522 Determines whether or not the given backend is available by the compilation environment.
8523 */
8524 MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend);
8525
8526 /*
8527 Retrieves compile-time enabled backends.
8528
8529
8530 Parameters
8531 ----------
8532 pBackends (out, optional)
8533     A pointer to the buffer that will receive the enabled backends. Set to NULL to retrieve the backend count. Setting
8534     the capacity of the buffer to `MA_BUFFER_COUNT` will guarantee it's large enough for all backends.
8535
8536 backendCap (in)
8537     The capacity of the `pBackends` buffer.
8538
8539 pBackendCount (out)
8540     A pointer to the variable that will receive the enabled backend count.
8541
8542
8543 Return Value
8544 ------------
8545 MA_SUCCESS if successful.
8546 MA_INVALID_ARGS if `pBackendCount` is NULL.
8547 MA_NO_SPACE if the capacity of `pBackends` is not large enough.
8548
8549 If `MA_NO_SPACE` is returned, the `pBackends` buffer will be filled with `*pBackendCount` values.
8550
8551
8552 Thread Safety
8553 -------------
8554 Safe.
8555
8556
8557 Callback Safety
8558 ---------------
8559 Safe.
8560
8561
8562 Remarks
8563 -------
8564 If you want to retrieve the number of backends so you can determine the capacity of `pBackends` buffer, you can call
8565 this function with `pBackends` set to NULL.
8566
8567 This will also enumerate the null backend. If you don't want to include this you need to check for `ma_backend_null`
8568 when you enumerate over the returned backends and handle it appropriately. Alternatively, you can disable it at
8569 compile time with `MA_NO_NULL`.
8570
8571 The returned backends are determined based on compile time settings, not the platform it's currently running on. For
8572 example, PulseAudio will be returned if it was enabled at compile time, even when the user doesn't actually have
8573 PulseAudio installed.
8574
8575
8576 Example 1
8577 ---------
8578 The example below retrieves the enabled backend count using a fixed sized buffer allocated on the stack. The buffer is
8579 given a capacity of `MA_BACKEND_COUNT` which will guarantee it'll be large enough to store all available backends.
8580 Since `MA_BACKEND_COUNT` is always a relatively small value, this should be suitable for most scenarios.
8581
8582 ```
8583 ma_backend enabledBackends[MA_BACKEND_COUNT];
8584 size_t enabledBackendCount;
8585
8586 result = ma_get_enabled_backends(enabledBackends, MA_BACKEND_COUNT, &enabledBackendCount);
8587 if (result != MA_SUCCESS) {
8588     // Failed to retrieve enabled backends. Should never happen in this example since all inputs are valid.
8589 }
8590 ```
8591
8592
8593 See Also
8594 --------
8595 ma_is_backend_enabled()
8596 */
8597 MA_API ma_result ma_get_enabled_backends(ma_backend* pBackends, size_t backendCap, size_t* pBackendCount);
8598
8599 /*
8600 Determines whether or not loopback mode is support by a backend.
8601 */
8602 MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend);
8603
8604 #endif  /* MA_NO_DEVICE_IO */
8605
8606
8607
8608 /*
8609 Locks a spinlock.
8610 */
8611 MA_API ma_result ma_spinlock_lock(volatile ma_spinlock* pSpinlock);
8612
8613 /*
8614 Locks a spinlock, but does not yield() when looping.
8615 */
8616 MA_API ma_result ma_spinlock_lock_noyield(volatile ma_spinlock* pSpinlock);
8617
8618 /*
8619 Unlocks a spinlock.
8620 */
8621 MA_API ma_result ma_spinlock_unlock(volatile ma_spinlock* pSpinlock);
8622
8623
8624 #ifndef MA_NO_THREADING
8625
8626 /*
8627 Creates a mutex.
8628
8629 A mutex must be created from a valid context. A mutex is initially unlocked.
8630 */
8631 MA_API ma_result ma_mutex_init(ma_mutex* pMutex);
8632
8633 /*
8634 Deletes a mutex.
8635 */
8636 MA_API void ma_mutex_uninit(ma_mutex* pMutex);
8637
8638 /*
8639 Locks a mutex with an infinite timeout.
8640 */
8641 MA_API void ma_mutex_lock(ma_mutex* pMutex);
8642
8643 /*
8644 Unlocks a mutex.
8645 */
8646 MA_API void ma_mutex_unlock(ma_mutex* pMutex);
8647
8648
8649 /*
8650 Initializes an auto-reset event.
8651 */
8652 MA_API ma_result ma_event_init(ma_event* pEvent);
8653
8654 /*
8655 Uninitializes an auto-reset event.
8656 */
8657 MA_API void ma_event_uninit(ma_event* pEvent);
8658
8659 /*
8660 Waits for the specified auto-reset event to become signalled.
8661 */
8662 MA_API ma_result ma_event_wait(ma_event* pEvent);
8663
8664 /*
8665 Signals the specified auto-reset event.
8666 */
8667 MA_API ma_result ma_event_signal(ma_event* pEvent);
8668 #endif  /* MA_NO_THREADING */
8669
8670
8671 /*
8672 Fence
8673 =====
8674 This locks while the counter is larger than 0. Counter can be incremented and decremented by any
8675 thread, but care needs to be taken when waiting. It is possible for one thread to acquire the
8676 fence just as another thread returns from ma_fence_wait().
8677
8678 The idea behind a fence is to allow you to wait for a group of operations to complete. When an
8679 operation starts, the counter is incremented which locks the fence. When the operation completes,
8680 the fence will be released which decrements the counter. ma_fence_wait() will block until the
8681 counter hits zero.
8682
8683 If threading is disabled, ma_fence_wait() will spin on the counter.
8684 */
8685 typedef struct
8686 {
8687 #ifndef MA_NO_THREADING
8688     ma_event e;
8689 #endif
8690     ma_uint32 counter;
8691 } ma_fence;
8692
8693 MA_API ma_result ma_fence_init(ma_fence* pFence);
8694 MA_API void ma_fence_uninit(ma_fence* pFence);
8695 MA_API ma_result ma_fence_acquire(ma_fence* pFence);    /* Increment counter. */
8696 MA_API ma_result ma_fence_release(ma_fence* pFence);    /* Decrement counter. */
8697 MA_API ma_result ma_fence_wait(ma_fence* pFence);       /* Wait for counter to reach 0. */
8698
8699
8700
8701 /*
8702 Notification callback for asynchronous operations.
8703 */
8704 typedef void ma_async_notification;
8705
8706 typedef struct
8707 {
8708     void (* onSignal)(ma_async_notification* pNotification);
8709 } ma_async_notification_callbacks;
8710
8711 MA_API ma_result ma_async_notification_signal(ma_async_notification* pNotification);
8712
8713
8714 /*
8715 Simple polling notification.
8716
8717 This just sets a variable when the notification has been signalled which is then polled with ma_async_notification_poll_is_signalled()
8718 */
8719 typedef struct
8720 {
8721     ma_async_notification_callbacks cb;
8722     ma_bool32 signalled;
8723 } ma_async_notification_poll;
8724
8725 MA_API ma_result ma_async_notification_poll_init(ma_async_notification_poll* pNotificationPoll);
8726 MA_API ma_bool32 ma_async_notification_poll_is_signalled(const ma_async_notification_poll* pNotificationPoll);
8727
8728
8729 /*
8730 Event Notification
8731
8732 This uses an ma_event. If threading is disabled (MA_NO_THREADING), initialization will fail.
8733 */
8734 typedef struct
8735 {
8736     ma_async_notification_callbacks cb;
8737 #ifndef MA_NO_THREADING
8738     ma_event e;
8739 #endif
8740 } ma_async_notification_event;
8741
8742 MA_API ma_result ma_async_notification_event_init(ma_async_notification_event* pNotificationEvent);
8743 MA_API ma_result ma_async_notification_event_uninit(ma_async_notification_event* pNotificationEvent);
8744 MA_API ma_result ma_async_notification_event_wait(ma_async_notification_event* pNotificationEvent);
8745 MA_API ma_result ma_async_notification_event_signal(ma_async_notification_event* pNotificationEvent);
8746
8747
8748
8749
8750 /************************************************************************************************************************************************************
8751
8752 Utiltities
8753
8754 ************************************************************************************************************************************************************/
8755
8756 /*
8757 Calculates a buffer size in milliseconds from the specified number of frames and sample rate.
8758 */
8759 MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate);
8760
8761 /*
8762 Calculates a buffer size in frames from the specified number of milliseconds and sample rate.
8763 */
8764 MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate);
8765
8766 /*
8767 Copies PCM frames from one buffer to another.
8768 */
8769 MA_API void ma_copy_pcm_frames(void* dst, const void* src, ma_uint64 frameCount, ma_format format, ma_uint32 channels);
8770
8771 /*
8772 Copies silent frames into the given buffer.
8773
8774 Remarks
8775 -------
8776 For all formats except `ma_format_u8`, the output buffer will be filled with 0. For `ma_format_u8` it will be filled with 128. The reason for this is that it
8777 makes more sense for the purpose of mixing to initialize it to the center point.
8778 */
8779 MA_API void ma_silence_pcm_frames(void* p, ma_uint64 frameCount, ma_format format, ma_uint32 channels);
8780
8781
8782 /*
8783 Offsets a pointer by the specified number of PCM frames.
8784 */
8785 MA_API void* ma_offset_pcm_frames_ptr(void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels);
8786 MA_API const void* ma_offset_pcm_frames_const_ptr(const void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels);
8787 static MA_INLINE float* ma_offset_pcm_frames_ptr_f32(float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return (float*)ma_offset_pcm_frames_ptr((void*)p, offsetInFrames, ma_format_f32, channels); }
8788 static MA_INLINE const float* ma_offset_pcm_frames_const_ptr_f32(const float* p, ma_uint64 offsetInFrames, ma_uint32 channels) { return (const float*)ma_offset_pcm_frames_const_ptr((const void*)p, offsetInFrames, ma_format_f32, channels); }
8789
8790
8791 /*
8792 Clips samples.
8793 */
8794 MA_API void ma_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count);
8795 MA_API void ma_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count);
8796 MA_API void ma_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count);
8797 MA_API void ma_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count);
8798 MA_API void ma_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count);
8799 MA_API void ma_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels);
8800
8801 /*
8802 Helper for applying a volume factor to samples.
8803
8804 Note that the source and destination buffers can be the same, in which case it'll perform the operation in-place.
8805 */
8806 MA_API void ma_copy_and_apply_volume_factor_u8(ma_uint8* pSamplesOut, const ma_uint8* pSamplesIn, ma_uint64 sampleCount, float factor);
8807 MA_API void ma_copy_and_apply_volume_factor_s16(ma_int16* pSamplesOut, const ma_int16* pSamplesIn, ma_uint64 sampleCount, float factor);
8808 MA_API void ma_copy_and_apply_volume_factor_s24(void* pSamplesOut, const void* pSamplesIn, ma_uint64 sampleCount, float factor);
8809 MA_API void ma_copy_and_apply_volume_factor_s32(ma_int32* pSamplesOut, const ma_int32* pSamplesIn, ma_uint64 sampleCount, float factor);
8810 MA_API void ma_copy_and_apply_volume_factor_f32(float* pSamplesOut, const float* pSamplesIn, ma_uint64 sampleCount, float factor);
8811
8812 MA_API void ma_apply_volume_factor_u8(ma_uint8* pSamples, ma_uint64 sampleCount, float factor);
8813 MA_API void ma_apply_volume_factor_s16(ma_int16* pSamples, ma_uint64 sampleCount, float factor);
8814 MA_API void ma_apply_volume_factor_s24(void* pSamples, ma_uint64 sampleCount, float factor);
8815 MA_API void ma_apply_volume_factor_s32(ma_int32* pSamples, ma_uint64 sampleCount, float factor);
8816 MA_API void ma_apply_volume_factor_f32(float* pSamples, ma_uint64 sampleCount, float factor);
8817
8818 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pFramesOut, const ma_uint8* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
8819 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pFramesOut, const ma_int16* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
8820 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
8821 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pFramesOut, const ma_int32* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
8822 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
8823 MA_API void ma_copy_and_apply_volume_factor_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor);
8824
8825 MA_API void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
8826 MA_API void ma_apply_volume_factor_pcm_frames_s16(ma_int16* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
8827 MA_API void ma_apply_volume_factor_pcm_frames_s24(void* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
8828 MA_API void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
8829 MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
8830 MA_API void ma_apply_volume_factor_pcm_frames(void* pFrames, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor);
8831
8832 MA_API void ma_copy_and_apply_volume_factor_per_channel_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float* pChannelGains);
8833
8834
8835 MA_API void ma_copy_and_apply_volume_and_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count, float volume);
8836 MA_API void ma_copy_and_apply_volume_and_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count, float volume);
8837 MA_API void ma_copy_and_apply_volume_and_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count, float volume);
8838 MA_API void ma_copy_and_apply_volume_and_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count, float volume);
8839 MA_API void ma_copy_and_apply_volume_and_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count, float volume);
8840 MA_API void ma_copy_and_apply_volume_and_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float volume);
8841
8842
8843 /*
8844 Helper for converting a linear factor to gain in decibels.
8845 */
8846 MA_API float ma_volume_linear_to_db(float factor);
8847
8848 /*
8849 Helper for converting gain in decibels to a linear factor.
8850 */
8851 MA_API float ma_volume_db_to_linear(float gain);
8852
8853
8854
8855 /*
8856 Slot Allocator
8857 --------------
8858 The idea of the slot allocator is for it to be used in conjunction with a fixed sized buffer. You use the slot allocator to allocator an index that can be used
8859 as the insertion point for an object.
8860
8861 Slots are reference counted to help mitigate the ABA problem in the lock-free queue we use for tracking jobs.
8862
8863 The slot index is stored in the low 32 bits. The reference counter is stored in the high 32 bits:
8864
8865     +-----------------+-----------------+
8866     | 32 Bits         | 32 Bits         |
8867     +-----------------+-----------------+
8868     | Reference Count | Slot Index      |
8869     +-----------------+-----------------+
8870 */
8871 typedef struct
8872 {
8873     ma_uint32 capacity;    /* The number of slots to make available. */
8874 } ma_slot_allocator_config;
8875
8876 MA_API ma_slot_allocator_config ma_slot_allocator_config_init(ma_uint32 capacity);
8877
8878
8879 typedef struct
8880 {
8881     MA_ATOMIC(4, ma_uint32) bitfield;   /* Must be used atomically because the allocation and freeing routines need to make copies of this which must never be optimized away by the compiler. */
8882 } ma_slot_allocator_group;
8883
8884 typedef struct
8885 {
8886     ma_slot_allocator_group* pGroups;   /* Slots are grouped in chunks of 32. */
8887     ma_uint32* pSlots;                  /* 32 bits for reference counting for ABA mitigation. */
8888     ma_uint32 count;                    /* Allocation count. */
8889     ma_uint32 capacity;
8890
8891     /* Memory management. */
8892     ma_bool32 _ownsHeap;
8893     void* _pHeap;
8894 } ma_slot_allocator;
8895
8896 MA_API ma_result ma_slot_allocator_get_heap_size(const ma_slot_allocator_config* pConfig, size_t* pHeapSizeInBytes);
8897 MA_API ma_result ma_slot_allocator_init_preallocated(const ma_slot_allocator_config* pConfig, void* pHeap, ma_slot_allocator* pAllocator);
8898 MA_API ma_result ma_slot_allocator_init(const ma_slot_allocator_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_slot_allocator* pAllocator);
8899 MA_API void ma_slot_allocator_uninit(ma_slot_allocator* pAllocator, const ma_allocation_callbacks* pAllocationCallbacks);
8900 MA_API ma_result ma_slot_allocator_alloc(ma_slot_allocator* pAllocator, ma_uint64* pSlot);
8901 MA_API ma_result ma_slot_allocator_free(ma_slot_allocator* pAllocator, ma_uint64 slot);
8902
8903
8904
8905
8906 /**************************************************************************************************
8907
8908 Data Source
8909
8910 **************************************************************************************************/
8911 typedef void ma_data_source;
8912
8913 #define MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT    0x00000001
8914
8915 typedef struct
8916 {
8917     ma_result (* onRead)(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
8918     ma_result (* onSeek)(ma_data_source* pDataSource, ma_uint64 frameIndex);
8919     ma_result (* onGetDataFormat)(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
8920     ma_result (* onGetCursor)(ma_data_source* pDataSource, ma_uint64* pCursor);
8921     ma_result (* onGetLength)(ma_data_source* pDataSource, ma_uint64* pLength);
8922     ma_result (* onSetLooping)(ma_data_source* pDataSource, ma_bool32 isLooping);
8923     ma_uint32 flags;
8924 } ma_data_source_vtable;
8925
8926 typedef ma_data_source* (* ma_data_source_get_next_proc)(ma_data_source* pDataSource);
8927
8928 typedef struct
8929 {
8930     const ma_data_source_vtable* vtable;
8931 } ma_data_source_config;
8932
8933 MA_API ma_data_source_config ma_data_source_config_init(void);
8934
8935
8936 typedef struct
8937 {
8938     const ma_data_source_vtable* vtable;
8939     ma_uint64 rangeBegInFrames;
8940     ma_uint64 rangeEndInFrames;             /* Set to -1 for unranged (default). */
8941     ma_uint64 loopBegInFrames;              /* Relative to rangeBegInFrames. */
8942     ma_uint64 loopEndInFrames;              /* Relative to rangeBegInFrames. Set to -1 for the end of the range. */
8943     ma_data_source* pCurrent;               /* When non-NULL, the data source being initialized will act as a proxy and will route all operations to pCurrent. Used in conjunction with pNext/onGetNext for seamless chaining. */
8944     ma_data_source* pNext;                  /* When set to NULL, onGetNext will be used. */
8945     ma_data_source_get_next_proc onGetNext; /* Will be used when pNext is NULL. If both are NULL, no next will be used. */
8946     MA_ATOMIC(4, ma_bool32) isLooping;
8947 } ma_data_source_base;
8948
8949 MA_API ma_result ma_data_source_init(const ma_data_source_config* pConfig, ma_data_source* pDataSource);
8950 MA_API void ma_data_source_uninit(ma_data_source* pDataSource);
8951 MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);   /* Must support pFramesOut = NULL in which case a forward seek should be performed. */
8952 MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, &framesRead); */
8953 MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex);
8954 MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
8955 MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor);
8956 MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength);    /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */
8957 MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping);
8958 MA_API ma_bool32 ma_data_source_is_looping(ma_data_source* pDataSource);
8959 MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames);
8960 MA_API void ma_data_source_get_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames);
8961 MA_API ma_result ma_data_source_set_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 loopBegInFrames, ma_uint64 loopEndInFrames);
8962 MA_API void ma_data_source_get_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames);
8963 MA_API ma_result ma_data_source_set_current(ma_data_source* pDataSource, ma_data_source* pCurrentDataSource);
8964 MA_API ma_data_source* ma_data_source_get_current(ma_data_source* pDataSource);
8965 MA_API ma_result ma_data_source_set_next(ma_data_source* pDataSource, ma_data_source* pNextDataSource);
8966 MA_API ma_data_source* ma_data_source_get_next(ma_data_source* pDataSource);
8967 MA_API ma_result ma_data_source_set_next_callback(ma_data_source* pDataSource, ma_data_source_get_next_proc onGetNext);
8968 MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(ma_data_source* pDataSource);
8969
8970
8971 typedef struct
8972 {
8973     ma_data_source_base ds;
8974     ma_format format;
8975     ma_uint32 channels;
8976     ma_uint64 cursor;
8977     ma_uint64 sizeInFrames;
8978     const void* pData;
8979 } ma_audio_buffer_ref;
8980
8981 MA_API ma_result ma_audio_buffer_ref_init(ma_format format, ma_uint32 channels, const void* pData, ma_uint64 sizeInFrames, ma_audio_buffer_ref* pAudioBufferRef);
8982 MA_API void ma_audio_buffer_ref_uninit(ma_audio_buffer_ref* pAudioBufferRef);
8983 MA_API ma_result ma_audio_buffer_ref_set_data(ma_audio_buffer_ref* pAudioBufferRef, const void* pData, ma_uint64 sizeInFrames);
8984 MA_API ma_uint64 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref* pAudioBufferRef, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop);
8985 MA_API ma_result ma_audio_buffer_ref_seek_to_pcm_frame(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameIndex);
8986 MA_API ma_result ma_audio_buffer_ref_map(ma_audio_buffer_ref* pAudioBufferRef, void** ppFramesOut, ma_uint64* pFrameCount);
8987 MA_API ma_result ma_audio_buffer_ref_unmap(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameCount);    /* Returns MA_AT_END if the end has been reached. This should be considered successful. */
8988 MA_API ma_bool32 ma_audio_buffer_ref_at_end(const ma_audio_buffer_ref* pAudioBufferRef);
8989 MA_API ma_result ma_audio_buffer_ref_get_cursor_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pCursor);
8990 MA_API ma_result ma_audio_buffer_ref_get_length_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pLength);
8991 MA_API ma_result ma_audio_buffer_ref_get_available_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pAvailableFrames);
8992
8993
8994
8995 typedef struct
8996 {
8997     ma_format format;
8998     ma_uint32 channels;
8999     ma_uint64 sizeInFrames;
9000     const void* pData;  /* If set to NULL, will allocate a block of memory for you. */
9001     ma_allocation_callbacks allocationCallbacks;
9002 } ma_audio_buffer_config;
9003
9004 MA_API ma_audio_buffer_config ma_audio_buffer_config_init(ma_format format, ma_uint32 channels, ma_uint64 sizeInFrames, const void* pData, const ma_allocation_callbacks* pAllocationCallbacks);
9005
9006 typedef struct
9007 {
9008     ma_audio_buffer_ref ref;
9009     ma_allocation_callbacks allocationCallbacks;
9010     ma_bool32 ownsData;             /* Used to control whether or not miniaudio owns the data buffer. If set to true, pData will be freed in ma_audio_buffer_uninit(). */
9011     ma_uint8 _pExtraData[1];        /* For allocating a buffer with the memory located directly after the other memory of the structure. */
9012 } ma_audio_buffer;
9013
9014 MA_API ma_result ma_audio_buffer_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer);
9015 MA_API ma_result ma_audio_buffer_init_copy(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer);
9016 MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer** ppAudioBuffer);  /* Always copies the data. Doesn't make sense to use this otherwise. Use ma_audio_buffer_uninit_and_free() to uninit. */
9017 MA_API void ma_audio_buffer_uninit(ma_audio_buffer* pAudioBuffer);
9018 MA_API void ma_audio_buffer_uninit_and_free(ma_audio_buffer* pAudioBuffer);
9019 MA_API ma_uint64 ma_audio_buffer_read_pcm_frames(ma_audio_buffer* pAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop);
9020 MA_API ma_result ma_audio_buffer_seek_to_pcm_frame(ma_audio_buffer* pAudioBuffer, ma_uint64 frameIndex);
9021 MA_API ma_result ma_audio_buffer_map(ma_audio_buffer* pAudioBuffer, void** ppFramesOut, ma_uint64* pFrameCount);
9022 MA_API ma_result ma_audio_buffer_unmap(ma_audio_buffer* pAudioBuffer, ma_uint64 frameCount);    /* Returns MA_AT_END if the end has been reached. This should be considered successful. */
9023 MA_API ma_bool32 ma_audio_buffer_at_end(const ma_audio_buffer* pAudioBuffer);
9024 MA_API ma_result ma_audio_buffer_get_cursor_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pCursor);
9025 MA_API ma_result ma_audio_buffer_get_length_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pLength);
9026 MA_API ma_result ma_audio_buffer_get_available_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames);
9027
9028
9029 /*
9030 Paged Audio Buffer
9031 ==================
9032 A paged audio buffer is made up of a linked list of pages. It's expandable, but not shrinkable. It
9033 can be used for cases where audio data is streamed in asynchronously while allowing data to be read
9034 at the same time.
9035
9036 This is lock-free, but not 100% thread safe. You can append a page and read from the buffer across
9037 simultaneously across different threads, however only one thread at a time can append, and only one
9038 thread at a time can read and seek.
9039 */
9040 typedef struct ma_paged_audio_buffer_page ma_paged_audio_buffer_page;
9041 struct ma_paged_audio_buffer_page
9042 {
9043     MA_ATOMIC(MA_SIZEOF_PTR, ma_paged_audio_buffer_page*) pNext;
9044     ma_uint64 sizeInFrames;
9045     ma_uint8 pAudioData[1];
9046 };
9047
9048 typedef struct
9049 {
9050     ma_format format;
9051     ma_uint32 channels;
9052     ma_paged_audio_buffer_page head;                                /* Dummy head for the lock-free algorithm. Always has a size of 0. */
9053     MA_ATOMIC(MA_SIZEOF_PTR, ma_paged_audio_buffer_page*) pTail;    /* Never null. Initially set to &head. */
9054 } ma_paged_audio_buffer_data;
9055
9056 MA_API ma_result ma_paged_audio_buffer_data_init(ma_format format, ma_uint32 channels, ma_paged_audio_buffer_data* pData);
9057 MA_API void ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data* pData, const ma_allocation_callbacks* pAllocationCallbacks);
9058 MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data* pData);
9059 MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data* pData);
9060 MA_API ma_result ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data* pData, ma_uint64* pLength);
9061 MA_API ma_result ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data* pData, ma_uint64 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks, ma_paged_audio_buffer_page** ppPage);
9062 MA_API ma_result ma_paged_audio_buffer_data_free_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage, const ma_allocation_callbacks* pAllocationCallbacks);
9063 MA_API ma_result ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage);
9064 MA_API ma_result ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks);
9065
9066
9067 typedef struct
9068 {
9069     ma_paged_audio_buffer_data* pData;  /* Must not be null. */
9070 } ma_paged_audio_buffer_config;
9071
9072 MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data* pData);
9073
9074
9075 typedef struct
9076 {
9077     ma_data_source_base ds;
9078     ma_paged_audio_buffer_data* pData;              /* Audio data is read from here. Cannot be null. */
9079     ma_paged_audio_buffer_page* pCurrent;
9080     ma_uint64 relativeCursor;                       /* Relative to the current page. */
9081     ma_uint64 absoluteCursor;
9082 } ma_paged_audio_buffer;
9083
9084 MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer);
9085 MA_API void ma_paged_audio_buffer_uninit(ma_paged_audio_buffer* pPagedAudioBuffer);
9086 MA_API ma_result ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);   /* Returns MA_AT_END if no more pages available. */
9087 MA_API ma_result ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64 frameIndex);
9088 MA_API ma_result ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pCursor);
9089 MA_API ma_result ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pLength);
9090
9091
9092
9093 /************************************************************************************************************************************************************
9094
9095 VFS
9096 ===
9097
9098 The VFS object (virtual file system) is what's used to customize file access. This is useful in cases where stdio FILE* based APIs may not be entirely
9099 appropriate for a given situation.
9100
9101 ************************************************************************************************************************************************************/
9102 typedef void      ma_vfs;
9103 typedef ma_handle ma_vfs_file;
9104
9105 typedef enum
9106 {
9107     MA_OPEN_MODE_READ  = 0x00000001,
9108     MA_OPEN_MODE_WRITE = 0x00000002
9109 } ma_open_mode_flags;
9110
9111 typedef enum
9112 {
9113     ma_seek_origin_start,
9114     ma_seek_origin_current,
9115     ma_seek_origin_end  /* Not used by decoders. */
9116 } ma_seek_origin;
9117
9118 typedef struct
9119 {
9120     ma_uint64 sizeInBytes;
9121 } ma_file_info;
9122
9123 typedef struct
9124 {
9125     ma_result (* onOpen) (ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
9126     ma_result (* onOpenW)(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
9127     ma_result (* onClose)(ma_vfs* pVFS, ma_vfs_file file);
9128     ma_result (* onRead) (ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead);
9129     ma_result (* onWrite)(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten);
9130     ma_result (* onSeek) (ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin);
9131     ma_result (* onTell) (ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor);
9132     ma_result (* onInfo) (ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo);
9133 } ma_vfs_callbacks;
9134
9135 MA_API ma_result ma_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
9136 MA_API ma_result ma_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
9137 MA_API ma_result ma_vfs_close(ma_vfs* pVFS, ma_vfs_file file);
9138 MA_API ma_result ma_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead);
9139 MA_API ma_result ma_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten);
9140 MA_API ma_result ma_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin);
9141 MA_API ma_result ma_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor);
9142 MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo);
9143 MA_API ma_result ma_vfs_open_and_read_file(ma_vfs* pVFS, const char* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks);
9144
9145 typedef struct
9146 {
9147     ma_vfs_callbacks cb;
9148     ma_allocation_callbacks allocationCallbacks;    /* Only used for the wchar_t version of open() on non-Windows platforms. */
9149 } ma_default_vfs;
9150
9151 MA_API ma_result ma_default_vfs_init(ma_default_vfs* pVFS, const ma_allocation_callbacks* pAllocationCallbacks);
9152
9153
9154
9155 typedef ma_result (* ma_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead);
9156 typedef ma_result (* ma_seek_proc)(void* pUserData, ma_int64 offset, ma_seek_origin origin);
9157 typedef ma_result (* ma_tell_proc)(void* pUserData, ma_int64* pCursor);
9158
9159
9160
9161 #if !defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING)
9162 typedef enum
9163 {
9164     ma_encoding_format_unknown = 0,
9165     ma_encoding_format_wav,
9166     ma_encoding_format_flac,
9167     ma_encoding_format_mp3,
9168     ma_encoding_format_vorbis
9169 } ma_encoding_format;
9170 #endif
9171
9172 /************************************************************************************************************************************************************
9173
9174 Decoding
9175 ========
9176
9177 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
9178 you do your own synchronization.
9179
9180 ************************************************************************************************************************************************************/
9181 #ifndef MA_NO_DECODING
9182 typedef struct ma_decoder ma_decoder;
9183
9184
9185 typedef struct
9186 {
9187     ma_format preferredFormat;
9188     ma_uint32 seekPointCount;   /* Set to > 0 to generate a seektable if the decoding backend supports it. */
9189 } ma_decoding_backend_config;
9190
9191 MA_API ma_decoding_backend_config ma_decoding_backend_config_init(ma_format preferredFormat, ma_uint32 seekPointCount);
9192
9193
9194 typedef struct
9195 {
9196     ma_result (* onInit      )(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend);
9197     ma_result (* onInitFile  )(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend);               /* Optional. */
9198     ma_result (* onInitFileW )(void* pUserData, const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend);            /* Optional. */
9199     ma_result (* onInitMemory)(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend);  /* Optional. */
9200     void      (* onUninit    )(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks);
9201 } ma_decoding_backend_vtable;
9202
9203
9204 typedef ma_result (* ma_decoder_read_proc)(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead);         /* Returns the number of bytes read. */
9205 typedef ma_result (* ma_decoder_seek_proc)(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin);
9206 typedef ma_result (* ma_decoder_tell_proc)(ma_decoder* pDecoder, ma_int64* pCursor);
9207
9208 typedef struct
9209 {
9210     ma_format format;      /* Set to 0 or ma_format_unknown to use the stream's internal format. */
9211     ma_uint32 channels;    /* Set to 0 to use the stream's internal channels. */
9212     ma_uint32 sampleRate;  /* Set to 0 to use the stream's internal sample rate. */
9213     ma_channel* pChannelMap;
9214     ma_channel_mix_mode channelMixMode;
9215     ma_dither_mode ditherMode;
9216     ma_resampler_config resampling;
9217     ma_allocation_callbacks allocationCallbacks;
9218     ma_encoding_format encodingFormat;
9219     ma_uint32 seekPointCount;   /* When set to > 0, specifies the number of seek points to use for the generation of a seek table. Not all decoding backends support this. */
9220     ma_decoding_backend_vtable** ppCustomBackendVTables;
9221     ma_uint32 customBackendCount;
9222     void* pCustomBackendUserData;
9223 } ma_decoder_config;
9224
9225 struct ma_decoder
9226 {
9227     ma_data_source_base ds;
9228     ma_data_source* pBackend;                   /* The decoding backend we'll be pulling data from. */
9229     const ma_decoding_backend_vtable* pBackendVTable; /* The vtable for the decoding backend. This needs to be stored so we can access the onUninit() callback. */
9230     void* pBackendUserData;
9231     ma_decoder_read_proc onRead;
9232     ma_decoder_seek_proc onSeek;
9233     ma_decoder_tell_proc onTell;
9234     void* pUserData;
9235     ma_uint64 readPointerInPCMFrames;      /* In output sample rate. Used for keeping track of how many frames are available for decoding. */
9236     ma_format outputFormat;
9237     ma_uint32 outputChannels;
9238     ma_uint32 outputSampleRate;
9239     ma_data_converter converter;    /* Data conversion is achieved by running frames through this. */
9240     void* pInputCache;              /* In input format. Can be null if it's not needed. */
9241     ma_uint64 inputCacheCap;        /* The capacity of the input cache. */
9242     ma_uint64 inputCacheConsumed;   /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */
9243     ma_uint64 inputCacheRemaining;  /* The number of valid frames remaining in the cahce. */
9244     ma_allocation_callbacks allocationCallbacks;
9245     union
9246     {
9247         struct
9248         {
9249             ma_vfs* pVFS;
9250             ma_vfs_file file;
9251         } vfs;
9252         struct
9253         {
9254             const ma_uint8* pData;
9255             size_t dataSize;
9256             size_t currentReadPos;
9257         } memory;               /* Only used for decoders that were opened against a block of memory. */
9258     } data;
9259 };
9260
9261 MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate);
9262 MA_API ma_decoder_config ma_decoder_config_init_default(void);
9263
9264 MA_API 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);
9265 MA_API ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
9266 MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
9267 MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
9268 MA_API ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
9269 MA_API ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
9270
9271 /*
9272 Uninitializes a decoder.
9273 */
9274 MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder);
9275
9276 /*
9277 Reads PCM frames from the given decoder.
9278
9279 This is not thread safe without your own synchronization.
9280 */
9281 MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
9282
9283 /*
9284 Seeks to a PCM frame based on it's absolute index.
9285
9286 This is not thread safe without your own synchronization.
9287 */
9288 MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex);
9289
9290 /*
9291 Retrieves the decoder's output data format.
9292 */
9293 MA_API ma_result ma_decoder_get_data_format(ma_decoder* pDecoder, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
9294
9295 /*
9296 Retrieves the current position of the read cursor in PCM frames.
9297 */
9298 MA_API ma_result ma_decoder_get_cursor_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pCursor);
9299
9300 /*
9301 Retrieves the length of the decoder in PCM frames.
9302
9303 Do not call this on streams of an undefined length, such as internet radio.
9304
9305 If the length is unknown or an error occurs, 0 will be returned.
9306
9307 This will always return 0 for Vorbis decoders. This is due to a limitation with stb_vorbis in push mode which is what miniaudio
9308 uses internally.
9309
9310 For MP3's, this will decode the entire file. Do not call this in time critical scenarios.
9311
9312 This function is not thread safe without your own synchronization.
9313 */
9314 MA_API ma_result ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pLength);
9315
9316 /*
9317 Retrieves the number of frames that can be read before reaching the end.
9318
9319 This calls `ma_decoder_get_length_in_pcm_frames()` so you need to be aware of the rules for that function, in
9320 particular ensuring you do not call it on streams of an undefined length, such as internet radio.
9321
9322 If the total length of the decoder cannot be retrieved, such as with Vorbis decoders, `MA_NOT_IMPLEMENTED` will be
9323 returned.
9324 */
9325 MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64* pAvailableFrames);
9326
9327 /*
9328 Helper for opening and decoding a file into a heap allocated block of memory. Free the returned pointer with ma_free(). On input,
9329 pConfig should be set to what you want. On output it will be set to what you got.
9330 */
9331 MA_API ma_result ma_decode_from_vfs(ma_vfs* pVFS, const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
9332 MA_API ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
9333 MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
9334
9335 #endif  /* MA_NO_DECODING */
9336
9337
9338 /************************************************************************************************************************************************************
9339
9340 Encoding
9341 ========
9342
9343 Encoders do not perform any format conversion for you. If your target format does not support the format, and error will be returned.
9344
9345 ************************************************************************************************************************************************************/
9346 #ifndef MA_NO_ENCODING
9347 typedef struct ma_encoder ma_encoder;
9348
9349 typedef size_t    (* ma_encoder_write_proc)           (ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite);     /* Returns the number of bytes written. */
9350 typedef ma_bool32 (* ma_encoder_seek_proc)            (ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin);
9351 typedef ma_result (* ma_encoder_init_proc)            (ma_encoder* pEncoder);
9352 typedef void      (* ma_encoder_uninit_proc)          (ma_encoder* pEncoder);
9353 typedef ma_result (* ma_encoder_write_pcm_frames_proc)(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten);
9354
9355 typedef struct
9356 {
9357     ma_encoding_format encodingFormat;
9358     ma_format format;
9359     ma_uint32 channels;
9360     ma_uint32 sampleRate;
9361     ma_allocation_callbacks allocationCallbacks;
9362 } ma_encoder_config;
9363
9364 MA_API ma_encoder_config ma_encoder_config_init(ma_encoding_format encodingFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate);
9365
9366 struct ma_encoder
9367 {
9368     ma_encoder_config config;
9369     ma_encoder_write_proc onWrite;
9370     ma_encoder_seek_proc onSeek;
9371     ma_encoder_init_proc onInit;
9372     ma_encoder_uninit_proc onUninit;
9373     ma_encoder_write_pcm_frames_proc onWritePCMFrames;
9374     void* pUserData;
9375     void* pInternalEncoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */
9376     void* pFile;    /* FILE*. Only used when initialized with ma_encoder_init_file(). */
9377 };
9378
9379 MA_API 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);
9380 MA_API ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder);
9381 MA_API ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder);
9382 MA_API void ma_encoder_uninit(ma_encoder* pEncoder);
9383 MA_API ma_result ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten);
9384
9385 #endif /* MA_NO_ENCODING */
9386
9387
9388 /************************************************************************************************************************************************************
9389
9390 Generation
9391
9392 ************************************************************************************************************************************************************/
9393 #ifndef MA_NO_GENERATION
9394 typedef enum
9395 {
9396     ma_waveform_type_sine,
9397     ma_waveform_type_square,
9398     ma_waveform_type_triangle,
9399     ma_waveform_type_sawtooth
9400 } ma_waveform_type;
9401
9402 typedef struct
9403 {
9404     ma_format format;
9405     ma_uint32 channels;
9406     ma_uint32 sampleRate;
9407     ma_waveform_type type;
9408     double amplitude;
9409     double frequency;
9410 } ma_waveform_config;
9411
9412 MA_API ma_waveform_config ma_waveform_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_waveform_type type, double amplitude, double frequency);
9413
9414 typedef struct
9415 {
9416     ma_data_source_base ds;
9417     ma_waveform_config config;
9418     double advance;
9419     double time;
9420 } ma_waveform;
9421
9422 MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform);
9423 MA_API void ma_waveform_uninit(ma_waveform* pWaveform);
9424 MA_API ma_result ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
9425 MA_API ma_result ma_waveform_seek_to_pcm_frame(ma_waveform* pWaveform, ma_uint64 frameIndex);
9426 MA_API ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude);
9427 MA_API ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency);
9428 MA_API ma_result ma_waveform_set_type(ma_waveform* pWaveform, ma_waveform_type type);
9429 MA_API ma_result ma_waveform_set_sample_rate(ma_waveform* pWaveform, ma_uint32 sampleRate);
9430
9431 typedef enum
9432 {
9433     ma_noise_type_white,
9434     ma_noise_type_pink,
9435     ma_noise_type_brownian
9436 } ma_noise_type;
9437
9438
9439 typedef struct
9440 {
9441     ma_format format;
9442     ma_uint32 channels;
9443     ma_noise_type type;
9444     ma_int32 seed;
9445     double amplitude;
9446     ma_bool32 duplicateChannels;
9447 } ma_noise_config;
9448
9449 MA_API ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels, ma_noise_type type, ma_int32 seed, double amplitude);
9450
9451 typedef struct
9452 {
9453     ma_data_source_vtable ds;
9454     ma_noise_config config;
9455     ma_lcg lcg;
9456     union
9457     {
9458         struct
9459         {
9460             double** bin;
9461             double* accumulation;
9462             ma_uint32* counter;
9463         } pink;
9464         struct
9465         {
9466             double* accumulation;
9467         } brownian;
9468     } state;
9469
9470     /* Memory management. */
9471     void* _pHeap;
9472     ma_bool32 _ownsHeap;
9473 } ma_noise;
9474
9475 MA_API ma_result ma_noise_get_heap_size(const ma_noise_config* pConfig, size_t* pHeapSizeInBytes);
9476 MA_API ma_result ma_noise_init_preallocated(const ma_noise_config* pConfig, void* pHeap, ma_noise* pNoise);
9477 MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_noise* pNoise);
9478 MA_API void ma_noise_uninit(ma_noise* pNoise, const ma_allocation_callbacks* pAllocationCallbacks);
9479 MA_API ma_result ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
9480 MA_API ma_result ma_noise_set_amplitude(ma_noise* pNoise, double amplitude);
9481 MA_API ma_result ma_noise_set_seed(ma_noise* pNoise, ma_int32 seed);
9482 MA_API ma_result ma_noise_set_type(ma_noise* pNoise, ma_noise_type type);
9483
9484 #endif  /* MA_NO_GENERATION */
9485
9486
9487
9488 /************************************************************************************************************************************************************
9489
9490 Resource Manager
9491
9492 ************************************************************************************************************************************************************/
9493 /* The resource manager cannot be enabled if there is no decoder. */
9494 #if !defined(MA_NO_RESOURCE_MANAGER) && defined(MA_NO_DECODING)
9495 #define MA_NO_RESOURCE_MANAGER
9496 #endif
9497
9498 #ifndef MA_NO_RESOURCE_MANAGER
9499 typedef struct ma_resource_manager                  ma_resource_manager;
9500 typedef struct ma_resource_manager_data_buffer_node ma_resource_manager_data_buffer_node;
9501 typedef struct ma_resource_manager_data_buffer      ma_resource_manager_data_buffer;
9502 typedef struct ma_resource_manager_data_stream      ma_resource_manager_data_stream;
9503 typedef struct ma_resource_manager_data_source      ma_resource_manager_data_source;
9504
9505 typedef enum
9506 {
9507     MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM    = 0x00000001,    /* When set, does not load the entire data source in memory. Disk I/O will happen on job threads. */
9508     MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE    = 0x00000002,    /* Decode data before storing in memory. When set, decoding is done at the resource manager level rather than the mixing thread. Results in faster mixing, but higher memory usage. */
9509     MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC     = 0x00000004,    /* When set, the resource manager will load the data source asynchronously. */
9510     MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT = 0x00000008     /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */
9511 } ma_resource_manager_data_source_flags;
9512
9513 typedef enum
9514 {
9515     MA_RESOURCE_MANAGER_JOB_QUIT                   = 0x00000000,
9516     MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE  = 0x00000001,
9517     MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER_NODE  = 0x00000002,
9518     MA_RESOURCE_MANAGER_JOB_PAGE_DATA_BUFFER_NODE  = 0x00000003,
9519     MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER       = 0x00000004,
9520     MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER       = 0x00000005,
9521     MA_RESOURCE_MANAGER_JOB_LOAD_DATA_STREAM       = 0x00000006,
9522     MA_RESOURCE_MANAGER_JOB_FREE_DATA_STREAM       = 0x00000007,
9523     MA_RESOURCE_MANAGER_JOB_PAGE_DATA_STREAM       = 0x00000008,
9524     MA_RESOURCE_MANAGER_JOB_SEEK_DATA_STREAM       = 0x00000009,
9525     MA_RESOURCE_MANAGER_JOB_CUSTOM                 = 0x00000100  /* Number your custom job codes as (MA_RESOURCE_MANAGER_JOB_CUSTOM + 0), (MA_RESOURCE_MANAGER_JOB_CUSTOM + 1), etc. */
9526 } ma_resource_manager_job_type;
9527
9528
9529 /*
9530 Pipeline notifications used by the resource manager. Made up of both an async notification and a fence, both of which are optional.
9531 */
9532 typedef struct
9533 {
9534     ma_async_notification* pNotification;
9535     ma_fence* pFence;
9536 } ma_resource_manager_pipeline_stage_notification;
9537
9538 typedef struct
9539 {
9540     ma_resource_manager_pipeline_stage_notification init;    /* Initialization of the decoder. */
9541     ma_resource_manager_pipeline_stage_notification done;    /* Decoding fully completed. */
9542 } ma_resource_manager_pipeline_notifications;
9543
9544 MA_API ma_resource_manager_pipeline_notifications ma_resource_manager_pipeline_notifications_init(void);
9545
9546
9547 typedef struct
9548 {
9549     union
9550     {
9551         struct
9552         {
9553             ma_uint16 code;
9554             ma_uint16 slot;
9555             ma_uint32 refcount;
9556         } breakup;
9557         ma_uint64 allocation;
9558     } toc;  /* 8 bytes. We encode the job code into the slot allocation data to save space. */
9559     MA_ATOMIC(8, ma_uint64) next; /* refcount + slot for the next item. Does not include the job code. */
9560     ma_uint32 order;    /* Execution order. Used to create a data dependency and ensure a job is executed in order. Usage is contextual depending on the job type. */
9561
9562     union
9563     {
9564         /* Resource Managemer Jobs */
9565         struct
9566         {
9567             ma_resource_manager_data_buffer_node* pDataBufferNode;
9568             char* pFilePath;
9569             wchar_t* pFilePathW;
9570             ma_bool32 decode;                               /* When set to true, the data buffer will be decoded. Otherwise it'll be encoded and will use a decoder for the connector. */
9571             ma_async_notification* pInitNotification;       /* Signalled when the data buffer has been initialized and the format/channels/rate can be retrieved. */
9572             ma_async_notification* pDoneNotification;       /* Signalled when the data buffer has been fully decoded. Will be passed through to MA_RESOURCE_MANAGER_JOB_PAGE_DATA_BUFFER_NODE when decoding. */
9573             ma_fence* pInitFence;                           /* Released when initialization of the decoder is complete. */
9574             ma_fence* pDoneFence;                           /* Released if initialization of the decoder fails. Passed through to PAGE_DATA_BUFFER_NODE untouched if init is successful. */
9575         } loadDataBufferNode;
9576         struct
9577         {
9578             ma_resource_manager_data_buffer_node* pDataBufferNode;
9579             ma_async_notification* pDoneNotification;
9580             ma_fence* pDoneFence;
9581         } freeDataBufferNode;
9582         struct
9583         {
9584             ma_resource_manager_data_buffer_node* pDataBufferNode;
9585             ma_decoder* pDecoder;
9586             ma_async_notification* pDoneNotification;       /* Signalled when the data buffer has been fully decoded. */
9587             ma_fence* pDoneFence;                           /* Passed through from LOAD_DATA_BUFFER_NODE and released when the data buffer completes decoding or an error occurs. */
9588         } pageDataBufferNode;
9589
9590         struct
9591         {
9592             ma_resource_manager_data_buffer* pDataBuffer;
9593             ma_async_notification* pInitNotification;       /* Signalled when the data buffer has been initialized and the format/channels/rate can be retrieved. */
9594             ma_async_notification* pDoneNotification;       /* Signalled when the data buffer has been fully decoded. */
9595             ma_fence* pInitFence;                           /* Released when the data buffer has been initialized and the format/channels/rate can be retrieved. */
9596             ma_fence* pDoneFence;                           /* Released when the data buffer has been fully decoded. */
9597         } loadDataBuffer;
9598         struct
9599         {
9600             ma_resource_manager_data_buffer* pDataBuffer;
9601             ma_async_notification* pDoneNotification;
9602             ma_fence* pDoneFence;
9603         } freeDataBuffer;
9604
9605         struct
9606         {
9607             ma_resource_manager_data_stream* pDataStream;
9608             char* pFilePath;                            /* Allocated when the job is posted, freed by the job thread after loading. */
9609             wchar_t* pFilePathW;                        /* ^ As above ^. Only used if pFilePath is NULL. */
9610             ma_uint64 initialSeekPoint;
9611             ma_async_notification* pInitNotification;   /* Signalled after the first two pages have been decoded and frames can be read from the stream. */
9612             ma_fence* pInitFence;
9613         } loadDataStream;
9614         struct
9615         {
9616             ma_resource_manager_data_stream* pDataStream;
9617             ma_async_notification* pDoneNotification;
9618             ma_fence* pDoneFence;
9619         } freeDataStream;
9620         struct
9621         {
9622             ma_resource_manager_data_stream* pDataStream;
9623             ma_uint32 pageIndex;                    /* The index of the page to decode into. */
9624         } pageDataStream;
9625         struct
9626         {
9627             ma_resource_manager_data_stream* pDataStream;
9628             ma_uint64 frameIndex;
9629         } seekDataStream;
9630
9631         /* Others. */
9632         struct
9633         {
9634             ma_uintptr data0;
9635             ma_uintptr data1;
9636         } custom;
9637     } data;
9638 } ma_resource_manager_job;
9639
9640 MA_API ma_resource_manager_job ma_resource_manager_job_init(ma_uint16 code);
9641
9642
9643 /*
9644 When set, ma_resource_manager_job_queue_next() will not wait and no semaphore will be signaled in
9645 ma_resource_manager_job_queue_post(). ma_resource_manager_job_queue_next() will return MA_NO_DATA_AVAILABLE if nothing is available.
9646
9647 This flag should always be used for platforms that do not support multithreading.
9648 */
9649 typedef enum
9650 {
9651     MA_RESOURCE_MANAGER_JOB_QUEUE_FLAG_NON_BLOCKING = 0x00000001
9652 } ma_resource_manager_job_queue_flags;
9653
9654 typedef struct
9655 {
9656     ma_uint32 flags;
9657     ma_uint32 capacity; /* The maximum number of jobs that can fit in the queue at a time. */
9658 } ma_resource_manager_job_queue_config;
9659
9660 MA_API ma_resource_manager_job_queue_config ma_resource_manager_job_queue_config_init(ma_uint32 flags, ma_uint32 capacity);
9661
9662
9663 typedef struct
9664 {
9665     ma_uint32 flags;                /* Flags passed in at initialization time. */
9666     ma_uint32 capacity;             /* The maximum number of jobs that can fit in the queue at a time. Set by the config. */
9667     MA_ATOMIC(8, ma_uint64) head;   /* The first item in the list. Required for removing from the top of the list. */
9668     MA_ATOMIC(8, ma_uint64) tail;   /* The last item in the list. Required for appending to the end of the list. */
9669 #ifndef MA_NO_THREADING
9670     ma_semaphore sem;               /* Only used when MA_RESOURCE_MANAGER_JOB_QUEUE_FLAG_NON_BLOCKING is unset. */
9671 #endif
9672     ma_slot_allocator allocator;
9673     ma_resource_manager_job* pJobs;
9674 #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
9675     ma_spinlock lock;
9676 #endif
9677
9678     /* Memory management. */
9679     void* _pHeap;
9680     ma_bool32 _ownsHeap;
9681 } ma_resource_manager_job_queue;
9682
9683 MA_API ma_result ma_resource_manager_job_queue_get_heap_size(const ma_resource_manager_job_queue_config* pConfig, size_t* pHeapSizeInBytes);
9684 MA_API ma_result ma_resource_manager_job_queue_init_preallocated(const ma_resource_manager_job_queue_config* pConfig, void* pHeap, ma_resource_manager_job_queue* pQueue);
9685 MA_API ma_result ma_resource_manager_job_queue_init(const ma_resource_manager_job_queue_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_resource_manager_job_queue* pQueue);
9686 MA_API void ma_resource_manager_job_queue_uninit(ma_resource_manager_job_queue* pQueue, const ma_allocation_callbacks* pAllocationCallbacks);
9687 MA_API ma_result ma_resource_manager_job_queue_post(ma_resource_manager_job_queue* pQueue, const ma_resource_manager_job* pJob);
9688 MA_API ma_result ma_resource_manager_job_queue_next(ma_resource_manager_job_queue* pQueue, ma_resource_manager_job* pJob); /* Returns MA_CANCELLED if the next job is a quit job. */
9689
9690
9691 /* Maximum job thread count will be restricted to this, but this may be removed later and replaced with a heap allocation thereby removing any limitation. */
9692 #ifndef MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT
9693 #define MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT    64
9694 #endif
9695
9696 typedef enum
9697 {
9698     /* Indicates ma_resource_manager_next_job() should not block. Only valid when the job thread count is 0. */
9699     MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING = 0x00000001,
9700
9701     /* Disables any kind of multithreading. Implicitly enables MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. */
9702     MA_RESOURCE_MANAGER_FLAG_NO_THREADING = 0x00000002
9703 } ma_resource_manager_flags;
9704
9705 typedef struct
9706 {
9707     const char* pFilePath;
9708     const wchar_t* pFilePathW;
9709     const ma_resource_manager_pipeline_notifications* pNotifications;
9710     ma_uint64 initialSeekPointInPCMFrames;
9711     ma_uint64 rangeBegInPCMFrames;
9712     ma_uint64 rangeEndInPCMFrames;
9713     ma_uint64 loopPointBegInPCMFrames;
9714     ma_uint64 loopPointEndInPCMFrames;
9715     ma_bool32 isLooping;
9716     ma_uint32 flags;
9717 } ma_resource_manager_data_source_config;
9718
9719 MA_API ma_resource_manager_data_source_config ma_resource_manager_data_source_config_init(void);
9720
9721
9722 typedef enum
9723 {
9724     ma_resource_manager_data_supply_type_unknown = 0,   /* Used for determining whether or the data supply has been initialized. */
9725     ma_resource_manager_data_supply_type_encoded,       /* Data supply is an encoded buffer. Connector is ma_decoder. */
9726     ma_resource_manager_data_supply_type_decoded,       /* Data supply is a decoded buffer. Connector is ma_audio_buffer. */
9727     ma_resource_manager_data_supply_type_decoded_paged  /* Data supply is a linked list of decoded buffers. Connector is ma_paged_audio_buffer. */
9728 } ma_resource_manager_data_supply_type;
9729
9730 typedef struct
9731 {
9732     MA_ATOMIC(4, ma_resource_manager_data_supply_type) type;    /* Read and written from different threads so needs to be accessed atomically. */
9733     union
9734     {
9735         struct
9736         {
9737             const void* pData;
9738             size_t sizeInBytes;
9739         } encoded;
9740         struct
9741         {
9742             const void* pData;
9743             ma_uint64 totalFrameCount;
9744             ma_uint64 decodedFrameCount;
9745             ma_format format;
9746             ma_uint32 channels;
9747             ma_uint32 sampleRate;
9748         } decoded;
9749         struct
9750         {
9751             ma_paged_audio_buffer_data data;
9752             ma_uint64 decodedFrameCount;
9753             ma_uint32 sampleRate;
9754         } decodedPaged;
9755     } backend;
9756 } ma_resource_manager_data_supply;
9757
9758 struct ma_resource_manager_data_buffer_node
9759 {
9760     ma_uint32 hashedName32;                         /* The hashed name. This is the key. */
9761     ma_uint32 refCount;
9762     MA_ATOMIC(4, ma_result) result;                 /* Result from asynchronous loading. When loading set to MA_BUSY. When fully loaded set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. */
9763     MA_ATOMIC(4, ma_uint32) executionCounter;       /* For allocating execution orders for jobs. */
9764     MA_ATOMIC(4, ma_uint32) executionPointer;       /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
9765     ma_bool32 isDataOwnedByResourceManager;         /* Set to true when the underlying data buffer was allocated the resource manager. Set to false if it is owned by the application (via ma_resource_manager_register_*()). */
9766     ma_resource_manager_data_supply data;
9767     ma_resource_manager_data_buffer_node* pParent;
9768     ma_resource_manager_data_buffer_node* pChildLo;
9769     ma_resource_manager_data_buffer_node* pChildHi;
9770 };
9771
9772 struct ma_resource_manager_data_buffer
9773 {
9774     ma_data_source_base ds;                         /* Base data source. A data buffer is a data source. */
9775     ma_resource_manager* pResourceManager;          /* A pointer to the resource manager that owns this buffer. */
9776     ma_resource_manager_data_buffer_node* pNode;    /* The data node. This is reference counted and is what supplies the data. */
9777     ma_uint32 flags;                                /* The flags that were passed used to initialize the buffer. */
9778     MA_ATOMIC(4, ma_uint32) executionCounter;       /* For allocating execution orders for jobs. */
9779     MA_ATOMIC(4, ma_uint32) executionPointer;       /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
9780     ma_uint64 seekTargetInPCMFrames;                /* Only updated by the public API. Never written nor read from the job thread. */
9781     ma_bool32 seekToCursorOnNextRead;               /* On the next read we need to seek to the frame cursor. */
9782     MA_ATOMIC(4, ma_result) result;                 /* Keeps track of a result of decoding. Set to MA_BUSY while the buffer is still loading. Set to MA_SUCCESS when loading is finished successfully. Otherwise set to some other code. */
9783     MA_ATOMIC(4, ma_bool32) isLooping;              /* Can be read and written by different threads at the same time. Must be used atomically. */
9784     ma_bool32 isConnectorInitialized;               /* Used for asynchronous loading to ensure we don't try to initialize the connector multiple times while waiting for the node to fully load. */
9785     union
9786     {
9787         ma_decoder decoder;                 /* Supply type is ma_resource_manager_data_supply_type_encoded */
9788         ma_audio_buffer buffer;             /* Supply type is ma_resource_manager_data_supply_type_decoded */
9789         ma_paged_audio_buffer pagedBuffer;  /* Supply type is ma_resource_manager_data_supply_type_decoded_paged */
9790     } connector;    /* Connects this object to the node's data supply. */
9791 };
9792
9793 struct ma_resource_manager_data_stream
9794 {
9795     ma_data_source_base ds;                     /* Base data source. A data stream is a data source. */
9796     ma_resource_manager* pResourceManager;      /* A pointer to the resource manager that owns this data stream. */
9797     ma_uint32 flags;                            /* The flags that were passed used to initialize the stream. */
9798     ma_decoder decoder;                         /* Used for filling pages with data. This is only ever accessed by the job thread. The public API should never touch this. */
9799     ma_bool32 isDecoderInitialized;             /* Required for determining whether or not the decoder should be uninitialized in MA_RESOURCE_MANAGER_JOB_FREE_DATA_STREAM. */
9800     ma_uint64 totalLengthInPCMFrames;           /* This is calculated when first loaded by the MA_RESOURCE_MANAGER_JOB_LOAD_DATA_STREAM. */
9801     ma_uint32 relativeCursor;                   /* The playback cursor, relative to the current page. Only ever accessed by the public API. Never accessed by the job thread. */
9802     MA_ATOMIC(8, ma_uint64) absoluteCursor;     /* The playback cursor, in absolute position starting from the start of the file. */
9803     ma_uint32 currentPageIndex;                 /* Toggles between 0 and 1. Index 0 is the first half of pPageData. Index 1 is the second half. Only ever accessed by the public API. Never accessed by the job thread. */
9804     MA_ATOMIC(4, ma_uint32) executionCounter;   /* For allocating execution orders for jobs. */
9805     MA_ATOMIC(4, ma_uint32) executionPointer;   /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
9806
9807     /* Written by the public API, read by the job thread. */
9808     MA_ATOMIC(4, ma_bool32) isLooping;          /* Whether or not the stream is looping. It's important to set the looping flag at the data stream level for smooth loop transitions. */
9809
9810     /* Written by the job thread, read by the public API. */
9811     void* pPageData;                            /* Buffer containing the decoded data of each page. Allocated once at initialization time. */
9812     MA_ATOMIC(4, ma_uint32) pageFrameCount[2];  /* The number of valid PCM frames in each page. Used to determine the last valid frame. */
9813
9814     /* Written and read by both the public API and the job thread. These must be atomic. */
9815     MA_ATOMIC(4, ma_result) result;             /* Result from asynchronous loading. When loading set to MA_BUSY. When initialized set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. If an error occurs when loading, set to an error code. */
9816     MA_ATOMIC(4, ma_bool32) isDecoderAtEnd;     /* Whether or not the decoder has reached the end. */
9817     MA_ATOMIC(4, ma_bool32) isPageValid[2];     /* Booleans to indicate whether or not a page is valid. Set to false by the public API, set to true by the job thread. Set to false as the pages are consumed, true when they are filled. */
9818     MA_ATOMIC(4, ma_bool32) seekCounter;        /* When 0, no seeking is being performed. When > 0, a seek is being performed and reading should be delayed with MA_BUSY. */
9819 };
9820
9821 struct ma_resource_manager_data_source
9822 {
9823     union
9824     {
9825         ma_resource_manager_data_buffer buffer;
9826         ma_resource_manager_data_stream stream;
9827     } backend;  /* Must be the first item because we need the first item to be the data source callbacks for the buffer or stream. */
9828
9829     ma_uint32 flags;                          /* The flags that were passed in to ma_resource_manager_data_source_init(). */
9830     MA_ATOMIC(4, ma_uint32) executionCounter;     /* For allocating execution orders for jobs. */
9831     MA_ATOMIC(4, ma_uint32) executionPointer;     /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
9832 };
9833
9834 typedef struct
9835 {
9836     ma_allocation_callbacks allocationCallbacks;
9837     ma_log* pLog;
9838     ma_format decodedFormat;        /* The decoded format to use. Set to ma_format_unknown (default) to use the file's native format. */
9839     ma_uint32 decodedChannels;      /* The decoded channel count to use. Set to 0 (default) to use the file's native channel count. */
9840     ma_uint32 decodedSampleRate;    /* the decoded sample rate to use. Set to 0 (default) to use the file's native sample rate. */
9841     ma_uint32 jobThreadCount;       /* Set to 0 if you want to self-manage your job threads. Defaults to 1. */
9842     ma_uint32 jobQueueCapacity;     /* The maximum number of jobs that can fit in the queue at a time. Defaults to MA_RESOURCE_MANAGER_JOB_QUEUE_CAPACITY. Cannot be zero. */
9843     ma_uint32 flags;
9844     ma_vfs* pVFS;                   /* Can be NULL in which case defaults will be used. */
9845     ma_decoding_backend_vtable** ppCustomDecodingBackendVTables;
9846     ma_uint32 customDecodingBackendCount;
9847     void* pCustomDecodingBackendUserData;
9848 } ma_resource_manager_config;
9849
9850 MA_API ma_resource_manager_config ma_resource_manager_config_init(void);
9851
9852 struct ma_resource_manager
9853 {
9854     ma_resource_manager_config config;
9855     ma_resource_manager_data_buffer_node* pRootDataBufferNode;      /* The root buffer in the binary tree. */
9856 #ifndef MA_NO_THREADING
9857     ma_mutex dataBufferBSTLock;                                     /* For synchronizing access to the data buffer binary tree. */
9858     ma_thread jobThreads[MA_RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT]; /* The threads for executing jobs. */
9859 #endif
9860     ma_resource_manager_job_queue jobQueue;                         /* Multi-consumer, multi-producer job queue for managing jobs for asynchronous decoding and streaming. */
9861     ma_default_vfs defaultVFS;                                      /* Only used if a custom VFS is not specified. */
9862     ma_log log;                                                     /* Only used if no log was specified in the config. */
9863 };
9864
9865 /* Init. */
9866 MA_API ma_result ma_resource_manager_init(const ma_resource_manager_config* pConfig, ma_resource_manager* pResourceManager);
9867 MA_API void ma_resource_manager_uninit(ma_resource_manager* pResourceManager);
9868 MA_API ma_log* ma_resource_manager_get_log(ma_resource_manager* pResourceManager);
9869
9870 /* Registration. */
9871 MA_API ma_result ma_resource_manager_register_file(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags);
9872 MA_API ma_result ma_resource_manager_register_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags);
9873 MA_API ma_result ma_resource_manager_register_decoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate);  /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */
9874 MA_API ma_result ma_resource_manager_register_decoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate);
9875 MA_API ma_result ma_resource_manager_register_encoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, size_t sizeInBytes);    /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */
9876 MA_API ma_result ma_resource_manager_register_encoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, size_t sizeInBytes);
9877 MA_API ma_result ma_resource_manager_unregister_file(ma_resource_manager* pResourceManager, const char* pFilePath);
9878 MA_API ma_result ma_resource_manager_unregister_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath);
9879 MA_API ma_result ma_resource_manager_unregister_data(ma_resource_manager* pResourceManager, const char* pName);
9880 MA_API ma_result ma_resource_manager_unregister_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName);
9881
9882 /* Data Buffers. */
9883 MA_API ma_result ma_resource_manager_data_buffer_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_buffer* pDataBuffer);
9884 MA_API ma_result ma_resource_manager_data_buffer_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer);
9885 MA_API ma_result ma_resource_manager_data_buffer_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer);
9886 MA_API ma_result ma_resource_manager_data_buffer_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_buffer* pExistingDataBuffer, ma_resource_manager_data_buffer* pDataBuffer);
9887 MA_API ma_result ma_resource_manager_data_buffer_uninit(ma_resource_manager_data_buffer* pDataBuffer);
9888 MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
9889 MA_API ma_result ma_resource_manager_data_buffer_seek_to_pcm_frame(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64 frameIndex);
9890 MA_API ma_result ma_resource_manager_data_buffer_get_data_format(ma_resource_manager_data_buffer* pDataBuffer, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
9891 MA_API ma_result ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pCursor);
9892 MA_API ma_result ma_resource_manager_data_buffer_get_length_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pLength);
9893 MA_API ma_result ma_resource_manager_data_buffer_result(const ma_resource_manager_data_buffer* pDataBuffer);
9894 MA_API ma_result ma_resource_manager_data_buffer_set_looping(ma_resource_manager_data_buffer* pDataBuffer, ma_bool32 isLooping);
9895 MA_API ma_bool32 ma_resource_manager_data_buffer_is_looping(const ma_resource_manager_data_buffer* pDataBuffer);
9896 MA_API ma_result ma_resource_manager_data_buffer_get_available_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pAvailableFrames);
9897
9898 /* Data Streams. */
9899 MA_API ma_result ma_resource_manager_data_stream_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_stream* pDataStream);
9900 MA_API ma_result ma_resource_manager_data_stream_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream);
9901 MA_API ma_result ma_resource_manager_data_stream_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream);
9902 MA_API ma_result ma_resource_manager_data_stream_uninit(ma_resource_manager_data_stream* pDataStream);
9903 MA_API ma_result ma_resource_manager_data_stream_read_pcm_frames(ma_resource_manager_data_stream* pDataStream, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
9904 MA_API ma_result ma_resource_manager_data_stream_seek_to_pcm_frame(ma_resource_manager_data_stream* pDataStream, ma_uint64 frameIndex);
9905 MA_API ma_result ma_resource_manager_data_stream_get_data_format(ma_resource_manager_data_stream* pDataStream, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
9906 MA_API ma_result ma_resource_manager_data_stream_get_cursor_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pCursor);
9907 MA_API ma_result ma_resource_manager_data_stream_get_length_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pLength);
9908 MA_API ma_result ma_resource_manager_data_stream_result(const ma_resource_manager_data_stream* pDataStream);
9909 MA_API ma_result ma_resource_manager_data_stream_set_looping(ma_resource_manager_data_stream* pDataStream, ma_bool32 isLooping);
9910 MA_API ma_bool32 ma_resource_manager_data_stream_is_looping(const ma_resource_manager_data_stream* pDataStream);
9911 MA_API ma_result ma_resource_manager_data_stream_get_available_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pAvailableFrames);
9912
9913 /* Data Sources. */
9914 MA_API ma_result ma_resource_manager_data_source_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_source* pDataSource);
9915 MA_API ma_result ma_resource_manager_data_source_init(ma_resource_manager* pResourceManager, const char* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource);
9916 MA_API ma_result ma_resource_manager_data_source_init_w(ma_resource_manager* pResourceManager, const wchar_t* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource);
9917 MA_API ma_result ma_resource_manager_data_source_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source* pExistingDataSource, ma_resource_manager_data_source* pDataSource);
9918 MA_API ma_result ma_resource_manager_data_source_uninit(ma_resource_manager_data_source* pDataSource);
9919 MA_API ma_result ma_resource_manager_data_source_read_pcm_frames(ma_resource_manager_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
9920 MA_API ma_result ma_resource_manager_data_source_seek_to_pcm_frame(ma_resource_manager_data_source* pDataSource, ma_uint64 frameIndex);
9921 MA_API ma_result ma_resource_manager_data_source_get_data_format(ma_resource_manager_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
9922 MA_API ma_result ma_resource_manager_data_source_get_cursor_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pCursor);
9923 MA_API ma_result ma_resource_manager_data_source_get_length_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pLength);
9924 MA_API ma_result ma_resource_manager_data_source_result(const ma_resource_manager_data_source* pDataSource);
9925 MA_API ma_result ma_resource_manager_data_source_set_looping(ma_resource_manager_data_source* pDataSource, ma_bool32 isLooping);
9926 MA_API ma_bool32 ma_resource_manager_data_source_is_looping(const ma_resource_manager_data_source* pDataSource);
9927 MA_API ma_result ma_resource_manager_data_source_get_available_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pAvailableFrames);
9928
9929 /* Job management. */
9930 MA_API ma_result ma_resource_manager_post_job(ma_resource_manager* pResourceManager, const ma_resource_manager_job* pJob);
9931 MA_API ma_result ma_resource_manager_post_job_quit(ma_resource_manager* pResourceManager);  /* Helper for posting a quit job. */
9932 MA_API ma_result ma_resource_manager_next_job(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob);
9933 MA_API ma_result ma_resource_manager_process_job(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob);
9934 MA_API ma_result ma_resource_manager_process_next_job(ma_resource_manager* pResourceManager);   /* Returns MA_CANCELLED if a MA_RESOURCE_MANAGER_JOB_QUIT job is found. In non-blocking mode, returns MA_NO_DATA_AVAILABLE if no jobs are available. */
9935 #endif  /* MA_NO_RESOURCE_MANAGER */
9936
9937
9938
9939 /************************************************************************************************************************************************************
9940
9941 Node Graph
9942
9943 ************************************************************************************************************************************************************/
9944 #ifndef MA_NO_NODE_GRAPH
9945 /* Must never exceed 254. */
9946 #ifndef MA_MAX_NODE_BUS_COUNT
9947 #define MA_MAX_NODE_BUS_COUNT       254
9948 #endif
9949
9950 /* Used internally by miniaudio for memory management. Must never exceed MA_MAX_NODE_BUS_COUNT. */
9951 #ifndef MA_MAX_NODE_LOCAL_BUS_COUNT
9952 #define MA_MAX_NODE_LOCAL_BUS_COUNT 2
9953 #endif
9954
9955 /* Use this when the bus count is determined by the node instance rather than the vtable. */
9956 #define MA_NODE_BUS_COUNT_UNKNOWN   255
9957
9958 typedef struct ma_node_graph ma_node_graph;
9959 typedef void ma_node;
9960
9961
9962 /* Node flags. */
9963 typedef enum
9964 {
9965     MA_NODE_FLAG_PASSTHROUGH                = 0x00000001,
9966     MA_NODE_FLAG_CONTINUOUS_PROCESSING      = 0x00000002,
9967     MA_NODE_FLAG_ALLOW_NULL_INPUT           = 0x00000004,
9968     MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES = 0x00000008
9969 } ma_node_flags;
9970
9971
9972 /* The playback state of a node. Either started or stopped. */
9973 typedef enum
9974 {
9975     ma_node_state_started = 0,
9976     ma_node_state_stopped = 1
9977 } ma_node_state;
9978
9979
9980 typedef struct
9981 {
9982     /*
9983     Extended processing callback. This callback is used for effects that process input and output
9984     at different rates (i.e. they perform resampling). This is similar to the simple version, only
9985     they take two seperate frame counts: one for input, and one for output.
9986
9987     On input, `pFrameCountOut` is equal to the capacity of the output buffer for each bus, whereas
9988     `pFrameCountIn` will be equal to the number of PCM frames in each of the buffers in `ppFramesIn`.
9989
9990     On output, set `pFrameCountOut` to the number of PCM frames that were actually output and set
9991     `pFrameCountIn` to the number of input frames that were consumed.
9992     */
9993     void (* onProcess)(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut);
9994
9995     /*
9996     A callback for retrieving the number of a input frames that are required to output the
9997     specified number of output frames. You would only want to implement this when the node performs
9998     resampling. This is optional, even for nodes that perform resampling, but it does offer a
9999     small reduction in latency as it allows miniaudio to calculate the exact number of input frames
10000     to read at a time instead of having to estimate.
10001     */
10002     ma_result (* onGetRequiredInputFrameCount)(ma_node* pNode, ma_uint32 outputFrameCount, ma_uint32* pInputFrameCount);
10003
10004     /*
10005     The number of input buses. This is how many sub-buffers will be contained in the `ppFramesIn`
10006     parameters of the callbacks above.
10007     */
10008     ma_uint8 inputBusCount;
10009
10010     /*
10011     The number of output buses. This is how many sub-buffers will be contained in the `ppFramesOut`
10012     parameters of the callbacks above.
10013     */
10014     ma_uint8 outputBusCount;
10015
10016     /*
10017     Flags describing characteristics of the node. This is currently just a placeholder for some
10018     ideas for later on.
10019     */
10020     ma_uint32 flags;
10021 } ma_node_vtable;
10022
10023 typedef struct
10024 {
10025     const ma_node_vtable* vtable;       /* Should never be null. Initialization of the node will fail if so. */
10026     ma_node_state initialState;         /* Defaults to ma_node_state_started. */
10027     ma_uint32 inputBusCount;            /* Only used if the vtable specifies an input bus count of `MA_NODE_BUS_COUNT_UNKNOWN`, otherwise must be set to `MA_NODE_BUS_COUNT_UNKNOWN` (default). */
10028     ma_uint32 outputBusCount;           /* Only used if the vtable specifies an output bus count of `MA_NODE_BUS_COUNT_UNKNOWN`, otherwise  be set to `MA_NODE_BUS_COUNT_UNKNOWN` (default). */
10029     const ma_uint32* pInputChannels;    /* The number of elements are determined by the input bus count as determined by the vtable, or `inputBusCount` if the vtable specifies `MA_NODE_BUS_COUNT_UNKNOWN`. */
10030     const ma_uint32* pOutputChannels;   /* The number of elements are determined by the output bus count as determined by the vtable, or `outputBusCount` if the vtable specifies `MA_NODE_BUS_COUNT_UNKNOWN`. */
10031 } ma_node_config;
10032
10033 MA_API ma_node_config ma_node_config_init(void);
10034
10035
10036 /*
10037 A node has multiple output buses. An output bus is attached to an input bus as an item in a linked
10038 list. Think of the input bus as a linked list, with the output bus being an item in that list.
10039 */
10040 typedef struct ma_node_output_bus ma_node_output_bus;
10041 struct ma_node_output_bus
10042 {
10043     /* Immutable. */
10044     ma_node* pNode;                                         /* The node that owns this output bus. The input node. Will be null for dummy head and tail nodes. */
10045     ma_uint8 outputBusIndex;                                /* The index of the output bus on pNode that this output bus represents. */
10046     ma_uint8 channels;                                      /* The number of channels in the audio stream for this bus. */
10047
10048     /* Mutable via multiple threads. Must be used atomically. The weird ordering here is for packing reasons. */
10049     MA_ATOMIC(1, ma_uint8) inputNodeInputBusIndex;          /* The index of the input bus on the input. Required for detaching. */
10050     MA_ATOMIC(4, ma_uint32) flags;                          /* Some state flags for tracking the read state of the output buffer. A combination of MA_NODE_OUTPUT_BUS_FLAG_*. */
10051     MA_ATOMIC(4, ma_uint32) refCount;                       /* Reference count for some thread-safety when detaching. */
10052     MA_ATOMIC(4, ma_bool32) isAttached;                     /* This is used to prevent iteration of nodes that are in the middle of being detached. Used for thread safety. */
10053     MA_ATOMIC(4, ma_spinlock) lock;                         /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */
10054     MA_ATOMIC(4, float) volume;                             /* Linear. */
10055     MA_ATOMIC(MA_SIZEOF_PTR, ma_node_output_bus*) pNext;    /* If null, it's the tail node or detached. */
10056     MA_ATOMIC(MA_SIZEOF_PTR, ma_node_output_bus*) pPrev;    /* If null, it's the head node or detached. */
10057     MA_ATOMIC(MA_SIZEOF_PTR, ma_node*) pInputNode;          /* The node that this output bus is attached to. Required for detaching. */
10058 };
10059
10060 /*
10061 A node has multiple input buses. The output buses of a node are connecting to the input busses of
10062 another. An input bus is essentially just a linked list of output buses.
10063 */
10064 typedef struct ma_node_input_bus ma_node_input_bus;
10065 struct ma_node_input_bus
10066 {
10067     /* Mutable via multiple threads. */
10068     ma_node_output_bus head;                /* Dummy head node for simplifying some lock-free thread-safety stuff. */
10069     MA_ATOMIC(4, ma_uint32) nextCounter;    /* This is used to determine whether or not the input bus is finding the next node in the list. Used for thread safety when detaching output buses. */
10070     MA_ATOMIC(4, ma_spinlock) lock;         /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */
10071
10072     /* Set once at startup. */
10073     ma_uint8 channels;                  /* The number of channels in the audio stream for this bus. */
10074 };
10075
10076
10077 typedef struct ma_node_base ma_node_base;
10078 struct ma_node_base
10079 {
10080     /* These variables are set once at startup. */
10081     ma_node_graph* pNodeGraph;  /* The graph this node belongs to. */
10082     const ma_node_vtable* vtable;
10083     float* pCachedData;                     /* Allocated on the heap. Fixed size. Needs to be stored on the heap because reading from output buses is done in separate function calls. */
10084     ma_uint16 cachedDataCapInFramesPerBus;  /* The capacity of the input data cache in frames, per bus. */
10085
10086     /* These variables are read and written only from the audio thread. */
10087     ma_uint16 cachedFrameCountOut;
10088     ma_uint16 cachedFrameCountIn;
10089     ma_uint16 consumedFrameCountIn;
10090
10091     /* These variables are read and written between different threads. */
10092     MA_ATOMIC(4, ma_node_state) state;      /* When set to stopped, nothing will be read, regardless of the times in stateTimes. */
10093     MA_ATOMIC(8, ma_uint64) stateTimes[2];  /* Indexed by ma_node_state. Specifies the time based on the global clock that a node should be considered to be in the relevant state. */
10094     MA_ATOMIC(8, ma_uint64) localTime;      /* The node's local clock. This is just a running sum of the number of output frames that have been processed. Can be modified by any thread with `ma_node_set_time()`. */
10095     ma_uint32 inputBusCount;
10096     ma_uint32 outputBusCount;
10097     ma_node_input_bus* pInputBuses;
10098     ma_node_output_bus* pOutputBuses;
10099
10100     /* Memory management. */
10101     ma_node_input_bus _inputBuses[MA_MAX_NODE_LOCAL_BUS_COUNT];
10102     ma_node_output_bus _outputBuses[MA_MAX_NODE_LOCAL_BUS_COUNT];
10103     void* _pHeap;   /* A heap allocation for internal use only. pInputBuses and/or pOutputBuses will point to this if the bus count exceeds MA_MAX_NODE_LOCAL_BUS_COUNT. */
10104     ma_bool32 _ownsHeap;    /* If set to true, the node owns the heap allocation and _pHeap will be freed in ma_node_uninit(). */
10105 };
10106
10107 MA_API ma_result ma_node_get_heap_size(const ma_node_config* pConfig, size_t* pHeapSizeInBytes);
10108 MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, void* pHeap, ma_node* pNode);
10109 MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node* pNode);
10110 MA_API void ma_node_uninit(ma_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks);
10111 MA_API ma_node_graph* ma_node_get_node_graph(const ma_node* pNode);
10112 MA_API ma_uint32 ma_node_get_input_bus_count(const ma_node* pNode);
10113 MA_API ma_uint32 ma_node_get_output_bus_count(const ma_node* pNode);
10114 MA_API ma_uint32 ma_node_get_input_channels(const ma_node* pNode, ma_uint32 inputBusIndex);
10115 MA_API ma_uint32 ma_node_get_output_channels(const ma_node* pNode, ma_uint32 outputBusIndex);
10116 MA_API ma_result ma_node_attach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex, ma_node* pOtherNode, ma_uint32 otherNodeInputBusIndex);
10117 MA_API ma_result ma_node_detach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex);
10118 MA_API ma_result ma_node_detach_all_output_buses(ma_node* pNode);
10119 MA_API ma_result ma_node_set_output_bus_volume(ma_node* pNode, ma_uint32 outputBusIndex, float volume);
10120 MA_API float ma_node_get_output_bus_volume(const ma_node* pNode, ma_uint32 outputBusIndex);
10121 MA_API ma_result ma_node_set_state(ma_node* pNode, ma_node_state state);
10122 MA_API ma_node_state ma_node_get_state(const ma_node* pNode);
10123 MA_API ma_result ma_node_set_state_time(ma_node* pNode, ma_node_state state, ma_uint64 globalTime);
10124 MA_API ma_uint64 ma_node_get_state_time(const ma_node* pNode, ma_node_state state);
10125 MA_API ma_node_state ma_node_get_state_by_time(const ma_node* pNode, ma_uint64 globalTime);
10126 MA_API ma_node_state ma_node_get_state_by_time_range(const ma_node* pNode, ma_uint64 globalTimeBeg, ma_uint64 globalTimeEnd);
10127 MA_API ma_uint64 ma_node_get_time(const ma_node* pNode);
10128 MA_API ma_result ma_node_set_time(ma_node* pNode, ma_uint64 localTime);
10129
10130
10131 typedef struct
10132 {
10133     ma_uint32 channels;
10134 } ma_node_graph_config;
10135
10136 MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels);
10137
10138
10139 struct ma_node_graph
10140 {
10141     /* Immutable. */
10142     ma_node_base endpoint;              /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */
10143
10144     /* Read and written by multiple threads. */
10145     MA_ATOMIC(4, ma_bool32) isReading;
10146 };
10147
10148 MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph);
10149 MA_API void ma_node_graph_uninit(ma_node_graph* pNodeGraph, const ma_allocation_callbacks* pAllocationCallbacks);
10150 MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph);
10151 MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
10152 MA_API ma_uint32 ma_node_graph_get_channels(const ma_node_graph* pNodeGraph);
10153 MA_API ma_uint64 ma_node_graph_get_time(const ma_node_graph* pNodeGraph);
10154 MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 globalTime);
10155
10156
10157
10158 /* Data source node. 0 input buses, 1 output bus. Used for reading from a data source. */
10159 typedef struct
10160 {
10161     ma_node_config nodeConfig;
10162     ma_data_source* pDataSource;
10163 } ma_data_source_node_config;
10164
10165 MA_API ma_data_source_node_config ma_data_source_node_config_init(ma_data_source* pDataSource);
10166
10167
10168 typedef struct
10169 {
10170     ma_node_base base;
10171     ma_data_source* pDataSource;
10172 } ma_data_source_node;
10173
10174 MA_API ma_result ma_data_source_node_init(ma_node_graph* pNodeGraph, const ma_data_source_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source_node* pDataSourceNode);
10175 MA_API void ma_data_source_node_uninit(ma_data_source_node* pDataSourceNode, const ma_allocation_callbacks* pAllocationCallbacks);
10176 MA_API ma_result ma_data_source_node_set_looping(ma_data_source_node* pDataSourceNode, ma_bool32 isLooping);
10177 MA_API ma_bool32 ma_data_source_node_is_looping(ma_data_source_node* pDataSourceNode);
10178
10179
10180 /* Splitter Node. 1 input, 2 outputs. Used for splitting/copying a stream so it can be as input into two separate output nodes. */
10181 typedef struct
10182 {
10183     ma_node_config nodeConfig;
10184     ma_uint32 channels;
10185 } ma_splitter_node_config;
10186
10187 MA_API ma_splitter_node_config ma_splitter_node_config_init(ma_uint32 channels);
10188
10189
10190 typedef struct
10191 {
10192     ma_node_base base;
10193 } ma_splitter_node;
10194
10195 MA_API ma_result ma_splitter_node_init(ma_node_graph* pNodeGraph, const ma_splitter_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_splitter_node* pSplitterNode);
10196 MA_API void ma_splitter_node_uninit(ma_splitter_node* pSplitterNode, const ma_allocation_callbacks* pAllocationCallbacks);
10197
10198
10199 /*
10200 Biquad Node
10201 */
10202 typedef struct
10203 {
10204     ma_node_config nodeConfig;
10205     ma_biquad_config biquad;
10206 } ma_biquad_node_config;
10207
10208 MA_API ma_biquad_node_config ma_biquad_node_config_init(ma_uint32 channels, float b0, float b1, float b2, float a0, float a1, float a2);
10209
10210
10211 typedef struct
10212 {
10213     ma_node_base baseNode;
10214     ma_biquad biquad;
10215 } ma_biquad_node;
10216
10217 MA_API ma_result ma_biquad_node_init(ma_node_graph* pNodeGraph, const ma_biquad_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad_node* pNode);
10218 MA_API ma_result ma_biquad_node_reinit(const ma_biquad_config* pConfig, ma_biquad_node* pNode);
10219 MA_API void ma_biquad_node_uninit(ma_biquad_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks);
10220
10221
10222 /*
10223 Low Pass Filter Node
10224 */
10225 typedef struct
10226 {
10227     ma_node_config nodeConfig;
10228     ma_lpf_config lpf;
10229 } ma_lpf_node_config;
10230
10231 MA_API ma_lpf_node_config ma_lpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order);
10232
10233
10234 typedef struct
10235 {
10236     ma_node_base baseNode;
10237     ma_lpf lpf;
10238 } ma_lpf_node;
10239
10240 MA_API ma_result ma_lpf_node_init(ma_node_graph* pNodeGraph, const ma_lpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf_node* pNode);
10241 MA_API ma_result ma_lpf_node_reinit(const ma_lpf_config* pConfig, ma_lpf_node* pNode);
10242 MA_API void ma_lpf_node_uninit(ma_lpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks);
10243
10244
10245 /*
10246 High Pass Filter Node
10247 */
10248 typedef struct
10249 {
10250     ma_node_config nodeConfig;
10251     ma_hpf_config hpf;
10252 } ma_hpf_node_config;
10253
10254 MA_API ma_hpf_node_config ma_hpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order);
10255
10256
10257 typedef struct
10258 {
10259     ma_node_base baseNode;
10260     ma_hpf hpf;
10261 } ma_hpf_node;
10262
10263 MA_API ma_result ma_hpf_node_init(ma_node_graph* pNodeGraph, const ma_hpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf_node* pNode);
10264 MA_API ma_result ma_hpf_node_reinit(const ma_hpf_config* pConfig, ma_hpf_node* pNode);
10265 MA_API void ma_hpf_node_uninit(ma_hpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks);
10266
10267
10268 /*
10269 Band Pass Filter Node
10270 */
10271 typedef struct
10272 {
10273     ma_node_config nodeConfig;
10274     ma_bpf_config bpf;
10275 } ma_bpf_node_config;
10276
10277 MA_API ma_bpf_node_config ma_bpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order);
10278
10279
10280 typedef struct
10281 {
10282     ma_node_base baseNode;
10283     ma_bpf bpf;
10284 } ma_bpf_node;
10285
10286 MA_API ma_result ma_bpf_node_init(ma_node_graph* pNodeGraph, const ma_bpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf_node* pNode);
10287 MA_API ma_result ma_bpf_node_reinit(const ma_bpf_config* pConfig, ma_bpf_node* pNode);
10288 MA_API void ma_bpf_node_uninit(ma_bpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks);
10289
10290
10291 /*
10292 Notching Filter Node
10293 */
10294 typedef struct
10295 {
10296     ma_node_config nodeConfig;
10297     ma_notch_config notch;
10298 } ma_notch_node_config;
10299
10300 MA_API ma_notch_node_config ma_notch_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency);
10301
10302
10303 typedef struct
10304 {
10305     ma_node_base baseNode;
10306     ma_notch2 notch;
10307 } ma_notch_node;
10308
10309 MA_API ma_result ma_notch_node_init(ma_node_graph* pNodeGraph, const ma_notch_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch_node* pNode);
10310 MA_API ma_result ma_notch_node_reinit(const ma_notch_config* pConfig, ma_notch_node* pNode);
10311 MA_API void ma_notch_node_uninit(ma_notch_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks);
10312
10313
10314 /*
10315 Peaking Filter Node
10316 */
10317 typedef struct
10318 {
10319     ma_node_config nodeConfig;
10320     ma_peak_config peak;
10321 } ma_peak_node_config;
10322
10323 MA_API ma_peak_node_config ma_peak_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency);
10324
10325
10326 typedef struct
10327 {
10328     ma_node_base baseNode;
10329     ma_peak2 peak;
10330 } ma_peak_node;
10331
10332 MA_API ma_result ma_peak_node_init(ma_node_graph* pNodeGraph, const ma_peak_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak_node* pNode);
10333 MA_API ma_result ma_peak_node_reinit(const ma_peak_config* pConfig, ma_peak_node* pNode);
10334 MA_API void ma_peak_node_uninit(ma_peak_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks);
10335
10336
10337 /*
10338 Low Shelf Filter Node
10339 */
10340 typedef struct
10341 {
10342     ma_node_config nodeConfig;
10343     ma_loshelf_config loshelf;
10344 } ma_loshelf_node_config;
10345
10346 MA_API ma_loshelf_node_config ma_loshelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency);
10347
10348
10349 typedef struct
10350 {
10351     ma_node_base baseNode;
10352     ma_loshelf2 loshelf;
10353 } ma_loshelf_node;
10354
10355 MA_API ma_result ma_loshelf_node_init(ma_node_graph* pNodeGraph, const ma_loshelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf_node* pNode);
10356 MA_API ma_result ma_loshelf_node_reinit(const ma_loshelf_config* pConfig, ma_loshelf_node* pNode);
10357 MA_API void ma_loshelf_node_uninit(ma_loshelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks);
10358
10359
10360 /*
10361 High Shelf Filter Node
10362 */
10363 typedef struct
10364 {
10365     ma_node_config nodeConfig;
10366     ma_hishelf_config hishelf;
10367 } ma_hishelf_node_config;
10368
10369 MA_API ma_hishelf_node_config ma_hishelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency);
10370
10371
10372 typedef struct
10373 {
10374     ma_node_base baseNode;
10375     ma_hishelf2 hishelf;
10376 } ma_hishelf_node;
10377
10378 MA_API ma_result ma_hishelf_node_init(ma_node_graph* pNodeGraph, const ma_hishelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf_node* pNode);
10379 MA_API ma_result ma_hishelf_node_reinit(const ma_hishelf_config* pConfig, ma_hishelf_node* pNode);
10380 MA_API void ma_hishelf_node_uninit(ma_hishelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks);
10381
10382
10383 typedef struct
10384 {
10385     ma_node_config nodeConfig;
10386     ma_delay_config delay;
10387 } ma_delay_node_config;
10388
10389 MA_API ma_delay_node_config ma_delay_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay);
10390
10391
10392 typedef struct
10393 {
10394     ma_node_base baseNode;
10395     ma_delay delay;
10396 } ma_delay_node;
10397
10398 MA_API ma_result ma_delay_node_init(ma_node_graph* pNodeGraph, const ma_delay_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay_node* pDelayNode);
10399 MA_API void ma_delay_node_uninit(ma_delay_node* pDelayNode, const ma_allocation_callbacks* pAllocationCallbacks);
10400 MA_API void ma_delay_node_set_wet(ma_delay_node* pDelayNode, float value);
10401 MA_API float ma_delay_node_get_wet(const ma_delay_node* pDelayNode);
10402 MA_API void ma_delay_node_set_dry(ma_delay_node* pDelayNode, float value);
10403 MA_API float ma_delay_node_get_dry(const ma_delay_node* pDelayNode);
10404 MA_API void ma_delay_node_set_decay(ma_delay_node* pDelayNode, float value);
10405 MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode);
10406 #endif  /* MA_NO_NODE_GRAPH */
10407
10408
10409 /************************************************************************************************************************************************************
10410
10411 Engine
10412
10413 ************************************************************************************************************************************************************/
10414 #if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH)
10415 typedef struct ma_engine ma_engine;
10416 typedef struct ma_sound  ma_sound;
10417
10418
10419 /* Sound flags. */
10420 typedef enum
10421 {
10422     MA_SOUND_FLAG_STREAM                = 0x00000001,   /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM */
10423     MA_SOUND_FLAG_DECODE                = 0x00000002,   /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE */
10424     MA_SOUND_FLAG_ASYNC                 = 0x00000004,   /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC */
10425     MA_SOUND_FLAG_WAIT_INIT             = 0x00000008,   /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT */
10426     MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT = 0x00000010,   /* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */
10427     MA_SOUND_FLAG_NO_PITCH              = 0x00000020,   /* Disable pitch shifting with ma_sound_set_pitch() and ma_sound_group_set_pitch(). This is an optimization. */
10428     MA_SOUND_FLAG_NO_SPATIALIZATION     = 0x00000040    /* Disable spatialization. */
10429 } ma_sound_flags;
10430
10431 #ifndef MA_ENGINE_MAX_LISTENERS
10432 #define MA_ENGINE_MAX_LISTENERS             4
10433 #endif
10434
10435 #define MA_LISTENER_INDEX_CLOSEST           ((ma_uint8)-1)
10436
10437 typedef enum
10438 {
10439     ma_engine_node_type_sound,
10440     ma_engine_node_type_group
10441 } ma_engine_node_type;
10442
10443 typedef struct
10444 {
10445     ma_engine* pEngine;
10446     ma_engine_node_type type;
10447     ma_uint32 channelsIn;
10448     ma_uint32 channelsOut;
10449     ma_uint32 sampleRate;               /* Only used when the type is set to ma_engine_node_type_sound. */
10450     ma_bool8 isPitchDisabled;           /* Pitching can be explicitly disable with MA_SOUND_FLAG_NO_PITCH to optimize processing. */
10451     ma_bool8 isSpatializationDisabled;  /* Spatialization can be explicitly disabled with MA_SOUND_FLAG_NO_SPATIALIZATION. */
10452     ma_uint8 pinnedListenerIndex;       /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */
10453 } ma_engine_node_config;
10454
10455 MA_API ma_engine_node_config ma_engine_node_config_init(ma_engine* pEngine, ma_engine_node_type type, ma_uint32 flags);
10456
10457
10458 /* Base node object for both ma_sound and ma_sound_group. */
10459 typedef struct
10460 {
10461     ma_node_base baseNode;                              /* Must be the first member for compatiblity with the ma_node API. */
10462     ma_engine* pEngine;                                 /* A pointer to the engine. Set based on the value from the config. */
10463     ma_uint32 sampleRate;                               /* The sample rate of the input data. For sounds backed by a data source, this will be the data source's sample rate. Otherwise it'll be the engine's sample rate. */
10464     ma_fader fader;
10465     ma_linear_resampler resampler;                      /* For pitch shift. */
10466     ma_spatializer spatializer;
10467     ma_panner panner;
10468     MA_ATOMIC(4, float) pitch;
10469     float oldPitch;                                     /* For determining whether or not the resampler needs to be updated to reflect the new pitch. The resampler will be updated on the mixing thread. */
10470     float oldDopplerPitch;                              /* For determining whether or not the resampler needs to be updated to take a new doppler pitch into account. */
10471     MA_ATOMIC(4, ma_bool32) isPitchDisabled;            /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */
10472     MA_ATOMIC(4, ma_bool32) isSpatializationDisabled;   /* Set to false by default. When set to false, will not have spatialisation applied. */
10473     MA_ATOMIC(4, ma_uint32) pinnedListenerIndex;        /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */
10474
10475     /* Memory management. */
10476     ma_bool8 _ownsHeap;
10477     void* _pHeap;
10478 } ma_engine_node;
10479
10480 MA_API ma_result ma_engine_node_get_heap_size(const ma_engine_node_config* pConfig, size_t* pHeapSizeInBytes);
10481 MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* pConfig, void* pHeap, ma_engine_node* pEngineNode);
10482 MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode);
10483 MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks);
10484
10485
10486 #define MA_SOUND_SOURCE_CHANNEL_COUNT   0xFFFFFFFF
10487
10488 typedef struct
10489 {
10490     const char* pFilePath;                      /* Set this to load from the resource manager. */
10491     const wchar_t* pFilePathW;                  /* Set this to load from the resource manager. */
10492     ma_data_source* pDataSource;                /* Set this to load from an existing data source. */
10493     ma_node* pInitialAttachment;                /* If set, the sound will be attached to an input of this node. This can be set to a ma_sound. If set to NULL, the sound will be attached directly to the endpoint unless MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT is set in `flags`. */
10494     ma_uint32 initialAttachmentInputBusIndex;   /* The index of the input bus of pInitialAttachment to attach the sound to. */
10495     ma_uint32 channelsIn;                       /* Ignored if using a data source as input (the data source's channel count will be used always). Otherwise, setting to 0 will cause the engine's channel count to be used. */
10496     ma_uint32 channelsOut;                      /* Set this to 0 (default) to use the engine's channel count. Set to MA_SOUND_SOURCE_CHANNEL_COUNT to use the data source's channel count (only used if using a data source as input). */
10497     ma_uint32 flags;                            /* A combination of MA_SOUND_FLAG_* flags. */
10498     ma_uint64 initialSeekPointInPCMFrames;      /* Initializes the sound such that it's seeked to this location by default. */
10499     ma_uint64 rangeBegInPCMFrames;
10500     ma_uint64 rangeEndInPCMFrames;
10501     ma_uint64 loopPointBegInPCMFrames;
10502     ma_uint64 loopPointEndInPCMFrames;
10503     ma_bool32 isLooping;
10504     ma_fence* pDoneFence;                       /* Released when the resource manager has finished decoding the entire sound. Not used with streams. */
10505 } ma_sound_config;
10506
10507 MA_API ma_sound_config ma_sound_config_init(void);
10508
10509 struct ma_sound
10510 {
10511     ma_engine_node engineNode;          /* Must be the first member for compatibility with the ma_node API. */
10512     ma_data_source* pDataSource;
10513     ma_uint64 seekTarget;               /* The PCM frame index to seek to in the mixing thread. Set to (~(ma_uint64)0) to not perform any seeking. */
10514     MA_ATOMIC(4, ma_bool32) atEnd;
10515     ma_bool8 ownsDataSource;
10516
10517     /*
10518     We're declaring a resource manager data source object here to save us a malloc when loading a
10519     sound via the resource manager, which I *think* will be the most common scenario.
10520     */
10521 #ifndef MA_NO_RESOURCE_MANAGER
10522     ma_resource_manager_data_source* pResourceManagerDataSource;
10523 #endif
10524 };
10525
10526 /* Structure specifically for sounds played with ma_engine_play_sound(). Making this a separate structure to reduce overhead. */
10527 typedef struct ma_sound_inlined ma_sound_inlined;
10528 struct ma_sound_inlined
10529 {
10530     ma_sound sound;
10531     ma_sound_inlined* pNext;
10532     ma_sound_inlined* pPrev;
10533 };
10534
10535 /* A sound group is just a sound. */
10536 typedef ma_sound_config ma_sound_group_config;
10537 typedef ma_sound        ma_sound_group;
10538
10539 MA_API ma_sound_group_config ma_sound_group_config_init(void);
10540
10541
10542 typedef struct
10543 {
10544 #if !defined(MA_NO_RESOURCE_MANAGER)
10545     ma_resource_manager* pResourceManager;      /* Can be null in which case a resource manager will be created for you. */
10546 #endif
10547 #if !defined(MA_NO_DEVICE_IO)
10548     ma_context* pContext;
10549     ma_device* pDevice;                         /* If set, the caller is responsible for calling ma_engine_data_callback() in the device's data callback. */
10550     ma_device_id* pPlaybackDeviceID;            /* The ID of the playback device to use with the default listener. */
10551 #endif
10552     ma_log* pLog;                               /* When set to NULL, will use the context's log. */
10553     ma_uint32 listenerCount;                    /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */
10554     ma_uint32 channels;                         /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */
10555     ma_uint32 sampleRate;                       /* The sample rate. When set to 0 will use the native channel count of the device. */
10556     ma_uint32 periodSizeInFrames;               /* If set to something other than 0, updates will always be exactly this size. The underlying device may be a different size, but from the perspective of the mixer that won't matter.*/
10557     ma_uint32 periodSizeInMilliseconds;         /* Used if periodSizeInFrames is unset. */
10558     ma_uint32 gainSmoothTimeInFrames;           /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */
10559     ma_uint32 gainSmoothTimeInMilliseconds;     /* When set to 0, gainSmoothTimeInFrames will be used. If both are set to 0, a default value will be used. */
10560     ma_allocation_callbacks allocationCallbacks;
10561     ma_bool32 noAutoStart;                      /* When set to true, requires an explicit call to ma_engine_start(). This is false by default, meaning the engine will be started automatically in ma_engine_init(). */
10562     ma_bool32 noDevice;                         /* When set to true, don't create a default device. ma_engine_read_pcm_frames() can be called manually to read data. */
10563     ma_mono_expansion_mode monoExpansionMode;   /* Controls how the mono channel should be expanded to other channels when spatialization is disabled on a sound. */
10564     ma_vfs* pResourceManagerVFS;                /* A pointer to a pre-allocated VFS object to use with the resource manager. This is ignored if pResourceManager is not NULL. */
10565 } ma_engine_config;
10566
10567 MA_API ma_engine_config ma_engine_config_init(void);
10568
10569
10570 struct ma_engine
10571 {
10572     ma_node_graph nodeGraph;                /* An engine is a node graph. It should be able to be plugged into any ma_node_graph API (with a cast) which means this must be the first member of this struct. */
10573 #if !defined(MA_NO_RESOURCE_MANAGER)
10574     ma_resource_manager* pResourceManager;
10575 #endif
10576 #if !defined(MA_NO_DEVICE_IO)
10577     ma_device* pDevice;                     /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */
10578 #endif
10579     ma_log* pLog;
10580     ma_uint32 sampleRate;
10581     ma_uint32 listenerCount;
10582     ma_spatializer_listener listeners[MA_ENGINE_MAX_LISTENERS];
10583     ma_allocation_callbacks allocationCallbacks;
10584     ma_bool8 ownsResourceManager;
10585     ma_bool8 ownsDevice;
10586     ma_spinlock inlinedSoundLock;               /* For synchronizing access so the inlined sound list. */
10587     ma_sound_inlined* pInlinedSoundHead;        /* The first inlined sound. Inlined sounds are tracked in a linked list. */
10588     MA_ATOMIC(4, ma_uint32) inlinedSoundCount;  /* The total number of allocated inlined sound objects. Used for debugging. */
10589     ma_uint32 gainSmoothTimeInFrames;           /* The number of frames to interpolate the gain of spatialized sounds across. */
10590     ma_mono_expansion_mode monoExpansionMode;
10591 };
10592
10593 MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine);
10594 MA_API void ma_engine_uninit(ma_engine* pEngine);
10595 MA_API ma_result ma_engine_read_pcm_frames(ma_engine* pEngine, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
10596 MA_API ma_node_graph* ma_engine_get_node_graph(ma_engine* pEngine);
10597 #if !defined(MA_NO_RESOURCE_MANAGER)
10598 MA_API ma_resource_manager* ma_engine_get_resource_manager(ma_engine* pEngine);
10599 #endif
10600 MA_API ma_device* ma_engine_get_device(ma_engine* pEngine);
10601 MA_API ma_log* ma_engine_get_log(ma_engine* pEngine);
10602 MA_API ma_node* ma_engine_get_endpoint(ma_engine* pEngine);
10603 MA_API ma_uint64 ma_engine_get_time(const ma_engine* pEngine);
10604 MA_API ma_uint64 ma_engine_set_time(ma_engine* pEngine, ma_uint64 globalTime);
10605 MA_API ma_uint32 ma_engine_get_channels(const ma_engine* pEngine);
10606 MA_API ma_uint32 ma_engine_get_sample_rate(const ma_engine* pEngine);
10607
10608 MA_API ma_result ma_engine_start(ma_engine* pEngine);
10609 MA_API ma_result ma_engine_stop(ma_engine* pEngine);
10610 MA_API ma_result ma_engine_set_volume(ma_engine* pEngine, float volume);
10611 MA_API ma_result ma_engine_set_gain_db(ma_engine* pEngine, float gainDB);
10612
10613 MA_API ma_uint32 ma_engine_get_listener_count(const ma_engine* pEngine);
10614 MA_API ma_uint32 ma_engine_find_closest_listener(const ma_engine* pEngine, float absolutePosX, float absolutePosY, float absolutePosZ);
10615 MA_API void ma_engine_listener_set_position(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z);
10616 MA_API ma_vec3f ma_engine_listener_get_position(const ma_engine* pEngine, ma_uint32 listenerIndex);
10617 MA_API void ma_engine_listener_set_direction(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z);
10618 MA_API ma_vec3f ma_engine_listener_get_direction(const ma_engine* pEngine, ma_uint32 listenerIndex);
10619 MA_API void ma_engine_listener_set_velocity(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z);
10620 MA_API ma_vec3f ma_engine_listener_get_velocity(const ma_engine* pEngine, ma_uint32 listenerIndex);
10621 MA_API void ma_engine_listener_set_cone(ma_engine* pEngine, ma_uint32 listenerIndex, float innerAngleInRadians, float outerAngleInRadians, float outerGain);
10622 MA_API void ma_engine_listener_get_cone(const ma_engine* pEngine, ma_uint32 listenerIndex, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain);
10623 MA_API void ma_engine_listener_set_world_up(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z);
10624 MA_API ma_vec3f ma_engine_listener_get_world_up(const ma_engine* pEngine, ma_uint32 listenerIndex);
10625 MA_API void ma_engine_listener_set_enabled(ma_engine* pEngine, ma_uint32 listenerIndex, ma_bool32 isEnabled);
10626 MA_API ma_bool32 ma_engine_listener_is_enabled(const ma_engine* pEngine, ma_uint32 listenerIndex);
10627
10628 #ifndef MA_NO_RESOURCE_MANAGER
10629 MA_API ma_result ma_engine_play_sound(ma_engine* pEngine, const char* pFilePath, ma_sound_group* pGroup);   /* Fire and forget. */
10630 #endif
10631
10632 #ifndef MA_NO_RESOURCE_MANAGER
10633 MA_API ma_result ma_sound_init_from_file(ma_engine* pEngine, const char* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound);
10634 MA_API ma_result ma_sound_init_from_file_w(ma_engine* pEngine, const wchar_t* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound);
10635 MA_API ma_result ma_sound_init_copy(ma_engine* pEngine, const ma_sound* pExistingSound, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound);
10636 #endif
10637 MA_API ma_result ma_sound_init_from_data_source(ma_engine* pEngine, ma_data_source* pDataSource, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound);
10638 MA_API ma_result ma_sound_init_ex(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound);
10639 MA_API void ma_sound_uninit(ma_sound* pSound);
10640 MA_API ma_engine* ma_sound_get_engine(const ma_sound* pSound);
10641 MA_API ma_data_source* ma_sound_get_data_source(const ma_sound* pSound);
10642 MA_API ma_result ma_sound_start(ma_sound* pSound);
10643 MA_API ma_result ma_sound_stop(ma_sound* pSound);
10644 MA_API void ma_sound_set_volume(ma_sound* pSound, float volume);
10645 MA_API float ma_sound_get_volume(const ma_sound* pSound);
10646 MA_API void ma_sound_set_pan(ma_sound* pSound, float pan);
10647 MA_API float ma_sound_get_pan(const ma_sound* pSound);
10648 MA_API void ma_sound_set_pan_mode(ma_sound* pSound, ma_pan_mode panMode);
10649 MA_API ma_pan_mode ma_sound_get_pan_mode(const ma_sound* pSound);
10650 MA_API void ma_sound_set_pitch(ma_sound* pSound, float pitch);
10651 MA_API float ma_sound_get_pitch(const ma_sound* pSound);
10652 MA_API void ma_sound_set_spatialization_enabled(ma_sound* pSound, ma_bool32 enabled);
10653 MA_API ma_bool32 ma_sound_is_spatialization_enabled(const ma_sound* pSound);
10654 MA_API void ma_sound_set_pinned_listener_index(ma_sound* pSound, ma_uint32 listenerIndex);
10655 MA_API ma_uint32 ma_sound_get_pinned_listener_index(const ma_sound* pSound);
10656 MA_API ma_uint32 ma_sound_get_listener_index(const ma_sound* pSound);
10657 MA_API ma_vec3f ma_sound_get_direction_to_listener(const ma_sound* pSound);
10658 MA_API void ma_sound_set_position(ma_sound* pSound, float x, float y, float z);
10659 MA_API ma_vec3f ma_sound_get_position(const ma_sound* pSound);
10660 MA_API void ma_sound_set_direction(ma_sound* pSound, float x, float y, float z);
10661 MA_API ma_vec3f ma_sound_get_direction(const ma_sound* pSound);
10662 MA_API void ma_sound_set_velocity(ma_sound* pSound, float x, float y, float z);
10663 MA_API ma_vec3f ma_sound_get_velocity(const ma_sound* pSound);
10664 MA_API void ma_sound_set_attenuation_model(ma_sound* pSound, ma_attenuation_model attenuationModel);
10665 MA_API ma_attenuation_model ma_sound_get_attenuation_model(const ma_sound* pSound);
10666 MA_API void ma_sound_set_positioning(ma_sound* pSound, ma_positioning positioning);
10667 MA_API ma_positioning ma_sound_get_positioning(const ma_sound* pSound);
10668 MA_API void ma_sound_set_rolloff(ma_sound* pSound, float rolloff);
10669 MA_API float ma_sound_get_rolloff(const ma_sound* pSound);
10670 MA_API void ma_sound_set_min_gain(ma_sound* pSound, float minGain);
10671 MA_API float ma_sound_get_min_gain(const ma_sound* pSound);
10672 MA_API void ma_sound_set_max_gain(ma_sound* pSound, float maxGain);
10673 MA_API float ma_sound_get_max_gain(const ma_sound* pSound);
10674 MA_API void ma_sound_set_min_distance(ma_sound* pSound, float minDistance);
10675 MA_API float ma_sound_get_min_distance(const ma_sound* pSound);
10676 MA_API void ma_sound_set_max_distance(ma_sound* pSound, float maxDistance);
10677 MA_API float ma_sound_get_max_distance(const ma_sound* pSound);
10678 MA_API void ma_sound_set_cone(ma_sound* pSound, float innerAngleInRadians, float outerAngleInRadians, float outerGain);
10679 MA_API void ma_sound_get_cone(const ma_sound* pSound, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain);
10680 MA_API void ma_sound_set_doppler_factor(ma_sound* pSound, float dopplerFactor);
10681 MA_API float ma_sound_get_doppler_factor(const ma_sound* pSound);
10682 MA_API void ma_sound_set_directional_attenuation_factor(ma_sound* pSound, float directionalAttenuationFactor);
10683 MA_API float ma_sound_get_directional_attenuation_factor(const ma_sound* pSound);
10684 MA_API void ma_sound_set_fade_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames);
10685 MA_API void ma_sound_set_fade_in_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds);
10686 MA_API float ma_sound_get_current_fade_volume(ma_sound* pSound);
10687 MA_API void ma_sound_set_start_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames);
10688 MA_API void ma_sound_set_start_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds);
10689 MA_API void ma_sound_set_stop_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames);
10690 MA_API void ma_sound_set_stop_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds);
10691 MA_API ma_bool32 ma_sound_is_playing(const ma_sound* pSound);
10692 MA_API ma_uint64 ma_sound_get_time_in_pcm_frames(const ma_sound* pSound);
10693 MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping);
10694 MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound);
10695 MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound);
10696 MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex); /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */
10697 MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
10698 MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor);
10699 MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength);
10700
10701 MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup);
10702 MA_API ma_result ma_sound_group_init_ex(ma_engine* pEngine, const ma_sound_group_config* pConfig, ma_sound_group* pGroup);
10703 MA_API void ma_sound_group_uninit(ma_sound_group* pGroup);
10704 MA_API ma_engine* ma_sound_group_get_engine(const ma_sound_group* pGroup);
10705 MA_API ma_result ma_sound_group_start(ma_sound_group* pGroup);
10706 MA_API ma_result ma_sound_group_stop(ma_sound_group* pGroup);
10707 MA_API void ma_sound_group_set_volume(ma_sound_group* pGroup, float volume);
10708 MA_API float ma_sound_group_get_volume(const ma_sound_group* pGroup);
10709 MA_API void ma_sound_group_set_pan(ma_sound_group* pGroup, float pan);
10710 MA_API float ma_sound_group_get_pan(const ma_sound_group* pGroup);
10711 MA_API void ma_sound_group_set_pan_mode(ma_sound_group* pGroup, ma_pan_mode panMode);
10712 MA_API ma_pan_mode ma_sound_group_get_pan_mode(const ma_sound_group* pGroup);
10713 MA_API void ma_sound_group_set_pitch(ma_sound_group* pGroup, float pitch);
10714 MA_API float ma_sound_group_get_pitch(const ma_sound_group* pGroup);
10715 MA_API void ma_sound_group_set_spatialization_enabled(ma_sound_group* pGroup, ma_bool32 enabled);
10716 MA_API ma_bool32 ma_sound_group_is_spatialization_enabled(const ma_sound_group* pGroup);
10717 MA_API void ma_sound_group_set_pinned_listener_index(ma_sound_group* pGroup, ma_uint32 listenerIndex);
10718 MA_API ma_uint32 ma_sound_group_get_pinned_listener_index(const ma_sound_group* pGroup);
10719 MA_API ma_uint32 ma_sound_group_get_listener_index(const ma_sound_group* pGroup);
10720 MA_API ma_vec3f ma_sound_group_get_direction_to_listener(const ma_sound_group* pGroup);
10721 MA_API void ma_sound_group_set_position(ma_sound_group* pGroup, float x, float y, float z);
10722 MA_API ma_vec3f ma_sound_group_get_position(const ma_sound_group* pGroup);
10723 MA_API void ma_sound_group_set_direction(ma_sound_group* pGroup, float x, float y, float z);
10724 MA_API ma_vec3f ma_sound_group_get_direction(const ma_sound_group* pGroup);
10725 MA_API void ma_sound_group_set_velocity(ma_sound_group* pGroup, float x, float y, float z);
10726 MA_API ma_vec3f ma_sound_group_get_velocity(const ma_sound_group* pGroup);
10727 MA_API void ma_sound_group_set_attenuation_model(ma_sound_group* pGroup, ma_attenuation_model attenuationModel);
10728 MA_API ma_attenuation_model ma_sound_group_get_attenuation_model(const ma_sound_group* pGroup);
10729 MA_API void ma_sound_group_set_positioning(ma_sound_group* pGroup, ma_positioning positioning);
10730 MA_API ma_positioning ma_sound_group_get_positioning(const ma_sound_group* pGroup);
10731 MA_API void ma_sound_group_set_rolloff(ma_sound_group* pGroup, float rolloff);
10732 MA_API float ma_sound_group_get_rolloff(const ma_sound_group* pGroup);
10733 MA_API void ma_sound_group_set_min_gain(ma_sound_group* pGroup, float minGain);
10734 MA_API float ma_sound_group_get_min_gain(const ma_sound_group* pGroup);
10735 MA_API void ma_sound_group_set_max_gain(ma_sound_group* pGroup, float maxGain);
10736 MA_API float ma_sound_group_get_max_gain(const ma_sound_group* pGroup);
10737 MA_API void ma_sound_group_set_min_distance(ma_sound_group* pGroup, float minDistance);
10738 MA_API float ma_sound_group_get_min_distance(const ma_sound_group* pGroup);
10739 MA_API void ma_sound_group_set_max_distance(ma_sound_group* pGroup, float maxDistance);
10740 MA_API float ma_sound_group_get_max_distance(const ma_sound_group* pGroup);
10741 MA_API void ma_sound_group_set_cone(ma_sound_group* pGroup, float innerAngleInRadians, float outerAngleInRadians, float outerGain);
10742 MA_API void ma_sound_group_get_cone(const ma_sound_group* pGroup, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain);
10743 MA_API void ma_sound_group_set_doppler_factor(ma_sound_group* pGroup, float dopplerFactor);
10744 MA_API float ma_sound_group_get_doppler_factor(const ma_sound_group* pGroup);
10745 MA_API void ma_sound_group_set_directional_attenuation_factor(ma_sound_group* pGroup, float directionalAttenuationFactor);
10746 MA_API float ma_sound_group_get_directional_attenuation_factor(const ma_sound_group* pGroup);
10747 MA_API void ma_sound_group_set_fade_in_pcm_frames(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames);
10748 MA_API void ma_sound_group_set_fade_in_milliseconds(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds);
10749 MA_API float ma_sound_group_get_current_fade_volume(ma_sound_group* pGroup);
10750 MA_API void ma_sound_group_set_start_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames);
10751 MA_API void ma_sound_group_set_start_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds);
10752 MA_API void ma_sound_group_set_stop_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames);
10753 MA_API void ma_sound_group_set_stop_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds);
10754 MA_API ma_bool32 ma_sound_group_is_playing(const ma_sound_group* pGroup);
10755 MA_API ma_uint64 ma_sound_group_get_time_in_pcm_frames(const ma_sound_group* pGroup);
10756 #endif  /* MA_NO_ENGINE */
10757
10758 #ifdef __cplusplus
10759 }
10760 #endif
10761 #endif  /* miniaudio_h */
10762
10763
10764
10765 /************************************************************************************************************************************************************
10766 *************************************************************************************************************************************************************
10767
10768 IMPLEMENTATION
10769
10770 *************************************************************************************************************************************************************
10771 ************************************************************************************************************************************************************/
10772 #if defined(MINIAUDIO_IMPLEMENTATION) || defined(MA_IMPLEMENTATION)
10773 #ifndef miniaudio_c
10774 #define miniaudio_c
10775
10776 #include <assert.h>
10777 #include <limits.h> /* For INT_MAX */
10778 #include <math.h>   /* sin(), etc. */
10779
10780 #include <stdarg.h>
10781 #include <stdio.h>
10782 #if !defined(_MSC_VER) && !defined(__DMC__)
10783     #include <strings.h>    /* For strcasecmp(). */
10784     #include <wchar.h>      /* For wcslen(), wcsrtombs() */
10785 #endif
10786 #ifdef _MSC_VER
10787     #include <float.h>      /* For _controlfp_s constants */
10788 #endif
10789
10790 #ifdef MA_WIN32
10791 #include <windows.h>
10792 #else
10793 #include <stdlib.h>     /* For malloc(), free(), wcstombs(). */
10794 #include <string.h>     /* For memset() */
10795 #include <sched.h>
10796 #include <sys/time.h>   /* select() (used for ma_sleep()). */
10797 #include <pthread.h>
10798 #endif
10799
10800 #include <sys/stat.h>   /* For fstat(), etc. */
10801
10802 #ifdef MA_EMSCRIPTEN
10803 #include <emscripten/emscripten.h>
10804 #endif
10805
10806 #if !defined(MA_64BIT) && !defined(MA_32BIT)
10807 #ifdef _WIN32
10808 #ifdef _WIN64
10809 #define MA_64BIT
10810 #else
10811 #define MA_32BIT
10812 #endif
10813 #endif
10814 #endif
10815
10816 #if !defined(MA_64BIT) && !defined(MA_32BIT)
10817 #ifdef __GNUC__
10818 #ifdef __LP64__
10819 #define MA_64BIT
10820 #else
10821 #define MA_32BIT
10822 #endif
10823 #endif
10824 #endif
10825
10826 #if !defined(MA_64BIT) && !defined(MA_32BIT)
10827 #include <stdint.h>
10828 #if INTPTR_MAX == INT64_MAX
10829 #define MA_64BIT
10830 #else
10831 #define MA_32BIT
10832 #endif
10833 #endif
10834
10835 /* Architecture Detection */
10836 #if defined(__x86_64__) || defined(_M_X64)
10837 #define MA_X64
10838 #elif defined(__i386) || defined(_M_IX86)
10839 #define MA_X86
10840 #elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64)
10841 #define MA_ARM
10842 #endif
10843
10844 /* Intrinsics Support */
10845 #if defined(MA_X64) || defined(MA_X86)
10846     #if defined(_MSC_VER) && !defined(__clang__)
10847         /* MSVC. */
10848         #if _MSC_VER >= 1400 && !defined(MA_NO_SSE2)   /* 2005 */
10849             #define MA_SUPPORT_SSE2
10850         #endif
10851         /*#if _MSC_VER >= 1600 && !defined(MA_NO_AVX)*/    /* 2010 */
10852         /*    #define MA_SUPPORT_AVX*/
10853         /*#endif*/
10854         #if _MSC_VER >= 1700 && !defined(MA_NO_AVX2)   /* 2012 */
10855             #define MA_SUPPORT_AVX2
10856         #endif
10857     #else
10858         /* Assume GNUC-style. */
10859         #if defined(__SSE2__) && !defined(MA_NO_SSE2)
10860             #define MA_SUPPORT_SSE2
10861         #endif
10862         /*#if defined(__AVX__) && !defined(MA_NO_AVX)*/
10863         /*    #define MA_SUPPORT_AVX*/
10864         /*#endif*/
10865         #if defined(__AVX2__) && !defined(MA_NO_AVX2)
10866             #define MA_SUPPORT_AVX2
10867         #endif
10868     #endif
10869
10870     /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */
10871     #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
10872         #if !defined(MA_SUPPORT_SSE2)   && !defined(MA_NO_SSE2)   && __has_include(<emmintrin.h>)
10873             #define MA_SUPPORT_SSE2
10874         #endif
10875         /*#if !defined(MA_SUPPORT_AVX)    && !defined(MA_NO_AVX)    && __has_include(<immintrin.h>)*/
10876         /*    #define MA_SUPPORT_AVX*/
10877         /*#endif*/
10878         #if !defined(MA_SUPPORT_AVX2)   && !defined(MA_NO_AVX2)   && __has_include(<immintrin.h>)
10879             #define MA_SUPPORT_AVX2
10880         #endif
10881     #endif
10882
10883     #if defined(MA_SUPPORT_AVX2) || defined(MA_SUPPORT_AVX)
10884         #include <immintrin.h>
10885     #elif defined(MA_SUPPORT_SSE2)
10886         #include <emmintrin.h>
10887     #endif
10888 #endif
10889
10890 #if defined(MA_ARM)
10891     #if !defined(MA_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
10892         #define MA_SUPPORT_NEON
10893     #endif
10894
10895     /* Fall back to looking for the #include file. */
10896     #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
10897         #if !defined(MA_SUPPORT_NEON) && !defined(MA_NO_NEON) && __has_include(<arm_neon.h>)
10898             #define MA_SUPPORT_NEON
10899         #endif
10900     #endif
10901
10902     #if defined(MA_SUPPORT_NEON)
10903         #include <arm_neon.h>
10904     #endif
10905 #endif
10906
10907 /* Begin globally disabled warnings. */
10908 #if defined(_MSC_VER)
10909     #pragma warning(push)
10910     #pragma warning(disable:4752)   /* found Intel(R) Advanced Vector Extensions; consider using /arch:AVX */
10911     #pragma warning(disable:4049)   /* compiler limit : terminating line number emission */
10912 #endif
10913
10914 #if defined(MA_X64) || defined(MA_X86)
10915     #if defined(_MSC_VER) && !defined(__clang__)
10916         #if _MSC_VER >= 1400
10917             #include <intrin.h>
10918             static MA_INLINE void ma_cpuid(int info[4], int fid)
10919             {
10920                 __cpuid(info, fid);
10921             }
10922         #else
10923             #define MA_NO_CPUID
10924         #endif
10925
10926         #if _MSC_VER >= 1600 && (defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219)
10927             static MA_INLINE unsigned __int64 ma_xgetbv(int reg)
10928             {
10929                 return _xgetbv(reg);
10930             }
10931         #else
10932             #define MA_NO_XGETBV
10933         #endif
10934     #elif (defined(__GNUC__) || defined(__clang__)) && !defined(MA_ANDROID)
10935         static MA_INLINE void ma_cpuid(int info[4], int fid)
10936         {
10937             /*
10938             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
10939             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
10940             supporting different assembly dialects.
10941
10942             What's basically happening is that we're saving and restoring the ebx register manually.
10943             */
10944             #if defined(DRFLAC_X86) && defined(__PIC__)
10945                 __asm__ __volatile__ (
10946                     "xchg{l} {%%}ebx, %k1;"
10947                     "cpuid;"
10948                     "xchg{l} {%%}ebx, %k1;"
10949                     : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
10950                 );
10951             #else
10952                 __asm__ __volatile__ (
10953                     "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
10954                 );
10955             #endif
10956         }
10957
10958         static MA_INLINE ma_uint64 ma_xgetbv(int reg)
10959         {
10960             unsigned int hi;
10961             unsigned int lo;
10962
10963             __asm__ __volatile__ (
10964                 "xgetbv" : "=a"(lo), "=d"(hi) : "c"(reg)
10965             );
10966
10967             return ((ma_uint64)hi << 32) | (ma_uint64)lo;
10968         }
10969     #else
10970         #define MA_NO_CPUID
10971         #define MA_NO_XGETBV
10972     #endif
10973 #else
10974     #define MA_NO_CPUID
10975     #define MA_NO_XGETBV
10976 #endif
10977
10978 static MA_INLINE ma_bool32 ma_has_sse2(void)
10979 {
10980 #if defined(MA_SUPPORT_SSE2)
10981     #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_SSE2)
10982         #if defined(MA_X64)
10983             return MA_TRUE;    /* 64-bit targets always support SSE2. */
10984         #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)
10985             return MA_TRUE;    /* If the compiler is allowed to freely generate SSE2 code we can assume support. */
10986         #else
10987             #if defined(MA_NO_CPUID)
10988                 return MA_FALSE;
10989             #else
10990                 int info[4];
10991                 ma_cpuid(info, 1);
10992                 return (info[3] & (1 << 26)) != 0;
10993             #endif
10994         #endif
10995     #else
10996         return MA_FALSE;       /* SSE2 is only supported on x86 and x64 architectures. */
10997     #endif
10998 #else
10999     return MA_FALSE;           /* No compiler support. */
11000 #endif
11001 }
11002
11003 #if 0
11004 static MA_INLINE ma_bool32 ma_has_avx()
11005 {
11006 #if defined(MA_SUPPORT_AVX)
11007     #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX)
11008         #if defined(_AVX_) || defined(__AVX__)
11009             return MA_TRUE;    /* If the compiler is allowed to freely generate AVX code we can assume support. */
11010         #else
11011             /* AVX requires both CPU and OS support. */
11012             #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV)
11013                 return MA_FALSE;
11014             #else
11015                 int info[4];
11016                 ma_cpuid(info, 1);
11017                 if (((info[2] & (1 << 27)) != 0) && ((info[2] & (1 << 28)) != 0)) {
11018                     ma_uint64 xrc = ma_xgetbv(0);
11019                     if ((xrc & 0x06) == 0x06) {
11020                         return MA_TRUE;
11021                     } else {
11022                         return MA_FALSE;
11023                     }
11024                 } else {
11025                     return MA_FALSE;
11026                 }
11027             #endif
11028         #endif
11029     #else
11030         return MA_FALSE;       /* AVX is only supported on x86 and x64 architectures. */
11031     #endif
11032 #else
11033     return MA_FALSE;           /* No compiler support. */
11034 #endif
11035 }
11036 #endif
11037
11038 static MA_INLINE ma_bool32 ma_has_avx2(void)
11039 {
11040 #if defined(MA_SUPPORT_AVX2)
11041     #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX2)
11042         #if defined(_AVX2_) || defined(__AVX2__)
11043             return MA_TRUE;    /* If the compiler is allowed to freely generate AVX2 code we can assume support. */
11044         #else
11045             /* AVX2 requires both CPU and OS support. */
11046             #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV)
11047                 return MA_FALSE;
11048             #else
11049                 int info1[4];
11050                 int info7[4];
11051                 ma_cpuid(info1, 1);
11052                 ma_cpuid(info7, 7);
11053                 if (((info1[2] & (1 << 27)) != 0) && ((info7[1] & (1 << 5)) != 0)) {
11054                     ma_uint64 xrc = ma_xgetbv(0);
11055                     if ((xrc & 0x06) == 0x06) {
11056                         return MA_TRUE;
11057                     } else {
11058                         return MA_FALSE;
11059                     }
11060                 } else {
11061                     return MA_FALSE;
11062                 }
11063             #endif
11064         #endif
11065     #else
11066         return MA_FALSE;       /* AVX2 is only supported on x86 and x64 architectures. */
11067     #endif
11068 #else
11069     return MA_FALSE;           /* No compiler support. */
11070 #endif
11071 }
11072
11073 static MA_INLINE ma_bool32 ma_has_neon(void)
11074 {
11075 #if defined(MA_SUPPORT_NEON)
11076     #if defined(MA_ARM) && !defined(MA_NO_NEON)
11077         #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
11078             return MA_TRUE;    /* If the compiler is allowed to freely generate NEON code we can assume support. */
11079         #else
11080             /* TODO: Runtime check. */
11081             return MA_FALSE;
11082         #endif
11083     #else
11084         return MA_FALSE;       /* NEON is only supported on ARM architectures. */
11085     #endif
11086 #else
11087     return MA_FALSE;           /* No compiler support. */
11088 #endif
11089 }
11090
11091 #define MA_SIMD_NONE    0
11092 #define MA_SIMD_SSE2    1
11093 #define MA_SIMD_AVX2    2
11094 #define MA_SIMD_NEON    3
11095
11096 #ifndef MA_PREFERRED_SIMD
11097     #  if defined(MA_SUPPORT_SSE2) && defined(MA_PREFER_SSE2)
11098         #define MA_PREFERRED_SIMD MA_SIMD_SSE2
11099     #elif defined(MA_SUPPORT_AVX2) && defined(MA_PREFER_AVX2)
11100         #define MA_PREFERRED_SIMD MA_SIMD_AVX2
11101     #elif defined(MA_SUPPORT_NEON) && defined(MA_PREFER_NEON)
11102         #define MA_PREFERRED_SIMD MA_SIMD_NEON
11103     #else
11104         #define MA_PREFERRED_SIMD MA_SIMD_NONE
11105     #endif
11106 #endif
11107
11108 #if defined(__has_builtin)
11109     #define MA_COMPILER_HAS_BUILTIN(x) __has_builtin(x)
11110 #else
11111     #define MA_COMPILER_HAS_BUILTIN(x) 0
11112 #endif
11113
11114 #ifndef MA_ASSUME
11115     #if MA_COMPILER_HAS_BUILTIN(__builtin_assume)
11116         #define MA_ASSUME(x) __builtin_assume(x)
11117     #elif MA_COMPILER_HAS_BUILTIN(__builtin_unreachable)
11118         #define MA_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0)
11119     #elif defined(_MSC_VER)
11120         #define MA_ASSUME(x) __assume(x)
11121     #else
11122         #define MA_ASSUME(x) (void)(x)
11123     #endif
11124 #endif
11125
11126 #ifndef MA_RESTRICT
11127     #if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
11128         #define MA_RESTRICT __restrict
11129     #else
11130         #define MA_RESTRICT
11131     #endif
11132 #endif
11133
11134 #if defined(_MSC_VER) && _MSC_VER >= 1400
11135     #define MA_HAS_BYTESWAP16_INTRINSIC
11136     #define MA_HAS_BYTESWAP32_INTRINSIC
11137     #define MA_HAS_BYTESWAP64_INTRINSIC
11138 #elif defined(__clang__)
11139     #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap16)
11140         #define MA_HAS_BYTESWAP16_INTRINSIC
11141     #endif
11142     #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap32)
11143         #define MA_HAS_BYTESWAP32_INTRINSIC
11144     #endif
11145     #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap64)
11146         #define MA_HAS_BYTESWAP64_INTRINSIC
11147     #endif
11148 #elif defined(__GNUC__)
11149     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
11150         #define MA_HAS_BYTESWAP32_INTRINSIC
11151         #define MA_HAS_BYTESWAP64_INTRINSIC
11152     #endif
11153     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
11154         #define MA_HAS_BYTESWAP16_INTRINSIC
11155     #endif
11156 #endif
11157
11158
11159 static MA_INLINE ma_bool32 ma_is_little_endian(void)
11160 {
11161 #if defined(MA_X86) || defined(MA_X64)
11162     return MA_TRUE;
11163 #else
11164     int n = 1;
11165     return (*(char*)&n) == 1;
11166 #endif
11167 }
11168
11169 static MA_INLINE ma_bool32 ma_is_big_endian(void)
11170 {
11171     return !ma_is_little_endian();
11172 }
11173
11174
11175 static MA_INLINE ma_uint32 ma_swap_endian_uint32(ma_uint32 n)
11176 {
11177 #ifdef MA_HAS_BYTESWAP32_INTRINSIC
11178     #if defined(_MSC_VER)
11179         return _byteswap_ulong(n);
11180     #elif defined(__GNUC__) || defined(__clang__)
11181         #if defined(MA_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(MA_64BIT)   /* <-- 64-bit inline assembly has not been tested, so disabling for now. */
11182             /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */
11183             ma_uint32 r;
11184             __asm__ __volatile__ (
11185             #if defined(MA_64BIT)
11186                 "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n)   /* <-- This is untested. If someone in the community could test this, that would be appreciated! */
11187             #else
11188                 "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
11189             #endif
11190             );
11191             return r;
11192         #else
11193             return __builtin_bswap32(n);
11194         #endif
11195     #else
11196         #error "This compiler does not support the byte swap intrinsic."
11197     #endif
11198 #else
11199     return ((n & 0xFF000000) >> 24) |
11200            ((n & 0x00FF0000) >>  8) |
11201            ((n & 0x0000FF00) <<  8) |
11202            ((n & 0x000000FF) << 24);
11203 #endif
11204 }
11205
11206
11207 #if !defined(MA_EMSCRIPTEN)
11208 #ifdef MA_WIN32
11209 static void ma_sleep__win32(ma_uint32 milliseconds)
11210 {
11211     Sleep((DWORD)milliseconds);
11212 }
11213 #endif
11214 #ifdef MA_POSIX
11215 static void ma_sleep__posix(ma_uint32 milliseconds)
11216 {
11217 #ifdef MA_EMSCRIPTEN
11218     (void)milliseconds;
11219     MA_ASSERT(MA_FALSE);  /* The Emscripten build should never sleep. */
11220 #else
11221     #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
11222         struct timespec ts;
11223         ts.tv_sec  = milliseconds / 1000;
11224         ts.tv_nsec = milliseconds % 1000 * 1000000;
11225         nanosleep(&ts, NULL);
11226     #else
11227         struct timeval tv;
11228         tv.tv_sec  = milliseconds / 1000;
11229         tv.tv_usec = milliseconds % 1000 * 1000;
11230         select(0, NULL, NULL, NULL, &tv);
11231     #endif
11232 #endif
11233 }
11234 #endif
11235
11236 static MA_INLINE void ma_sleep(ma_uint32 milliseconds)
11237 {
11238 #ifdef MA_WIN32
11239     ma_sleep__win32(milliseconds);
11240 #endif
11241 #ifdef MA_POSIX
11242     ma_sleep__posix(milliseconds);
11243 #endif
11244 }
11245 #endif
11246
11247 static MA_INLINE void ma_yield()
11248 {
11249 #if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
11250     /* x86/x64 */
11251     #if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__)) && !defined(__clang__)
11252         #if _MSC_VER >= 1400
11253             _mm_pause();
11254         #else
11255             #if defined(__DMC__)
11256                 /* Digital Mars does not recognize the PAUSE opcode. Fall back to NOP. */
11257                 __asm nop;
11258             #else
11259                 __asm pause;
11260             #endif
11261         #endif
11262     #else
11263         __asm__ __volatile__ ("pause");
11264     #endif
11265 #elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(_M_ARM64) || (defined(_M_ARM) && _M_ARM >= 7) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__)
11266     /* ARM */
11267     #if defined(_MSC_VER)
11268         /* Apparently there is a __yield() intrinsic that's compatible with ARM, but I cannot find documentation for it nor can I find where it's declared. */
11269         __yield();
11270     #else
11271         __asm__ __volatile__ ("yield"); /* ARMv6K/ARMv6T2 and above. */
11272     #endif
11273 #else
11274     /* Unknown or unsupported architecture. No-op. */
11275 #endif
11276 }
11277
11278
11279 #define MA_MM_DENORMALS_ZERO_MASK   0x0040
11280 #define MA_MM_FLUSH_ZERO_MASK       0x8000
11281
11282 static MA_INLINE unsigned int ma_disable_denormals()
11283 {
11284     unsigned int prevState;
11285
11286     #if defined(_MSC_VER)
11287     {
11288         /*
11289         Older versions of Visual Studio don't support the "safe" versions of _controlfp_s(). I don't
11290         know which version of Visual Studio first added support for _controlfp_s(), but I do know
11291         that VC6 lacks support. _MSC_VER = 1200 is VC6, but if you get compilation errors on older
11292         versions of Visual Studio, let me know and I'll make the necessary adjustment.
11293         */
11294         #if _MSC_VER <= 1200
11295         {
11296             prevState = _statusfp();
11297             _controlfp(prevState | _DN_FLUSH, _MCW_DN);
11298         }
11299         #else
11300         {
11301             unsigned int unused;
11302             _controlfp_s(&prevState, 0, 0);
11303             _controlfp_s(&unused, prevState | _DN_FLUSH, _MCW_DN);
11304         }
11305         #endif
11306     }
11307     #elif defined(MA_X86) || defined(MA_X64)
11308     {
11309         #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__))   /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */
11310         {
11311             prevState = _mm_getcsr();
11312             _mm_setcsr(prevState | MA_MM_DENORMALS_ZERO_MASK | MA_MM_FLUSH_ZERO_MASK);
11313         }
11314         #else
11315         {
11316             /* x88/64, but no support for _mm_getcsr()/_mm_setcsr(). May need to fall back to inlined assembly here. */
11317             prevState = 0;
11318         }
11319         #endif
11320     }
11321     #else
11322     {
11323         /* Unknown or unsupported architecture. No-op. */
11324         prevState = 0;
11325     }
11326     #endif
11327
11328     return prevState;
11329 }
11330
11331 static MA_INLINE void ma_restore_denormals(unsigned int prevState)
11332 {
11333     #if defined(_MSC_VER)
11334     {
11335         /* Older versions of Visual Studio do not support _controlfp_s(). See ma_disable_denormals(). */
11336         #if _MSC_VER <= 1200
11337         {
11338             _controlfp(prevState, _MCW_DN);
11339         }
11340         #else
11341         {
11342             unsigned int unused;
11343             _controlfp_s(&unused, prevState, _MCW_DN);
11344         }
11345         #endif
11346     }
11347     #elif defined(MA_X86) || defined(MA_X64)
11348     {
11349         #if defined(__SSE2__) && !(defined(__TINYC__) || defined(__WATCOMC__))   /* <-- Add compilers that lack support for _mm_getcsr() and _mm_setcsr() to this list. */
11350         {
11351             _mm_setcsr(prevState);
11352         }
11353         #else
11354         {
11355             /* x88/64, but no support for _mm_getcsr()/_mm_setcsr(). May need to fall back to inlined assembly here. */
11356             (void)prevState;
11357         }
11358         #endif
11359     }
11360     #else
11361     {
11362         /* Unknown or unsupported architecture. No-op. */
11363         (void)prevState;
11364     }
11365     #endif
11366 }
11367
11368
11369
11370 #ifndef MA_COINIT_VALUE
11371 #define MA_COINIT_VALUE    0   /* 0 = COINIT_MULTITHREADED */
11372 #endif
11373
11374
11375 #ifndef MA_FLT_MAX
11376     #ifdef FLT_MAX
11377         #define MA_FLT_MAX FLT_MAX
11378     #else
11379         #define MA_FLT_MAX 3.402823466e+38F
11380     #endif
11381 #endif
11382
11383
11384 #ifndef MA_PI
11385 #define MA_PI      3.14159265358979323846264f
11386 #endif
11387 #ifndef MA_PI_D
11388 #define MA_PI_D    3.14159265358979323846264
11389 #endif
11390 #ifndef MA_TAU
11391 #define MA_TAU     6.28318530717958647693f
11392 #endif
11393 #ifndef MA_TAU_D
11394 #define MA_TAU_D   6.28318530717958647693
11395 #endif
11396
11397
11398 /* The default format when ma_format_unknown (0) is requested when initializing a device. */
11399 #ifndef MA_DEFAULT_FORMAT
11400 #define MA_DEFAULT_FORMAT                                   ma_format_f32
11401 #endif
11402
11403 /* The default channel count to use when 0 is used when initializing a device. */
11404 #ifndef MA_DEFAULT_CHANNELS
11405 #define MA_DEFAULT_CHANNELS                                 2
11406 #endif
11407
11408 /* The default sample rate to use when 0 is used when initializing a device. */
11409 #ifndef MA_DEFAULT_SAMPLE_RATE
11410 #define MA_DEFAULT_SAMPLE_RATE                              48000
11411 #endif
11412
11413 /* Default periods when none is specified in ma_device_init(). More periods means more work on the CPU. */
11414 #ifndef MA_DEFAULT_PERIODS
11415 #define MA_DEFAULT_PERIODS                                  3
11416 #endif
11417
11418 /* The default period size in milliseconds for low latency mode. */
11419 #ifndef MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY
11420 #define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY  10
11421 #endif
11422
11423 /* The default buffer size in milliseconds for conservative mode. */
11424 #ifndef MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE
11425 #define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE 100
11426 #endif
11427
11428 /* The default LPF filter order for linear resampling. Note that this is clamped to MA_MAX_FILTER_ORDER. */
11429 #ifndef MA_DEFAULT_RESAMPLER_LPF_ORDER
11430     #if MA_MAX_FILTER_ORDER >= 4
11431         #define MA_DEFAULT_RESAMPLER_LPF_ORDER  4
11432     #else
11433         #define MA_DEFAULT_RESAMPLER_LPF_ORDER  MA_MAX_FILTER_ORDER
11434     #endif
11435 #endif
11436
11437
11438 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
11439     #pragma GCC diagnostic push
11440     #pragma GCC diagnostic ignored "-Wunused-variable"
11441 #endif
11442
11443 /* Standard sample rates, in order of priority. */
11444 static ma_uint32 g_maStandardSampleRatePriorities[] = {
11445     (ma_uint32)ma_standard_sample_rate_48000,
11446     (ma_uint32)ma_standard_sample_rate_44100,
11447
11448     (ma_uint32)ma_standard_sample_rate_32000,
11449     (ma_uint32)ma_standard_sample_rate_24000,
11450     (ma_uint32)ma_standard_sample_rate_22050,
11451
11452     (ma_uint32)ma_standard_sample_rate_88200,
11453     (ma_uint32)ma_standard_sample_rate_96000,
11454     (ma_uint32)ma_standard_sample_rate_176400,
11455     (ma_uint32)ma_standard_sample_rate_192000,
11456
11457     (ma_uint32)ma_standard_sample_rate_16000,
11458     (ma_uint32)ma_standard_sample_rate_11025,
11459     (ma_uint32)ma_standard_sample_rate_8000,
11460
11461     (ma_uint32)ma_standard_sample_rate_352800,
11462     (ma_uint32)ma_standard_sample_rate_384000
11463 };
11464
11465 static MA_INLINE ma_bool32 ma_is_standard_sample_rate(ma_uint32 sampleRate)
11466 {
11467     ma_uint32 iSampleRate;
11468
11469     for (iSampleRate = 0; iSampleRate < sizeof(g_maStandardSampleRatePriorities) / sizeof(g_maStandardSampleRatePriorities[0]); iSampleRate += 1) {
11470         if (g_maStandardSampleRatePriorities[iSampleRate] == sampleRate) {
11471             return MA_TRUE;
11472         }
11473     }
11474
11475     /* Getting here means the sample rate is not supported. */
11476     return MA_FALSE;
11477 }
11478
11479
11480 static ma_format g_maFormatPriorities[] = {
11481     ma_format_s16,         /* Most common */
11482     ma_format_f32,
11483
11484     /*ma_format_s24_32,*/    /* Clean alignment */
11485     ma_format_s32,
11486
11487     ma_format_s24,         /* Unclean alignment */
11488
11489     ma_format_u8           /* Low quality */
11490 };
11491 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
11492     #pragma GCC diagnostic pop
11493 #endif
11494
11495
11496 MA_API void ma_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision)
11497 {
11498     if (pMajor) {
11499         *pMajor = MA_VERSION_MAJOR;
11500     }
11501
11502     if (pMinor) {
11503         *pMinor = MA_VERSION_MINOR;
11504     }
11505
11506     if (pRevision) {
11507         *pRevision = MA_VERSION_REVISION;
11508     }
11509 }
11510
11511 MA_API const char* ma_version_string(void)
11512 {
11513     return MA_VERSION_STRING;
11514 }
11515
11516
11517 /******************************************************************************
11518
11519 Standard Library Stuff
11520
11521 ******************************************************************************/
11522 #ifndef MA_MALLOC
11523 #ifdef MA_WIN32
11524 #define MA_MALLOC(sz) HeapAlloc(GetProcessHeap(), 0, (sz))
11525 #else
11526 #define MA_MALLOC(sz) malloc((sz))
11527 #endif
11528 #endif
11529
11530 #ifndef MA_REALLOC
11531 #ifdef MA_WIN32
11532 #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)))
11533 #else
11534 #define MA_REALLOC(p, sz) realloc((p), (sz))
11535 #endif
11536 #endif
11537
11538 #ifndef MA_FREE
11539 #ifdef MA_WIN32
11540 #define MA_FREE(p) HeapFree(GetProcessHeap(), 0, (p))
11541 #else
11542 #define MA_FREE(p) free((p))
11543 #endif
11544 #endif
11545
11546 #ifndef MA_ZERO_MEMORY
11547 #ifdef MA_WIN32
11548 #define MA_ZERO_MEMORY(p, sz) ZeroMemory((p), (sz))
11549 #else
11550 #define MA_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
11551 #endif
11552 #endif
11553
11554 #ifndef MA_COPY_MEMORY
11555 #ifdef MA_WIN32
11556 #define MA_COPY_MEMORY(dst, src, sz) CopyMemory((dst), (src), (sz))
11557 #else
11558 #define MA_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
11559 #endif
11560 #endif
11561
11562 #ifndef MA_MOVE_MEMORY
11563 #ifdef MA_WIN32
11564 #define MA_MOVE_MEMORY(dst, src, sz) MoveMemory((dst), (src), (sz))
11565 #else
11566 #define MA_MOVE_MEMORY(dst, src, sz) memmove((dst), (src), (sz))
11567 #endif
11568 #endif
11569
11570 #ifndef MA_ASSERT
11571 #ifdef MA_WIN32
11572 #define MA_ASSERT(condition) assert(condition)
11573 #else
11574 #define MA_ASSERT(condition) assert(condition)
11575 #endif
11576 #endif
11577
11578 #define MA_ZERO_OBJECT(p) MA_ZERO_MEMORY((p), sizeof(*(p)))
11579
11580 #define ma_countof(x)               (sizeof(x) / sizeof(x[0]))
11581 #define ma_max(x, y)                (((x) > (y)) ? (x) : (y))
11582 #define ma_min(x, y)                (((x) < (y)) ? (x) : (y))
11583 #define ma_abs(x)                   (((x) > 0) ? (x) : -(x))
11584 #define ma_clamp(x, lo, hi)         (ma_max(lo, ma_min(x, hi)))
11585 #define ma_offset_ptr(p, offset)    (((ma_uint8*)(p)) + (offset))
11586 #define ma_align(x, a)              ((x + (a-1)) & ~(a-1))
11587 #define ma_align_64(x)              ma_align(x, 8)
11588
11589 #define ma_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / ma_get_bytes_per_sample(format) / (channels))
11590
11591 static MA_INLINE double ma_sind(double x)
11592 {
11593     /* TODO: Implement custom sin(x). */
11594     return sin(x);
11595 }
11596
11597 static MA_INLINE double ma_expd(double x)
11598 {
11599     /* TODO: Implement custom exp(x). */
11600     return exp(x);
11601 }
11602
11603 static MA_INLINE double ma_logd(double x)
11604 {
11605     /* TODO: Implement custom log(x). */
11606     return log(x);
11607 }
11608
11609 static MA_INLINE double ma_powd(double x, double y)
11610 {
11611     /* TODO: Implement custom pow(x, y). */
11612     return pow(x, y);
11613 }
11614
11615 static MA_INLINE double ma_sqrtd(double x)
11616 {
11617     /* TODO: Implement custom sqrt(x). */
11618     return sqrt(x);
11619 }
11620
11621
11622 static MA_INLINE double ma_cosd(double x)
11623 {
11624     return ma_sind((MA_PI_D*0.5) - x);
11625 }
11626
11627 static MA_INLINE double ma_log10d(double x)
11628 {
11629     return ma_logd(x) * 0.43429448190325182765;
11630 }
11631
11632 static MA_INLINE float ma_powf(float x, float y)
11633 {
11634     return (float)ma_powd((double)x, (double)y);
11635 }
11636
11637 static MA_INLINE float ma_log10f(float x)
11638 {
11639     return (float)ma_log10d((double)x);
11640 }
11641
11642
11643 static MA_INLINE double ma_degrees_to_radians(double degrees)
11644 {
11645     return degrees * 0.01745329252;
11646 }
11647
11648 static MA_INLINE double ma_radians_to_degrees(double radians)
11649 {
11650     return radians * 57.295779512896;
11651 }
11652
11653 static MA_INLINE float ma_degrees_to_radians_f(float degrees)
11654 {
11655     return degrees * 0.01745329252f;
11656 }
11657
11658 static MA_INLINE float ma_radians_to_degrees_f(float radians)
11659 {
11660     return radians * 57.295779512896f;
11661 }
11662
11663
11664 /*
11665 Return Values:
11666   0:  Success
11667   22: EINVAL
11668   34: ERANGE
11669
11670 Not using symbolic constants for errors because I want to avoid #including errno.h
11671 */
11672 MA_API int ma_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src)
11673 {
11674     size_t i;
11675
11676     if (dst == 0) {
11677         return 22;
11678     }
11679     if (dstSizeInBytes == 0) {
11680         return 34;
11681     }
11682     if (src == 0) {
11683         dst[0] = '\0';
11684         return 22;
11685     }
11686
11687     for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) {
11688         dst[i] = src[i];
11689     }
11690
11691     if (i < dstSizeInBytes) {
11692         dst[i] = '\0';
11693         return 0;
11694     }
11695
11696     dst[0] = '\0';
11697     return 34;
11698 }
11699
11700 MA_API int ma_wcscpy_s(wchar_t* dst, size_t dstCap, const wchar_t* src)
11701 {
11702     size_t i;
11703
11704     if (dst == 0) {
11705         return 22;
11706     }
11707     if (dstCap == 0) {
11708         return 34;
11709     }
11710     if (src == 0) {
11711         dst[0] = '\0';
11712         return 22;
11713     }
11714
11715     for (i = 0; i < dstCap && src[i] != '\0'; ++i) {
11716         dst[i] = src[i];
11717     }
11718
11719     if (i < dstCap) {
11720         dst[i] = '\0';
11721         return 0;
11722     }
11723
11724     dst[0] = '\0';
11725     return 34;
11726 }
11727
11728
11729 MA_API int ma_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count)
11730 {
11731     size_t maxcount;
11732     size_t i;
11733
11734     if (dst == 0) {
11735         return 22;
11736     }
11737     if (dstSizeInBytes == 0) {
11738         return 34;
11739     }
11740     if (src == 0) {
11741         dst[0] = '\0';
11742         return 22;
11743     }
11744
11745     maxcount = count;
11746     if (count == ((size_t)-1) || count >= dstSizeInBytes) {        /* -1 = _TRUNCATE */
11747         maxcount = dstSizeInBytes - 1;
11748     }
11749
11750     for (i = 0; i < maxcount && src[i] != '\0'; ++i) {
11751         dst[i] = src[i];
11752     }
11753
11754     if (src[i] == '\0' || i == count || count == ((size_t)-1)) {
11755         dst[i] = '\0';
11756         return 0;
11757     }
11758
11759     dst[0] = '\0';
11760     return 34;
11761 }
11762
11763 MA_API int ma_strcat_s(char* dst, size_t dstSizeInBytes, const char* src)
11764 {
11765     char* dstorig;
11766
11767     if (dst == 0) {
11768         return 22;
11769     }
11770     if (dstSizeInBytes == 0) {
11771         return 34;
11772     }
11773     if (src == 0) {
11774         dst[0] = '\0';
11775         return 22;
11776     }
11777
11778     dstorig = dst;
11779
11780     while (dstSizeInBytes > 0 && dst[0] != '\0') {
11781         dst += 1;
11782         dstSizeInBytes -= 1;
11783     }
11784
11785     if (dstSizeInBytes == 0) {
11786         return 22;  /* Unterminated. */
11787     }
11788
11789
11790     while (dstSizeInBytes > 0 && src[0] != '\0') {
11791         *dst++ = *src++;
11792         dstSizeInBytes -= 1;
11793     }
11794
11795     if (dstSizeInBytes > 0) {
11796         dst[0] = '\0';
11797     } else {
11798         dstorig[0] = '\0';
11799         return 34;
11800     }
11801
11802     return 0;
11803 }
11804
11805 MA_API int ma_strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count)
11806 {
11807     char* dstorig;
11808
11809     if (dst == 0) {
11810         return 22;
11811     }
11812     if (dstSizeInBytes == 0) {
11813         return 34;
11814     }
11815     if (src == 0) {
11816         return 22;
11817     }
11818
11819     dstorig = dst;
11820
11821     while (dstSizeInBytes > 0 && dst[0] != '\0') {
11822         dst += 1;
11823         dstSizeInBytes -= 1;
11824     }
11825
11826     if (dstSizeInBytes == 0) {
11827         return 22;  /* Unterminated. */
11828     }
11829
11830
11831     if (count == ((size_t)-1)) {        /* _TRUNCATE */
11832         count = dstSizeInBytes - 1;
11833     }
11834
11835     while (dstSizeInBytes > 0 && src[0] != '\0' && count > 0) {
11836         *dst++ = *src++;
11837         dstSizeInBytes -= 1;
11838         count -= 1;
11839     }
11840
11841     if (dstSizeInBytes > 0) {
11842         dst[0] = '\0';
11843     } else {
11844         dstorig[0] = '\0';
11845         return 34;
11846     }
11847
11848     return 0;
11849 }
11850
11851 MA_API int ma_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix)
11852 {
11853     int sign;
11854     unsigned int valueU;
11855     char* dstEnd;
11856
11857     if (dst == NULL || dstSizeInBytes == 0) {
11858         return 22;
11859     }
11860     if (radix < 2 || radix > 36) {
11861         dst[0] = '\0';
11862         return 22;
11863     }
11864
11865     sign = (value < 0 && radix == 10) ? -1 : 1;     /* The negative sign is only used when the base is 10. */
11866
11867     if (value < 0) {
11868         valueU = -value;
11869     } else {
11870         valueU = value;
11871     }
11872
11873     dstEnd = dst;
11874     do
11875     {
11876         int remainder = valueU % radix;
11877         if (remainder > 9) {
11878             *dstEnd = (char)((remainder - 10) + 'a');
11879         } else {
11880             *dstEnd = (char)(remainder + '0');
11881         }
11882
11883         dstEnd += 1;
11884         dstSizeInBytes -= 1;
11885         valueU /= radix;
11886     } while (dstSizeInBytes > 0 && valueU > 0);
11887
11888     if (dstSizeInBytes == 0) {
11889         dst[0] = '\0';
11890         return 22;  /* Ran out of room in the output buffer. */
11891     }
11892
11893     if (sign < 0) {
11894         *dstEnd++ = '-';
11895         dstSizeInBytes -= 1;
11896     }
11897
11898     if (dstSizeInBytes == 0) {
11899         dst[0] = '\0';
11900         return 22;  /* Ran out of room in the output buffer. */
11901     }
11902
11903     *dstEnd = '\0';
11904
11905
11906     /* At this point the string will be reversed. */
11907     dstEnd -= 1;
11908     while (dst < dstEnd) {
11909         char temp = *dst;
11910         *dst = *dstEnd;
11911         *dstEnd = temp;
11912
11913         dst += 1;
11914         dstEnd -= 1;
11915     }
11916
11917     return 0;
11918 }
11919
11920 MA_API int ma_strcmp(const char* str1, const char* str2)
11921 {
11922     if (str1 == str2) return  0;
11923
11924     /* These checks differ from the standard implementation. It's not important, but I prefer it just for sanity. */
11925     if (str1 == NULL) return -1;
11926     if (str2 == NULL) return  1;
11927
11928     for (;;) {
11929         if (str1[0] == '\0') {
11930             break;
11931         }
11932         if (str1[0] != str2[0]) {
11933             break;
11934         }
11935
11936         str1 += 1;
11937         str2 += 1;
11938     }
11939
11940     return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0];
11941 }
11942
11943 MA_API int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB)
11944 {
11945     int result;
11946
11947     result = ma_strncpy_s(dst, dstSize, srcA, (size_t)-1);
11948     if (result != 0) {
11949         return result;
11950     }
11951
11952     result = ma_strncat_s(dst, dstSize, srcB, (size_t)-1);
11953     if (result != 0) {
11954         return result;
11955     }
11956
11957     return result;
11958 }
11959
11960 MA_API char* ma_copy_string(const char* src, const ma_allocation_callbacks* pAllocationCallbacks)
11961 {
11962     if (src == NULL) {
11963         return NULL;
11964     }
11965
11966     size_t sz = strlen(src)+1;
11967     char* dst = (char*)ma_malloc(sz, pAllocationCallbacks);
11968     if (dst == NULL) {
11969         return NULL;
11970     }
11971
11972     ma_strcpy_s(dst, sz, src);
11973
11974     return dst;
11975 }
11976
11977 MA_API wchar_t* ma_copy_string_w(const wchar_t* src, const ma_allocation_callbacks* pAllocationCallbacks)
11978 {
11979     size_t sz = wcslen(src)+1;
11980     wchar_t* dst = (wchar_t*)ma_malloc(sz * sizeof(*dst), pAllocationCallbacks);
11981     if (dst == NULL) {
11982         return NULL;
11983     }
11984
11985     ma_wcscpy_s(dst, sz, src);
11986
11987     return dst;
11988 }
11989
11990
11991 #include <errno.h>
11992 static ma_result ma_result_from_errno(int e)
11993 {
11994     switch (e)
11995     {
11996         case 0: return MA_SUCCESS;
11997     #ifdef EPERM
11998         case EPERM: return MA_INVALID_OPERATION;
11999     #endif
12000     #ifdef ENOENT
12001         case ENOENT: return MA_DOES_NOT_EXIST;
12002     #endif
12003     #ifdef ESRCH
12004         case ESRCH: return MA_DOES_NOT_EXIST;
12005     #endif
12006     #ifdef EINTR
12007         case EINTR: return MA_INTERRUPT;
12008     #endif
12009     #ifdef EIO
12010         case EIO: return MA_IO_ERROR;
12011     #endif
12012     #ifdef ENXIO
12013         case ENXIO: return MA_DOES_NOT_EXIST;
12014     #endif
12015     #ifdef E2BIG
12016         case E2BIG: return MA_INVALID_ARGS;
12017     #endif
12018     #ifdef ENOEXEC
12019         case ENOEXEC: return MA_INVALID_FILE;
12020     #endif
12021     #ifdef EBADF
12022         case EBADF: return MA_INVALID_FILE;
12023     #endif
12024     #ifdef ECHILD
12025         case ECHILD: return MA_ERROR;
12026     #endif
12027     #ifdef EAGAIN
12028         case EAGAIN: return MA_UNAVAILABLE;
12029     #endif
12030     #ifdef ENOMEM
12031         case ENOMEM: return MA_OUT_OF_MEMORY;
12032     #endif
12033     #ifdef EACCES
12034         case EACCES: return MA_ACCESS_DENIED;
12035     #endif
12036     #ifdef EFAULT
12037         case EFAULT: return MA_BAD_ADDRESS;
12038     #endif
12039     #ifdef ENOTBLK
12040         case ENOTBLK: return MA_ERROR;
12041     #endif
12042     #ifdef EBUSY
12043         case EBUSY: return MA_BUSY;
12044     #endif
12045     #ifdef EEXIST
12046         case EEXIST: return MA_ALREADY_EXISTS;
12047     #endif
12048     #ifdef EXDEV
12049         case EXDEV: return MA_ERROR;
12050     #endif
12051     #ifdef ENODEV
12052         case ENODEV: return MA_DOES_NOT_EXIST;
12053     #endif
12054     #ifdef ENOTDIR
12055         case ENOTDIR: return MA_NOT_DIRECTORY;
12056     #endif
12057     #ifdef EISDIR
12058         case EISDIR: return MA_IS_DIRECTORY;
12059     #endif
12060     #ifdef EINVAL
12061         case EINVAL: return MA_INVALID_ARGS;
12062     #endif
12063     #ifdef ENFILE
12064         case ENFILE: return MA_TOO_MANY_OPEN_FILES;
12065     #endif
12066     #ifdef EMFILE
12067         case EMFILE: return MA_TOO_MANY_OPEN_FILES;
12068     #endif
12069     #ifdef ENOTTY
12070         case ENOTTY: return MA_INVALID_OPERATION;
12071     #endif
12072     #ifdef ETXTBSY
12073         case ETXTBSY: return MA_BUSY;
12074     #endif
12075     #ifdef EFBIG
12076         case EFBIG: return MA_TOO_BIG;
12077     #endif
12078     #ifdef ENOSPC
12079         case ENOSPC: return MA_NO_SPACE;
12080     #endif
12081     #ifdef ESPIPE
12082         case ESPIPE: return MA_BAD_SEEK;
12083     #endif
12084     #ifdef EROFS
12085         case EROFS: return MA_ACCESS_DENIED;
12086     #endif
12087     #ifdef EMLINK
12088         case EMLINK: return MA_TOO_MANY_LINKS;
12089     #endif
12090     #ifdef EPIPE
12091         case EPIPE: return MA_BAD_PIPE;
12092     #endif
12093     #ifdef EDOM
12094         case EDOM: return MA_OUT_OF_RANGE;
12095     #endif
12096     #ifdef ERANGE
12097         case ERANGE: return MA_OUT_OF_RANGE;
12098     #endif
12099     #ifdef EDEADLK
12100         case EDEADLK: return MA_DEADLOCK;
12101     #endif
12102     #ifdef ENAMETOOLONG
12103         case ENAMETOOLONG: return MA_PATH_TOO_LONG;
12104     #endif
12105     #ifdef ENOLCK
12106         case ENOLCK: return MA_ERROR;
12107     #endif
12108     #ifdef ENOSYS
12109         case ENOSYS: return MA_NOT_IMPLEMENTED;
12110     #endif
12111     #ifdef ENOTEMPTY
12112         case ENOTEMPTY: return MA_DIRECTORY_NOT_EMPTY;
12113     #endif
12114     #ifdef ELOOP
12115         case ELOOP: return MA_TOO_MANY_LINKS;
12116     #endif
12117     #ifdef ENOMSG
12118         case ENOMSG: return MA_NO_MESSAGE;
12119     #endif
12120     #ifdef EIDRM
12121         case EIDRM: return MA_ERROR;
12122     #endif
12123     #ifdef ECHRNG
12124         case ECHRNG: return MA_ERROR;
12125     #endif
12126     #ifdef EL2NSYNC
12127         case EL2NSYNC: return MA_ERROR;
12128     #endif
12129     #ifdef EL3HLT
12130         case EL3HLT: return MA_ERROR;
12131     #endif
12132     #ifdef EL3RST
12133         case EL3RST: return MA_ERROR;
12134     #endif
12135     #ifdef ELNRNG
12136         case ELNRNG: return MA_OUT_OF_RANGE;
12137     #endif
12138     #ifdef EUNATCH
12139         case EUNATCH: return MA_ERROR;
12140     #endif
12141     #ifdef ENOCSI
12142         case ENOCSI: return MA_ERROR;
12143     #endif
12144     #ifdef EL2HLT
12145         case EL2HLT: return MA_ERROR;
12146     #endif
12147     #ifdef EBADE
12148         case EBADE: return MA_ERROR;
12149     #endif
12150     #ifdef EBADR
12151         case EBADR: return MA_ERROR;
12152     #endif
12153     #ifdef EXFULL
12154         case EXFULL: return MA_ERROR;
12155     #endif
12156     #ifdef ENOANO
12157         case ENOANO: return MA_ERROR;
12158     #endif
12159     #ifdef EBADRQC
12160         case EBADRQC: return MA_ERROR;
12161     #endif
12162     #ifdef EBADSLT
12163         case EBADSLT: return MA_ERROR;
12164     #endif
12165     #ifdef EBFONT
12166         case EBFONT: return MA_INVALID_FILE;
12167     #endif
12168     #ifdef ENOSTR
12169         case ENOSTR: return MA_ERROR;
12170     #endif
12171     #ifdef ENODATA
12172         case ENODATA: return MA_NO_DATA_AVAILABLE;
12173     #endif
12174     #ifdef ETIME
12175         case ETIME: return MA_TIMEOUT;
12176     #endif
12177     #ifdef ENOSR
12178         case ENOSR: return MA_NO_DATA_AVAILABLE;
12179     #endif
12180     #ifdef ENONET
12181         case ENONET: return MA_NO_NETWORK;
12182     #endif
12183     #ifdef ENOPKG
12184         case ENOPKG: return MA_ERROR;
12185     #endif
12186     #ifdef EREMOTE
12187         case EREMOTE: return MA_ERROR;
12188     #endif
12189     #ifdef ENOLINK
12190         case ENOLINK: return MA_ERROR;
12191     #endif
12192     #ifdef EADV
12193         case EADV: return MA_ERROR;
12194     #endif
12195     #ifdef ESRMNT
12196         case ESRMNT: return MA_ERROR;
12197     #endif
12198     #ifdef ECOMM
12199         case ECOMM: return MA_ERROR;
12200     #endif
12201     #ifdef EPROTO
12202         case EPROTO: return MA_ERROR;
12203     #endif
12204     #ifdef EMULTIHOP
12205         case EMULTIHOP: return MA_ERROR;
12206     #endif
12207     #ifdef EDOTDOT
12208         case EDOTDOT: return MA_ERROR;
12209     #endif
12210     #ifdef EBADMSG
12211         case EBADMSG: return MA_BAD_MESSAGE;
12212     #endif
12213     #ifdef EOVERFLOW
12214         case EOVERFLOW: return MA_TOO_BIG;
12215     #endif
12216     #ifdef ENOTUNIQ
12217         case ENOTUNIQ: return MA_NOT_UNIQUE;
12218     #endif
12219     #ifdef EBADFD
12220         case EBADFD: return MA_ERROR;
12221     #endif
12222     #ifdef EREMCHG
12223         case EREMCHG: return MA_ERROR;
12224     #endif
12225     #ifdef ELIBACC
12226         case ELIBACC: return MA_ACCESS_DENIED;
12227     #endif
12228     #ifdef ELIBBAD
12229         case ELIBBAD: return MA_INVALID_FILE;
12230     #endif
12231     #ifdef ELIBSCN
12232         case ELIBSCN: return MA_INVALID_FILE;
12233     #endif
12234     #ifdef ELIBMAX
12235         case ELIBMAX: return MA_ERROR;
12236     #endif
12237     #ifdef ELIBEXEC
12238         case ELIBEXEC: return MA_ERROR;
12239     #endif
12240     #ifdef EILSEQ
12241         case EILSEQ: return MA_INVALID_DATA;
12242     #endif
12243     #ifdef ERESTART
12244         case ERESTART: return MA_ERROR;
12245     #endif
12246     #ifdef ESTRPIPE
12247         case ESTRPIPE: return MA_ERROR;
12248     #endif
12249     #ifdef EUSERS
12250         case EUSERS: return MA_ERROR;
12251     #endif
12252     #ifdef ENOTSOCK
12253         case ENOTSOCK: return MA_NOT_SOCKET;
12254     #endif
12255     #ifdef EDESTADDRREQ
12256         case EDESTADDRREQ: return MA_NO_ADDRESS;
12257     #endif
12258     #ifdef EMSGSIZE
12259         case EMSGSIZE: return MA_TOO_BIG;
12260     #endif
12261     #ifdef EPROTOTYPE
12262         case EPROTOTYPE: return MA_BAD_PROTOCOL;
12263     #endif
12264     #ifdef ENOPROTOOPT
12265         case ENOPROTOOPT: return MA_PROTOCOL_UNAVAILABLE;
12266     #endif
12267     #ifdef EPROTONOSUPPORT
12268         case EPROTONOSUPPORT: return MA_PROTOCOL_NOT_SUPPORTED;
12269     #endif
12270     #ifdef ESOCKTNOSUPPORT
12271         case ESOCKTNOSUPPORT: return MA_SOCKET_NOT_SUPPORTED;
12272     #endif
12273     #ifdef EOPNOTSUPP
12274         case EOPNOTSUPP: return MA_INVALID_OPERATION;
12275     #endif
12276     #ifdef EPFNOSUPPORT
12277         case EPFNOSUPPORT: return MA_PROTOCOL_FAMILY_NOT_SUPPORTED;
12278     #endif
12279     #ifdef EAFNOSUPPORT
12280         case EAFNOSUPPORT: return MA_ADDRESS_FAMILY_NOT_SUPPORTED;
12281     #endif
12282     #ifdef EADDRINUSE
12283         case EADDRINUSE: return MA_ALREADY_IN_USE;
12284     #endif
12285     #ifdef EADDRNOTAVAIL
12286         case EADDRNOTAVAIL: return MA_ERROR;
12287     #endif
12288     #ifdef ENETDOWN
12289         case ENETDOWN: return MA_NO_NETWORK;
12290     #endif
12291     #ifdef ENETUNREACH
12292         case ENETUNREACH: return MA_NO_NETWORK;
12293     #endif
12294     #ifdef ENETRESET
12295         case ENETRESET: return MA_NO_NETWORK;
12296     #endif
12297     #ifdef ECONNABORTED
12298         case ECONNABORTED: return MA_NO_NETWORK;
12299     #endif
12300     #ifdef ECONNRESET
12301         case ECONNRESET: return MA_CONNECTION_RESET;
12302     #endif
12303     #ifdef ENOBUFS
12304         case ENOBUFS: return MA_NO_SPACE;
12305     #endif
12306     #ifdef EISCONN
12307         case EISCONN: return MA_ALREADY_CONNECTED;
12308     #endif
12309     #ifdef ENOTCONN
12310         case ENOTCONN: return MA_NOT_CONNECTED;
12311     #endif
12312     #ifdef ESHUTDOWN
12313         case ESHUTDOWN: return MA_ERROR;
12314     #endif
12315     #ifdef ETOOMANYREFS
12316         case ETOOMANYREFS: return MA_ERROR;
12317     #endif
12318     #ifdef ETIMEDOUT
12319         case ETIMEDOUT: return MA_TIMEOUT;
12320     #endif
12321     #ifdef ECONNREFUSED
12322         case ECONNREFUSED: return MA_CONNECTION_REFUSED;
12323     #endif
12324     #ifdef EHOSTDOWN
12325         case EHOSTDOWN: return MA_NO_HOST;
12326     #endif
12327     #ifdef EHOSTUNREACH
12328         case EHOSTUNREACH: return MA_NO_HOST;
12329     #endif
12330     #ifdef EALREADY
12331         case EALREADY: return MA_IN_PROGRESS;
12332     #endif
12333     #ifdef EINPROGRESS
12334         case EINPROGRESS: return MA_IN_PROGRESS;
12335     #endif
12336     #ifdef ESTALE
12337         case ESTALE: return MA_INVALID_FILE;
12338     #endif
12339     #ifdef EUCLEAN
12340         case EUCLEAN: return MA_ERROR;
12341     #endif
12342     #ifdef ENOTNAM
12343         case ENOTNAM: return MA_ERROR;
12344     #endif
12345     #ifdef ENAVAIL
12346         case ENAVAIL: return MA_ERROR;
12347     #endif
12348     #ifdef EISNAM
12349         case EISNAM: return MA_ERROR;
12350     #endif
12351     #ifdef EREMOTEIO
12352         case EREMOTEIO: return MA_IO_ERROR;
12353     #endif
12354     #ifdef EDQUOT
12355         case EDQUOT: return MA_NO_SPACE;
12356     #endif
12357     #ifdef ENOMEDIUM
12358         case ENOMEDIUM: return MA_DOES_NOT_EXIST;
12359     #endif
12360     #ifdef EMEDIUMTYPE
12361         case EMEDIUMTYPE: return MA_ERROR;
12362     #endif
12363     #ifdef ECANCELED
12364         case ECANCELED: return MA_CANCELLED;
12365     #endif
12366     #ifdef ENOKEY
12367         case ENOKEY: return MA_ERROR;
12368     #endif
12369     #ifdef EKEYEXPIRED
12370         case EKEYEXPIRED: return MA_ERROR;
12371     #endif
12372     #ifdef EKEYREVOKED
12373         case EKEYREVOKED: return MA_ERROR;
12374     #endif
12375     #ifdef EKEYREJECTED
12376         case EKEYREJECTED: return MA_ERROR;
12377     #endif
12378     #ifdef EOWNERDEAD
12379         case EOWNERDEAD: return MA_ERROR;
12380     #endif
12381     #ifdef ENOTRECOVERABLE
12382         case ENOTRECOVERABLE: return MA_ERROR;
12383     #endif
12384     #ifdef ERFKILL
12385         case ERFKILL: return MA_ERROR;
12386     #endif
12387     #ifdef EHWPOISON
12388         case EHWPOISON: return MA_ERROR;
12389     #endif
12390         default: return MA_ERROR;
12391     }
12392 }
12393
12394 MA_API ma_result ma_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
12395 {
12396 #if defined(_MSC_VER) && _MSC_VER >= 1400
12397     errno_t err;
12398 #endif
12399
12400     if (ppFile != NULL) {
12401         *ppFile = NULL;  /* Safety. */
12402     }
12403
12404     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
12405         return MA_INVALID_ARGS;
12406     }
12407
12408 #if defined(_MSC_VER) && _MSC_VER >= 1400
12409     err = fopen_s(ppFile, pFilePath, pOpenMode);
12410     if (err != 0) {
12411         return ma_result_from_errno(err);
12412     }
12413 #else
12414 #if defined(_WIN32) || defined(__APPLE__)
12415     *ppFile = fopen(pFilePath, pOpenMode);
12416 #else
12417     #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
12418         *ppFile = fopen64(pFilePath, pOpenMode);
12419     #else
12420         *ppFile = fopen(pFilePath, pOpenMode);
12421     #endif
12422 #endif
12423     if (*ppFile == NULL) {
12424         ma_result result = ma_result_from_errno(errno);
12425         if (result == MA_SUCCESS) {
12426             result = MA_ERROR;   /* Just a safety check to make sure we never ever return success when pFile == NULL. */
12427         }
12428
12429         return result;
12430     }
12431 #endif
12432
12433     return MA_SUCCESS;
12434 }
12435
12436
12437
12438 /*
12439 _wfopen() isn't always available in all compilation environments.
12440
12441     * Windows only.
12442     * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
12443     * MinGW-64 (both 32- and 64-bit) seems to support it.
12444     * MinGW wraps it in !defined(__STRICT_ANSI__).
12445     * OpenWatcom wraps it in !defined(_NO_EXT_KEYS).
12446
12447 This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
12448 fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
12449 */
12450 #if defined(_WIN32)
12451     #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
12452         #define MA_HAS_WFOPEN
12453     #endif
12454 #endif
12455
12456 MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const ma_allocation_callbacks* pAllocationCallbacks)
12457 {
12458     if (ppFile != NULL) {
12459         *ppFile = NULL;  /* Safety. */
12460     }
12461
12462     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
12463         return MA_INVALID_ARGS;
12464     }
12465
12466 #if defined(MA_HAS_WFOPEN)
12467     {
12468         /* Use _wfopen() on Windows. */
12469     #if defined(_MSC_VER) && _MSC_VER >= 1400
12470         errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
12471         if (err != 0) {
12472             return ma_result_from_errno(err);
12473         }
12474     #else
12475         *ppFile = _wfopen(pFilePath, pOpenMode);
12476         if (*ppFile == NULL) {
12477             return ma_result_from_errno(errno);
12478         }
12479     #endif
12480         (void)pAllocationCallbacks;
12481     }
12482 #else
12483     /*
12484     Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
12485     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
12486     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.
12487     */
12488     {
12489         mbstate_t mbs;
12490         size_t lenMB;
12491         const wchar_t* pFilePathTemp = pFilePath;
12492         char* pFilePathMB = NULL;
12493         char pOpenModeMB[32] = {0};
12494
12495         /* Get the length first. */
12496         MA_ZERO_OBJECT(&mbs);
12497         lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
12498         if (lenMB == (size_t)-1) {
12499             return ma_result_from_errno(errno);
12500         }
12501
12502         pFilePathMB = (char*)ma_malloc(lenMB + 1, pAllocationCallbacks);
12503         if (pFilePathMB == NULL) {
12504             return MA_OUT_OF_MEMORY;
12505         }
12506
12507         pFilePathTemp = pFilePath;
12508         MA_ZERO_OBJECT(&mbs);
12509         wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
12510
12511         /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
12512         {
12513             size_t i = 0;
12514             for (;;) {
12515                 if (pOpenMode[i] == 0) {
12516                     pOpenModeMB[i] = '\0';
12517                     break;
12518                 }
12519
12520                 pOpenModeMB[i] = (char)pOpenMode[i];
12521                 i += 1;
12522             }
12523         }
12524
12525         *ppFile = fopen(pFilePathMB, pOpenModeMB);
12526
12527         ma_free(pFilePathMB, pAllocationCallbacks);
12528     }
12529
12530     if (*ppFile == NULL) {
12531         return MA_ERROR;
12532     }
12533 #endif
12534
12535     return MA_SUCCESS;
12536 }
12537
12538
12539
12540 static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 sizeInBytes)
12541 {
12542 #if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX
12543     MA_COPY_MEMORY(dst, src, (size_t)sizeInBytes);
12544 #else
12545     while (sizeInBytes > 0) {
12546         ma_uint64 bytesToCopyNow = sizeInBytes;
12547         if (bytesToCopyNow > MA_SIZE_MAX) {
12548             bytesToCopyNow = MA_SIZE_MAX;
12549         }
12550
12551         MA_COPY_MEMORY(dst, src, (size_t)bytesToCopyNow);  /* Safe cast to size_t. */
12552
12553         sizeInBytes -= bytesToCopyNow;
12554         dst = (      void*)((      ma_uint8*)dst + bytesToCopyNow);
12555         src = (const void*)((const ma_uint8*)src + bytesToCopyNow);
12556     }
12557 #endif
12558 }
12559
12560 static MA_INLINE void ma_zero_memory_64(void* dst, ma_uint64 sizeInBytes)
12561 {
12562 #if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX
12563     MA_ZERO_MEMORY(dst, (size_t)sizeInBytes);
12564 #else
12565     while (sizeInBytes > 0) {
12566         ma_uint64 bytesToZeroNow = sizeInBytes;
12567         if (bytesToZeroNow > MA_SIZE_MAX) {
12568             bytesToZeroNow = MA_SIZE_MAX;
12569         }
12570
12571         MA_ZERO_MEMORY(dst, (size_t)bytesToZeroNow);  /* Safe cast to size_t. */
12572
12573         sizeInBytes -= bytesToZeroNow;
12574         dst = (void*)((ma_uint8*)dst + bytesToZeroNow);
12575     }
12576 #endif
12577 }
12578
12579
12580 /* Thanks to good old Bit Twiddling Hacks for this one: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */
12581 static MA_INLINE unsigned int ma_next_power_of_2(unsigned int x)
12582 {
12583     x--;
12584     x |= x >> 1;
12585     x |= x >> 2;
12586     x |= x >> 4;
12587     x |= x >> 8;
12588     x |= x >> 16;
12589     x++;
12590
12591     return x;
12592 }
12593
12594 static MA_INLINE unsigned int ma_prev_power_of_2(unsigned int x)
12595 {
12596     return ma_next_power_of_2(x) >> 1;
12597 }
12598
12599 static MA_INLINE unsigned int ma_round_to_power_of_2(unsigned int x)
12600 {
12601     unsigned int prev = ma_prev_power_of_2(x);
12602     unsigned int next = ma_next_power_of_2(x);
12603     if ((next - x) > (x - prev)) {
12604         return prev;
12605     } else {
12606         return next;
12607     }
12608 }
12609
12610 static MA_INLINE unsigned int ma_count_set_bits(unsigned int x)
12611 {
12612     unsigned int count = 0;
12613     while (x != 0) {
12614         if (x & 1) {
12615             count += 1;
12616         }
12617
12618         x = x >> 1;
12619     }
12620
12621     return count;
12622 }
12623
12624
12625
12626 /**************************************************************************************************************************************************************
12627
12628 Allocation Callbacks
12629
12630 **************************************************************************************************************************************************************/
12631 static void* ma__malloc_default(size_t sz, void* pUserData)
12632 {
12633     (void)pUserData;
12634     return MA_MALLOC(sz);
12635 }
12636
12637 static void* ma__realloc_default(void* p, size_t sz, void* pUserData)
12638 {
12639     (void)pUserData;
12640     return MA_REALLOC(p, sz);
12641 }
12642
12643 static void ma__free_default(void* p, void* pUserData)
12644 {
12645     (void)pUserData;
12646     MA_FREE(p);
12647 }
12648
12649 static ma_allocation_callbacks ma_allocation_callbacks_init_default(void)
12650 {
12651     ma_allocation_callbacks callbacks;
12652     callbacks.pUserData = NULL;
12653     callbacks.onMalloc  = ma__malloc_default;
12654     callbacks.onRealloc = ma__realloc_default;
12655     callbacks.onFree    = ma__free_default;
12656
12657     return callbacks;
12658 }
12659
12660 static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst, const ma_allocation_callbacks* pSrc)
12661 {
12662     if (pDst == NULL) {
12663         return MA_INVALID_ARGS;
12664     }
12665
12666     if (pSrc == NULL) {
12667         *pDst = ma_allocation_callbacks_init_default();
12668     } else {
12669         if (pSrc->pUserData == NULL && pSrc->onFree == NULL && pSrc->onMalloc == NULL && pSrc->onRealloc == NULL) {
12670             *pDst = ma_allocation_callbacks_init_default();
12671         } else {
12672             if (pSrc->onFree == NULL || (pSrc->onMalloc == NULL && pSrc->onRealloc == NULL)) {
12673                 return MA_INVALID_ARGS;    /* Invalid allocation callbacks. */
12674             } else {
12675                 *pDst = *pSrc;
12676             }
12677         }
12678     }
12679
12680     return MA_SUCCESS;
12681 }
12682
12683
12684
12685
12686 /**************************************************************************************************************************************************************
12687
12688 Logging
12689
12690 **************************************************************************************************************************************************************/
12691 MA_API const char* ma_log_level_to_string(ma_uint32 logLevel)
12692 {
12693     switch (logLevel)
12694     {
12695         case MA_LOG_LEVEL_DEBUG:   return "DEBUG";
12696         case MA_LOG_LEVEL_INFO:    return "INFO";
12697         case MA_LOG_LEVEL_WARNING: return "WARNING";
12698         case MA_LOG_LEVEL_ERROR:   return "ERROR";
12699         default:                   return "ERROR";
12700     }
12701 }
12702
12703 #if defined(MA_DEBUG_OUTPUT)
12704
12705 /* Customize this to use a specific tag in __android_log_print() for debug output messages. */
12706 #ifndef MA_ANDROID_LOG_TAG
12707 #define MA_ANDROID_LOG_TAG  "miniaudio"
12708 #endif
12709
12710 void ma_log_callback_debug(void* pUserData, ma_uint32 level, const char* pMessage)
12711 {
12712     (void)pUserData;
12713
12714     /* Special handling for some platforms. */
12715     #if defined(MA_ANDROID)
12716     {
12717         /* Android. */
12718         __android_log_print(ANDROID_LOG_DEBUG, MA_ANDROID_LOG_TAG, "%s: %s", ma_log_level_to_string(level), pMessage);
12719     }
12720     #else
12721     {
12722         /* Everything else. */
12723         printf("%s: %s", ma_log_level_to_string(level), pMessage);
12724     }
12725     #endif
12726 }
12727 #endif
12728
12729 MA_API ma_log_callback ma_log_callback_init(ma_log_callback_proc onLog, void* pUserData)
12730 {
12731     ma_log_callback callback;
12732
12733     MA_ZERO_OBJECT(&callback);
12734     callback.onLog     = onLog;
12735     callback.pUserData = pUserData;
12736
12737     return callback;
12738 }
12739
12740
12741 MA_API ma_result ma_log_init(const ma_allocation_callbacks* pAllocationCallbacks, ma_log* pLog)
12742 {
12743     if (pLog == NULL) {
12744         return MA_INVALID_ARGS;
12745     }
12746
12747     MA_ZERO_OBJECT(pLog);
12748     ma_allocation_callbacks_init_copy(&pLog->allocationCallbacks, pAllocationCallbacks);
12749
12750     /* We need a mutex for thread safety. */
12751     #ifndef MA_NO_THREADING
12752     {
12753         ma_result result = ma_mutex_init(&pLog->lock);
12754         if (result != MA_SUCCESS) {
12755             return result;
12756         }
12757     }
12758     #endif
12759
12760     /* If we're using debug output, enable it. */
12761     #if defined(MA_DEBUG_OUTPUT)
12762     {
12763         ma_log_register_callback(pLog, ma_log_callback_init(ma_log_callback_debug, NULL)); /* Doesn't really matter if this fails. */
12764     }
12765     #endif
12766
12767     return MA_SUCCESS;
12768 }
12769
12770 MA_API void ma_log_uninit(ma_log* pLog)
12771 {
12772     if (pLog == NULL) {
12773         return;
12774     }
12775
12776 #ifndef MA_NO_THREADING
12777     ma_mutex_uninit(&pLog->lock);
12778 #endif
12779 }
12780
12781 static void ma_log_lock(ma_log* pLog)
12782 {
12783 #ifndef MA_NO_THREADING
12784     ma_mutex_lock(&pLog->lock);
12785 #else
12786     (void)pLog;
12787 #endif
12788 }
12789
12790 static void ma_log_unlock(ma_log* pLog)
12791 {
12792 #ifndef MA_NO_THREADING
12793     ma_mutex_unlock(&pLog->lock);
12794 #else
12795     (void)pLog;
12796 #endif
12797 }
12798
12799 MA_API ma_result ma_log_register_callback(ma_log* pLog, ma_log_callback callback)
12800 {
12801     ma_result result = MA_SUCCESS;
12802
12803     if (pLog == NULL || callback.onLog == NULL) {
12804         return MA_INVALID_ARGS;
12805     }
12806
12807     ma_log_lock(pLog);
12808     {
12809         if (pLog->callbackCount == ma_countof(pLog->callbacks)) {
12810             result = MA_OUT_OF_MEMORY;  /* Reached the maximum allowed log callbacks. */
12811         } else {
12812             pLog->callbacks[pLog->callbackCount] = callback;
12813             pLog->callbackCount += 1;
12814         }
12815     }
12816     ma_log_unlock(pLog);
12817
12818     return result;
12819 }
12820
12821 MA_API ma_result ma_log_unregister_callback(ma_log* pLog, ma_log_callback callback)
12822 {
12823     if (pLog == NULL) {
12824         return MA_INVALID_ARGS;
12825     }
12826
12827     ma_log_lock(pLog);
12828     {
12829         ma_uint32 iLog;
12830         for (iLog = 0; iLog < pLog->callbackCount; ) {
12831             if (pLog->callbacks[iLog].onLog == callback.onLog) {
12832                 /* Found. Move everything down a slot. */
12833                 ma_uint32 jLog;
12834                 for (jLog = iLog; jLog < pLog->callbackCount-1; jLog += 1) {
12835                     pLog->callbacks[jLog] = pLog->callbacks[jLog + 1];
12836                 }
12837
12838                 pLog->callbackCount -= 1;
12839             } else {
12840                 /* Not found. */
12841                 iLog += 1;
12842             }
12843         }
12844     }
12845     ma_log_unlock(pLog);
12846
12847     return MA_SUCCESS;
12848 }
12849
12850 MA_API ma_result ma_log_post(ma_log* pLog, ma_uint32 level, const char* pMessage)
12851 {
12852     if (pLog == NULL || pMessage == NULL) {
12853         return MA_INVALID_ARGS;
12854     }
12855
12856     /* If it's a debug log, ignore it unless MA_DEBUG_OUTPUT is enabled. */
12857     #if !defined(MA_DEBUG_OUTPUT)
12858     {
12859         if (level == MA_LOG_LEVEL_DEBUG) {
12860             return MA_INVALID_ARGS; /* Don't post debug messages if debug output is disabled. */
12861         }
12862     }
12863     #endif
12864
12865     ma_log_lock(pLog);
12866     {
12867         ma_uint32 iLog;
12868         for (iLog = 0; iLog < pLog->callbackCount; iLog += 1) {
12869             if (pLog->callbacks[iLog].onLog) {
12870                 pLog->callbacks[iLog].onLog(pLog->callbacks[iLog].pUserData, level, pMessage);
12871             }
12872         }
12873     }
12874     ma_log_unlock(pLog);
12875
12876     return MA_SUCCESS;
12877 }
12878
12879
12880 /*
12881 We need to emulate _vscprintf() for the VC6 build. This can be more efficient, but since it's only VC6, and it's just a
12882 logging function, I'm happy to keep this simple. In the VC6 build we can implement this in terms of _vsnprintf().
12883 */
12884 #if defined(_MSC_VER) && _MSC_VER < 1900
12885 static int ma_vscprintf(const ma_allocation_callbacks* pAllocationCallbacks, const char* format, va_list args)
12886 {
12887 #if _MSC_VER > 1200
12888     return _vscprintf(format, args);
12889 #else
12890     int result;
12891     char* pTempBuffer = NULL;
12892     size_t tempBufferCap = 1024;
12893
12894     if (format == NULL) {
12895         errno = EINVAL;
12896         return -1;
12897     }
12898
12899     for (;;) {
12900         char* pNewTempBuffer = (char*)ma_realloc(pTempBuffer, tempBufferCap, pAllocationCallbacks);
12901         if (pNewTempBuffer == NULL) {
12902             ma_free(pTempBuffer, pAllocationCallbacks);
12903             errno = ENOMEM;
12904             return -1;  /* Out of memory. */
12905         }
12906
12907         pTempBuffer = pNewTempBuffer;
12908
12909         result = _vsnprintf(pTempBuffer, tempBufferCap, format, args);
12910         ma_free(pTempBuffer, NULL);
12911
12912         if (result != -1) {
12913             break;  /* Got it. */
12914         }
12915
12916         /* Buffer wasn't big enough. Ideally it'd be nice to use an error code to know the reason for sure, but this is reliable enough. */
12917         tempBufferCap *= 2;
12918     }
12919
12920     return result;
12921 #endif
12922 }
12923 #endif
12924
12925 MA_API ma_result ma_log_postv(ma_log* pLog, ma_uint32 level, const char* pFormat, va_list args)
12926 {
12927     if (pLog == NULL || pFormat == NULL) {
12928         return MA_INVALID_ARGS;
12929     }
12930
12931     /*
12932     If it's a debug log, ignore it unless MA_DEBUG_OUTPUT is enabled. Do this before generating the
12933     formatted message string so that we don't waste time only to have ma_log_post() reject it.
12934     */
12935     #if !defined(MA_DEBUG_OUTPUT)
12936     {
12937         if (level == MA_LOG_LEVEL_DEBUG) {
12938             return MA_INVALID_ARGS; /* Don't post debug messages if debug output is disabled. */
12939         }
12940     }
12941     #endif
12942
12943     #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || ((!defined(_MSC_VER) || _MSC_VER >= 1900) && !defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
12944     {
12945         ma_result result;
12946         int length;
12947         char  pFormattedMessageStack[1024];
12948         char* pFormattedMessageHeap = NULL;
12949
12950         /* First try formatting into our fixed sized stack allocated buffer. If this is too small we'll fallback to a heap allocation. */
12951         length = vsnprintf(pFormattedMessageStack, sizeof(pFormattedMessageStack), pFormat, args);
12952         if (length < 0) {
12953             return MA_INVALID_OPERATION;    /* An error occured when trying to convert the buffer. */
12954         }
12955
12956         if ((size_t)length < sizeof(pFormattedMessageStack)) {
12957             /* The string was written to the stack. */
12958             result = ma_log_post(pLog, level, pFormattedMessageStack);
12959         } else {
12960             /* The stack buffer was too small, try the heap. */
12961             pFormattedMessageHeap = (char*)ma_malloc(length + 1, &pLog->allocationCallbacks);
12962             if (pFormattedMessageHeap == NULL) {
12963                 return MA_OUT_OF_MEMORY;
12964             }
12965
12966             length = vsnprintf(pFormattedMessageHeap, length + 1, pFormat, args);
12967             if (length < 0) {
12968                 ma_free(pFormattedMessageHeap, &pLog->allocationCallbacks);
12969                 return MA_INVALID_OPERATION;
12970             }
12971
12972             result = ma_log_post(pLog, level, pFormattedMessageHeap);
12973             ma_free(pFormattedMessageHeap, &pLog->allocationCallbacks);
12974         }
12975
12976         return result;
12977     }
12978     #else
12979     {
12980         /*
12981         Without snprintf() we need to first measure the string and then heap allocate it. I'm only aware of Visual Studio having support for this without snprintf(), so we'll
12982         need to restrict this branch to Visual Studio. For other compilers we need to just not support formatted logging because I don't want the security risk of overflowing
12983         a fixed sized stack allocated buffer.
12984         */
12985         #if defined(_MSC_VER) && _MSC_VER >= 1200   /* 1200 = VC6 */
12986         {
12987             ma_result result;
12988             int formattedLen;
12989             char* pFormattedMessage = NULL;
12990             va_list args2;
12991
12992             #if _MSC_VER >= 1800
12993             {
12994                 va_copy(args2, args);
12995             }
12996             #else
12997             {
12998                 args2 = args;
12999             }
13000             #endif
13001
13002             formattedLen = ma_vscprintf(&pLog->allocationCallbacks, pFormat, args2);
13003             va_end(args2);
13004
13005             if (formattedLen <= 0) {
13006                 return MA_INVALID_OPERATION;
13007             }
13008
13009             pFormattedMessage = (char*)ma_malloc(formattedLen + 1, &pLog->allocationCallbacks);
13010             if (pFormattedMessage == NULL) {
13011                 return MA_OUT_OF_MEMORY;
13012             }
13013
13014             /* We'll get errors on newer versions of Visual Studio if we try to use vsprintf().  */
13015             #if _MSC_VER >= 1400    /* 1400 = Visual Studio 2005 */
13016             {
13017                 vsprintf_s(pFormattedMessage, formattedLen + 1, pFormat, args);
13018             }
13019             #else
13020             {
13021                 vsprintf(pFormattedMessage, pFormat, args);
13022             }
13023             #endif
13024
13025             result = ma_log_post(pLog, level, pFormattedMessage);
13026             ma_free(pFormattedMessage, &pLog->allocationCallbacks);
13027
13028             return result;
13029         }
13030         #else
13031         {
13032             /* Can't do anything because we don't have a safe way of to emulate vsnprintf() without a manual solution. */
13033             (void)level;
13034             (void)args;
13035
13036             return MA_INVALID_OPERATION;
13037         }
13038         #endif
13039     }
13040     #endif
13041 }
13042
13043 MA_API ma_result ma_log_postf(ma_log* pLog, ma_uint32 level, const char* pFormat, ...)
13044 {
13045     ma_result result;
13046     va_list args;
13047
13048     if (pLog == NULL || pFormat == NULL) {
13049         return MA_INVALID_ARGS;
13050     }
13051
13052     /*
13053     If it's a debug log, ignore it unless MA_DEBUG_OUTPUT is enabled. Do this before generating the
13054     formatted message string so that we don't waste time only to have ma_log_post() reject it.
13055     */
13056     #if !defined(MA_DEBUG_OUTPUT)
13057     {
13058         if (level == MA_LOG_LEVEL_DEBUG) {
13059             return MA_INVALID_ARGS; /* Don't post debug messages if debug output is disabled. */
13060         }
13061     }
13062     #endif
13063
13064     va_start(args, pFormat);
13065     {
13066         result = ma_log_postv(pLog, level, pFormat, args);
13067     }
13068     va_end(args);
13069
13070     return result;
13071 }
13072
13073
13074
13075 static MA_INLINE ma_uint8 ma_clip_u8(ma_int32 x)
13076 {
13077     return (ma_uint8)(ma_clamp(x, -128, 127) + 128);
13078 }
13079
13080 static MA_INLINE ma_int16 ma_clip_s16(ma_int32 x)
13081 {
13082     return (ma_int16)ma_clamp(x, -32768, 32767);
13083 }
13084
13085 static MA_INLINE ma_int64 ma_clip_s24(ma_int64 x)
13086 {
13087     return (ma_int64)ma_clamp(x, -8388608, 8388607);
13088 }
13089
13090 static MA_INLINE ma_int32 ma_clip_s32(ma_int64 x)
13091 {
13092     /* This dance is to silence warnings with -std=c89. A good compiler should be able to optimize this away. */
13093     ma_int64 clipMin;
13094     ma_int64 clipMax;
13095     clipMin = -((ma_int64)2147483647 + 1);
13096     clipMax =   (ma_int64)2147483647;
13097
13098     return (ma_int32)ma_clamp(x, clipMin, clipMax);
13099 }
13100
13101 static MA_INLINE float ma_clip_f32(float x)
13102 {
13103     if (x < -1) return -1;
13104     if (x > +1) return +1;
13105     return x;
13106 }
13107
13108
13109 static MA_INLINE float ma_mix_f32(float x, float y, float a)
13110 {
13111     return x*(1-a) + y*a;
13112 }
13113 static MA_INLINE float ma_mix_f32_fast(float x, float y, float a)
13114 {
13115     float r0 = (y - x);
13116     float r1 = r0*a;
13117     return x + r1;
13118     /*return x + (y - x)*a;*/
13119 }
13120
13121 #if defined(MA_SUPPORT_SSE2)
13122 static MA_INLINE __m128 ma_mix_f32_fast__sse2(__m128 x, __m128 y, __m128 a)
13123 {
13124     return _mm_add_ps(x, _mm_mul_ps(_mm_sub_ps(y, x), a));
13125 }
13126 #endif
13127 #if defined(MA_SUPPORT_AVX2)
13128 static MA_INLINE __m256 ma_mix_f32_fast__avx2(__m256 x, __m256 y, __m256 a)
13129 {
13130     return _mm256_add_ps(x, _mm256_mul_ps(_mm256_sub_ps(y, x), a));
13131 }
13132 #endif
13133 #if defined(MA_SUPPORT_NEON)
13134 static MA_INLINE float32x4_t ma_mix_f32_fast__neon(float32x4_t x, float32x4_t y, float32x4_t a)
13135 {
13136     return vaddq_f32(x, vmulq_f32(vsubq_f32(y, x), a));
13137 }
13138 #endif
13139
13140
13141 static MA_INLINE double ma_mix_f64(double x, double y, double a)
13142 {
13143     return x*(1-a) + y*a;
13144 }
13145 static MA_INLINE double ma_mix_f64_fast(double x, double y, double a)
13146 {
13147     return x + (y - x)*a;
13148 }
13149
13150 static MA_INLINE float ma_scale_to_range_f32(float x, float lo, float hi)
13151 {
13152     return lo + x*(hi-lo);
13153 }
13154
13155
13156 /*
13157 Greatest common factor using Euclid's algorithm iteratively.
13158 */
13159 static MA_INLINE ma_uint32 ma_gcf_u32(ma_uint32 a, ma_uint32 b)
13160 {
13161     for (;;) {
13162         if (b == 0) {
13163             break;
13164         } else {
13165             ma_uint32 t = a;
13166             a = b;
13167             b = t % a;
13168         }
13169     }
13170
13171     return a;
13172 }
13173
13174
13175 static ma_uint32 ma_ffs_32(ma_uint32 x)
13176 {
13177     ma_uint32 i;
13178
13179     /* Just a naive implementation just to get things working for now. Will optimize this later. */
13180     for (i = 0; i < 32; i += 1) {
13181         if ((x & (1 << i)) != 0) {
13182             return i;
13183         }
13184     }
13185
13186     return i;
13187 }
13188
13189 static MA_INLINE ma_int16 ma_float_to_fixed_16(float x)
13190 {
13191     return (ma_int16)(x * (1 << 8));
13192 }
13193
13194
13195
13196 /*
13197 Random Number Generation
13198
13199 miniaudio uses the LCG random number generation algorithm. This is good enough for audio.
13200
13201 Note that miniaudio's global LCG implementation uses global state which is _not_ thread-local. When this is called across
13202 multiple threads, results will be unpredictable. However, it won't crash and results will still be random enough for
13203 miniaudio's purposes.
13204 */
13205 #ifndef MA_DEFAULT_LCG_SEED
13206 #define MA_DEFAULT_LCG_SEED 4321
13207 #endif
13208
13209 #define MA_LCG_M   2147483647
13210 #define MA_LCG_A   48271
13211 #define MA_LCG_C   0
13212
13213 static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_seed() to use an explicit seed. */
13214
13215 static MA_INLINE void ma_lcg_seed(ma_lcg* pLCG, ma_int32 seed)
13216 {
13217     MA_ASSERT(pLCG != NULL);
13218     pLCG->state = seed;
13219 }
13220
13221 static MA_INLINE ma_int32 ma_lcg_rand_s32(ma_lcg* pLCG)
13222 {
13223     pLCG->state = (MA_LCG_A * pLCG->state + MA_LCG_C) % MA_LCG_M;
13224     return pLCG->state;
13225 }
13226
13227 static MA_INLINE ma_uint32 ma_lcg_rand_u32(ma_lcg* pLCG)
13228 {
13229     return (ma_uint32)ma_lcg_rand_s32(pLCG);
13230 }
13231
13232 static MA_INLINE ma_int16 ma_lcg_rand_s16(ma_lcg* pLCG)
13233 {
13234     return (ma_int16)(ma_lcg_rand_s32(pLCG) & 0xFFFF);
13235 }
13236
13237 static MA_INLINE double ma_lcg_rand_f64(ma_lcg* pLCG)
13238 {
13239     return ma_lcg_rand_s32(pLCG) / (double)0x7FFFFFFF;
13240 }
13241
13242 static MA_INLINE float ma_lcg_rand_f32(ma_lcg* pLCG)
13243 {
13244     return (float)ma_lcg_rand_f64(pLCG);
13245 }
13246
13247 static MA_INLINE float ma_lcg_rand_range_f32(ma_lcg* pLCG, float lo, float hi)
13248 {
13249     return ma_scale_to_range_f32(ma_lcg_rand_f32(pLCG), lo, hi);
13250 }
13251
13252 static MA_INLINE ma_int32 ma_lcg_rand_range_s32(ma_lcg* pLCG, ma_int32 lo, ma_int32 hi)
13253 {
13254     if (lo == hi) {
13255         return lo;
13256     }
13257
13258     return lo + ma_lcg_rand_u32(pLCG) / (0xFFFFFFFF / (hi - lo + 1) + 1);
13259 }
13260
13261
13262
13263 static MA_INLINE void ma_seed(ma_int32 seed)
13264 {
13265     ma_lcg_seed(&g_maLCG, seed);
13266 }
13267
13268 static MA_INLINE ma_int32 ma_rand_s32(void)
13269 {
13270     return ma_lcg_rand_s32(&g_maLCG);
13271 }
13272
13273 static MA_INLINE ma_uint32 ma_rand_u32(void)
13274 {
13275     return ma_lcg_rand_u32(&g_maLCG);
13276 }
13277
13278 static MA_INLINE double ma_rand_f64(void)
13279 {
13280     return ma_lcg_rand_f64(&g_maLCG);
13281 }
13282
13283 static MA_INLINE float ma_rand_f32(void)
13284 {
13285     return ma_lcg_rand_f32(&g_maLCG);
13286 }
13287
13288 static MA_INLINE float ma_rand_range_f32(float lo, float hi)
13289 {
13290     return ma_lcg_rand_range_f32(&g_maLCG, lo, hi);
13291 }
13292
13293 static MA_INLINE ma_int32 ma_rand_range_s32(ma_int32 lo, ma_int32 hi)
13294 {
13295     return ma_lcg_rand_range_s32(&g_maLCG, lo, hi);
13296 }
13297
13298
13299 static MA_INLINE float ma_dither_f32_rectangle(float ditherMin, float ditherMax)
13300 {
13301     return ma_rand_range_f32(ditherMin, ditherMax);
13302 }
13303
13304 static MA_INLINE float ma_dither_f32_triangle(float ditherMin, float ditherMax)
13305 {
13306     float a = ma_rand_range_f32(ditherMin, 0);
13307     float b = ma_rand_range_f32(0, ditherMax);
13308     return a + b;
13309 }
13310
13311 static MA_INLINE float ma_dither_f32(ma_dither_mode ditherMode, float ditherMin, float ditherMax)
13312 {
13313     if (ditherMode == ma_dither_mode_rectangle) {
13314         return ma_dither_f32_rectangle(ditherMin, ditherMax);
13315     }
13316     if (ditherMode == ma_dither_mode_triangle) {
13317         return ma_dither_f32_triangle(ditherMin, ditherMax);
13318     }
13319
13320     return 0;
13321 }
13322
13323 static MA_INLINE ma_int32 ma_dither_s32(ma_dither_mode ditherMode, ma_int32 ditherMin, ma_int32 ditherMax)
13324 {
13325     if (ditherMode == ma_dither_mode_rectangle) {
13326         ma_int32 a = ma_rand_range_s32(ditherMin, ditherMax);
13327         return a;
13328     }
13329     if (ditherMode == ma_dither_mode_triangle) {
13330         ma_int32 a = ma_rand_range_s32(ditherMin, 0);
13331         ma_int32 b = ma_rand_range_s32(0, ditherMax);
13332         return a + b;
13333     }
13334
13335     return 0;
13336 }
13337
13338
13339 /**************************************************************************************************************************************************************
13340
13341 Atomics
13342
13343 **************************************************************************************************************************************************************/
13344 /* c89atomic.h begin */
13345 #ifndef c89atomic_h
13346 #define c89atomic_h
13347 #if defined(__cplusplus)
13348 extern "C" {
13349 #endif
13350 typedef   signed char           c89atomic_int8;
13351 typedef unsigned char           c89atomic_uint8;
13352 typedef   signed short          c89atomic_int16;
13353 typedef unsigned short          c89atomic_uint16;
13354 typedef   signed int            c89atomic_int32;
13355 typedef unsigned int            c89atomic_uint32;
13356 #if defined(_MSC_VER) && !defined(__clang__)
13357     typedef   signed __int64    c89atomic_int64;
13358     typedef unsigned __int64    c89atomic_uint64;
13359 #else
13360     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
13361         #pragma GCC diagnostic push
13362         #pragma GCC diagnostic ignored "-Wlong-long"
13363         #if defined(__clang__)
13364             #pragma GCC diagnostic ignored "-Wc++11-long-long"
13365         #endif
13366     #endif
13367     typedef   signed long long  c89atomic_int64;
13368     typedef unsigned long long  c89atomic_uint64;
13369     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
13370         #pragma GCC diagnostic pop
13371     #endif
13372 #endif
13373 typedef int                     c89atomic_memory_order;
13374 typedef unsigned char           c89atomic_bool;
13375 #if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT)
13376 #ifdef _WIN32
13377 #ifdef _WIN64
13378 #define C89ATOMIC_64BIT
13379 #else
13380 #define C89ATOMIC_32BIT
13381 #endif
13382 #endif
13383 #endif
13384 #if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT)
13385 #ifdef __GNUC__
13386 #ifdef __LP64__
13387 #define C89ATOMIC_64BIT
13388 #else
13389 #define C89ATOMIC_32BIT
13390 #endif
13391 #endif
13392 #endif
13393 #if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT)
13394 #include <stdint.h>
13395 #if INTPTR_MAX == INT64_MAX
13396 #define C89ATOMIC_64BIT
13397 #else
13398 #define C89ATOMIC_32BIT
13399 #endif
13400 #endif
13401 #if defined(__x86_64__) || defined(_M_X64)
13402 #define C89ATOMIC_X64
13403 #elif defined(__i386) || defined(_M_IX86)
13404 #define C89ATOMIC_X86
13405 #elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64)
13406 #define C89ATOMIC_ARM
13407 #endif
13408 #if defined(_MSC_VER)
13409     #define C89ATOMIC_INLINE __forceinline
13410 #elif defined(__GNUC__)
13411     #if defined(__STRICT_ANSI__)
13412         #define C89ATOMIC_INLINE __inline__ __attribute__((always_inline))
13413     #else
13414         #define C89ATOMIC_INLINE inline __attribute__((always_inline))
13415     #endif
13416 #elif defined(__WATCOMC__) || defined(__DMC__)
13417     #define C89ATOMIC_INLINE __inline
13418 #else
13419     #define C89ATOMIC_INLINE
13420 #endif
13421 #define C89ATOMIC_HAS_8
13422 #define C89ATOMIC_HAS_16
13423 #define C89ATOMIC_HAS_32
13424 #define C89ATOMIC_HAS_64
13425 #if (defined(_MSC_VER) ) || defined(__WATCOMC__) || defined(__DMC__)
13426     #define c89atomic_memory_order_relaxed  0
13427     #define c89atomic_memory_order_consume  1
13428     #define c89atomic_memory_order_acquire  2
13429     #define c89atomic_memory_order_release  3
13430     #define c89atomic_memory_order_acq_rel  4
13431     #define c89atomic_memory_order_seq_cst  5
13432     #if _MSC_VER < 1600 && defined(C89ATOMIC_X86)
13433         #define C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY
13434     #endif
13435     #if _MSC_VER < 1600
13436         #undef C89ATOMIC_HAS_8
13437         #undef C89ATOMIC_HAS_16
13438     #endif
13439     #if !defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
13440         #include <intrin.h>
13441     #endif
13442     #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
13443         #if defined(C89ATOMIC_HAS_8)
13444             static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 desired)
13445             {
13446                 c89atomic_uint8 result = 0;
13447                 __asm {
13448                     mov ecx, dst
13449                     mov al,  expected
13450                     mov dl,  desired
13451                     lock cmpxchg [ecx], dl
13452                     mov result, al
13453                 }
13454                 return result;
13455             }
13456         #endif
13457         #if defined(C89ATOMIC_HAS_16)
13458             static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 desired)
13459             {
13460                 c89atomic_uint16 result = 0;
13461                 __asm {
13462                     mov ecx, dst
13463                     mov ax,  expected
13464                     mov dx,  desired
13465                     lock cmpxchg [ecx], dx
13466                     mov result, ax
13467                 }
13468                 return result;
13469             }
13470         #endif
13471         #if defined(C89ATOMIC_HAS_32)
13472             static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 desired)
13473             {
13474                 c89atomic_uint32 result = 0;
13475                 __asm {
13476                     mov ecx, dst
13477                     mov eax, expected
13478                     mov edx, desired
13479                     lock cmpxchg [ecx], edx
13480                     mov result, eax
13481                 }
13482                 return result;
13483             }
13484         #endif
13485         #if defined(C89ATOMIC_HAS_64)
13486             static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 desired)
13487             {
13488                 c89atomic_uint32 resultEAX = 0;
13489                 c89atomic_uint32 resultEDX = 0;
13490                 __asm {
13491                     mov esi, dst
13492                     mov eax, dword ptr expected
13493                     mov edx, dword ptr expected + 4
13494                     mov ebx, dword ptr desired
13495                     mov ecx, dword ptr desired + 4
13496                     lock cmpxchg8b qword ptr [esi]
13497                     mov resultEAX, eax
13498                     mov resultEDX, edx
13499                 }
13500                 return ((c89atomic_uint64)resultEDX << 32) | resultEAX;
13501             }
13502         #endif
13503     #else
13504         #if defined(C89ATOMIC_HAS_8)
13505             #define c89atomic_compare_and_swap_8( dst, expected, desired) (c89atomic_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)desired, (char)expected)
13506         #endif
13507         #if defined(C89ATOMIC_HAS_16)
13508             #define c89atomic_compare_and_swap_16(dst, expected, desired) (c89atomic_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)desired, (short)expected)
13509         #endif
13510         #if defined(C89ATOMIC_HAS_32)
13511             #define c89atomic_compare_and_swap_32(dst, expected, desired) (c89atomic_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)desired, (long)expected)
13512         #endif
13513         #if defined(C89ATOMIC_HAS_64)
13514             #define c89atomic_compare_and_swap_64(dst, expected, desired) (c89atomic_uint64)_InterlockedCompareExchange64((volatile c89atomic_int64*)dst, (c89atomic_int64)desired, (c89atomic_int64)expected)
13515         #endif
13516     #endif
13517     #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
13518         #if defined(C89ATOMIC_HAS_8)
13519             static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
13520             {
13521                 c89atomic_uint8 result = 0;
13522                 (void)order;
13523                 __asm {
13524                     mov ecx, dst
13525                     mov al,  src
13526                     lock xchg [ecx], al
13527                     mov result, al
13528                 }
13529                 return result;
13530             }
13531         #endif
13532         #if defined(C89ATOMIC_HAS_16)
13533             static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
13534             {
13535                 c89atomic_uint16 result = 0;
13536                 (void)order;
13537                 __asm {
13538                     mov ecx, dst
13539                     mov ax,  src
13540                     lock xchg [ecx], ax
13541                     mov result, ax
13542                 }
13543                 return result;
13544             }
13545         #endif
13546         #if defined(C89ATOMIC_HAS_32)
13547             static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
13548             {
13549                 c89atomic_uint32 result = 0;
13550                 (void)order;
13551                 __asm {
13552                     mov ecx, dst
13553                     mov eax, src
13554                     lock xchg [ecx], eax
13555                     mov result, eax
13556                 }
13557                 return result;
13558             }
13559         #endif
13560     #else
13561         #if defined(C89ATOMIC_HAS_8)
13562             static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
13563             {
13564                 (void)order;
13565                 return (c89atomic_uint8)_InterlockedExchange8((volatile char*)dst, (char)src);
13566             }
13567         #endif
13568         #if defined(C89ATOMIC_HAS_16)
13569             static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
13570             {
13571                 (void)order;
13572                 return (c89atomic_uint16)_InterlockedExchange16((volatile short*)dst, (short)src);
13573             }
13574         #endif
13575         #if defined(C89ATOMIC_HAS_32)
13576             static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
13577             {
13578                 (void)order;
13579                 return (c89atomic_uint32)_InterlockedExchange((volatile long*)dst, (long)src);
13580             }
13581         #endif
13582         #if defined(C89ATOMIC_HAS_64) && defined(C89ATOMIC_64BIT)
13583             static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
13584             {
13585                 (void)order;
13586                 return (c89atomic_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src);
13587             }
13588         #else
13589         #endif
13590     #endif
13591     #if defined(C89ATOMIC_HAS_64) && !defined(C89ATOMIC_64BIT)
13592         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
13593         {
13594             c89atomic_uint64 oldValue;
13595             do {
13596                 oldValue = *dst;
13597             } while (c89atomic_compare_and_swap_64(dst, oldValue, src) != oldValue);
13598             (void)order;
13599             return oldValue;
13600         }
13601     #endif
13602     #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
13603         #if defined(C89ATOMIC_HAS_8)
13604             static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
13605             {
13606                 c89atomic_uint8 result = 0;
13607                 (void)order;
13608                 __asm {
13609                     mov ecx, dst
13610                     mov al,  src
13611                     lock xadd [ecx], al
13612                     mov result, al
13613                 }
13614                 return result;
13615             }
13616         #endif
13617         #if defined(C89ATOMIC_HAS_16)
13618             static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
13619             {
13620                 c89atomic_uint16 result = 0;
13621                 (void)order;
13622                 __asm {
13623                     mov ecx, dst
13624                     mov ax,  src
13625                     lock xadd [ecx], ax
13626                     mov result, ax
13627                 }
13628                 return result;
13629             }
13630         #endif
13631         #if defined(C89ATOMIC_HAS_32)
13632             static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
13633             {
13634                 c89atomic_uint32 result = 0;
13635                 (void)order;
13636                 __asm {
13637                     mov ecx, dst
13638                     mov eax, src
13639                     lock xadd [ecx], eax
13640                     mov result, eax
13641                 }
13642                 return result;
13643             }
13644         #endif
13645     #else
13646         #if defined(C89ATOMIC_HAS_8)
13647             static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
13648             {
13649                 (void)order;
13650                 return (c89atomic_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src);
13651             }
13652         #endif
13653         #if defined(C89ATOMIC_HAS_16)
13654             static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
13655             {
13656                 (void)order;
13657                 return (c89atomic_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src);
13658             }
13659         #endif
13660         #if defined(C89ATOMIC_HAS_32)
13661             static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
13662             {
13663                 (void)order;
13664                 return (c89atomic_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src);
13665             }
13666         #endif
13667         #if defined(C89ATOMIC_HAS_64) && defined(C89ATOMIC_64BIT)
13668             static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
13669             {
13670                 (void)order;
13671                 return (c89atomic_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src);
13672             }
13673         #else
13674         #endif
13675     #endif
13676     #if defined(C89ATOMIC_HAS_64) && !defined(C89ATOMIC_64BIT)
13677         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
13678         {
13679             c89atomic_uint64 oldValue;
13680             c89atomic_uint64 newValue;
13681             do {
13682                 oldValue = *dst;
13683                 newValue = oldValue + src;
13684             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
13685             (void)order;
13686             return oldValue;
13687         }
13688     #endif
13689     #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
13690         static C89ATOMIC_INLINE void __stdcall c89atomic_thread_fence(c89atomic_memory_order order)
13691         {
13692             (void)order;
13693             __asm {
13694                 lock add [esp], 0
13695             }
13696         }
13697     #else
13698         #if defined(C89ATOMIC_X64)
13699             #define c89atomic_thread_fence(order)   __faststorefence(), (void)order
13700         #else
13701             static C89ATOMIC_INLINE void c89atomic_thread_fence(c89atomic_memory_order order)
13702             {
13703                 volatile c89atomic_uint32 barrier = 0;
13704                 c89atomic_fetch_add_explicit_32(&barrier, 0, order);
13705             }
13706         #endif
13707     #endif
13708     #define c89atomic_compiler_fence()      c89atomic_thread_fence(c89atomic_memory_order_seq_cst)
13709     #define c89atomic_signal_fence(order)   c89atomic_thread_fence(order)
13710     #if defined(C89ATOMIC_HAS_8)
13711         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order)
13712         {
13713             (void)order;
13714             return c89atomic_compare_and_swap_8((volatile c89atomic_uint8*)ptr, 0, 0);
13715         }
13716     #endif
13717     #if defined(C89ATOMIC_HAS_16)
13718         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order)
13719         {
13720             (void)order;
13721             return c89atomic_compare_and_swap_16((volatile c89atomic_uint16*)ptr, 0, 0);
13722         }
13723     #endif
13724     #if defined(C89ATOMIC_HAS_32)
13725         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order)
13726         {
13727             (void)order;
13728             return c89atomic_compare_and_swap_32((volatile c89atomic_uint32*)ptr, 0, 0);
13729         }
13730     #endif
13731     #if defined(C89ATOMIC_HAS_64)
13732         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order)
13733         {
13734             (void)order;
13735             return c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)ptr, 0, 0);
13736         }
13737     #endif
13738     #if defined(C89ATOMIC_HAS_8)
13739         #define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order)
13740     #endif
13741     #if defined(C89ATOMIC_HAS_16)
13742         #define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order)
13743     #endif
13744     #if defined(C89ATOMIC_HAS_32)
13745         #define c89atomic_store_explicit_32(dst, src, order) (void)c89atomic_exchange_explicit_32(dst, src, order)
13746     #endif
13747     #if defined(C89ATOMIC_HAS_64)
13748         #define c89atomic_store_explicit_64(dst, src, order) (void)c89atomic_exchange_explicit_64(dst, src, order)
13749     #endif
13750     #if defined(C89ATOMIC_HAS_8)
13751         static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
13752         {
13753             c89atomic_uint8 oldValue;
13754             c89atomic_uint8 newValue;
13755             do {
13756                 oldValue = *dst;
13757                 newValue = (c89atomic_uint8)(oldValue - src);
13758             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
13759             (void)order;
13760             return oldValue;
13761         }
13762     #endif
13763     #if defined(C89ATOMIC_HAS_16)
13764         static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
13765         {
13766             c89atomic_uint16 oldValue;
13767             c89atomic_uint16 newValue;
13768             do {
13769                 oldValue = *dst;
13770                 newValue = (c89atomic_uint16)(oldValue - src);
13771             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
13772             (void)order;
13773             return oldValue;
13774         }
13775     #endif
13776     #if defined(C89ATOMIC_HAS_32)
13777         static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
13778         {
13779             c89atomic_uint32 oldValue;
13780             c89atomic_uint32 newValue;
13781             do {
13782                 oldValue = *dst;
13783                 newValue = oldValue - src;
13784             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
13785             (void)order;
13786             return oldValue;
13787         }
13788     #endif
13789     #if defined(C89ATOMIC_HAS_64)
13790         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
13791         {
13792             c89atomic_uint64 oldValue;
13793             c89atomic_uint64 newValue;
13794             do {
13795                 oldValue = *dst;
13796                 newValue = oldValue - src;
13797             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
13798             (void)order;
13799             return oldValue;
13800         }
13801     #endif
13802     #if defined(C89ATOMIC_HAS_8)
13803         static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
13804         {
13805             c89atomic_uint8 oldValue;
13806             c89atomic_uint8 newValue;
13807             do {
13808                 oldValue = *dst;
13809                 newValue = (c89atomic_uint8)(oldValue & src);
13810             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
13811             (void)order;
13812             return oldValue;
13813         }
13814     #endif
13815     #if defined(C89ATOMIC_HAS_16)
13816         static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
13817         {
13818             c89atomic_uint16 oldValue;
13819             c89atomic_uint16 newValue;
13820             do {
13821                 oldValue = *dst;
13822                 newValue = (c89atomic_uint16)(oldValue & src);
13823             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
13824             (void)order;
13825             return oldValue;
13826         }
13827     #endif
13828     #if defined(C89ATOMIC_HAS_32)
13829         static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
13830         {
13831             c89atomic_uint32 oldValue;
13832             c89atomic_uint32 newValue;
13833             do {
13834                 oldValue = *dst;
13835                 newValue = oldValue & src;
13836             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
13837             (void)order;
13838             return oldValue;
13839         }
13840     #endif
13841     #if defined(C89ATOMIC_HAS_64)
13842         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
13843         {
13844             c89atomic_uint64 oldValue;
13845             c89atomic_uint64 newValue;
13846             do {
13847                 oldValue = *dst;
13848                 newValue = oldValue & src;
13849             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
13850             (void)order;
13851             return oldValue;
13852         }
13853     #endif
13854     #if defined(C89ATOMIC_HAS_8)
13855         static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
13856         {
13857             c89atomic_uint8 oldValue;
13858             c89atomic_uint8 newValue;
13859             do {
13860                 oldValue = *dst;
13861                 newValue = (c89atomic_uint8)(oldValue ^ src);
13862             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
13863             (void)order;
13864             return oldValue;
13865         }
13866     #endif
13867     #if defined(C89ATOMIC_HAS_16)
13868         static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
13869         {
13870             c89atomic_uint16 oldValue;
13871             c89atomic_uint16 newValue;
13872             do {
13873                 oldValue = *dst;
13874                 newValue = (c89atomic_uint16)(oldValue ^ src);
13875             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
13876             (void)order;
13877             return oldValue;
13878         }
13879     #endif
13880     #if defined(C89ATOMIC_HAS_32)
13881         static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
13882         {
13883             c89atomic_uint32 oldValue;
13884             c89atomic_uint32 newValue;
13885             do {
13886                 oldValue = *dst;
13887                 newValue = oldValue ^ src;
13888             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
13889             (void)order;
13890             return oldValue;
13891         }
13892     #endif
13893     #if defined(C89ATOMIC_HAS_64)
13894         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
13895         {
13896             c89atomic_uint64 oldValue;
13897             c89atomic_uint64 newValue;
13898             do {
13899                 oldValue = *dst;
13900                 newValue = oldValue ^ src;
13901             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
13902             (void)order;
13903             return oldValue;
13904         }
13905     #endif
13906     #if defined(C89ATOMIC_HAS_8)
13907         static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
13908         {
13909             c89atomic_uint8 oldValue;
13910             c89atomic_uint8 newValue;
13911             do {
13912                 oldValue = *dst;
13913                 newValue = (c89atomic_uint8)(oldValue | src);
13914             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
13915             (void)order;
13916             return oldValue;
13917         }
13918     #endif
13919     #if defined(C89ATOMIC_HAS_16)
13920         static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
13921         {
13922             c89atomic_uint16 oldValue;
13923             c89atomic_uint16 newValue;
13924             do {
13925                 oldValue = *dst;
13926                 newValue = (c89atomic_uint16)(oldValue | src);
13927             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
13928             (void)order;
13929             return oldValue;
13930         }
13931     #endif
13932     #if defined(C89ATOMIC_HAS_32)
13933         static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
13934         {
13935             c89atomic_uint32 oldValue;
13936             c89atomic_uint32 newValue;
13937             do {
13938                 oldValue = *dst;
13939                 newValue = oldValue | src;
13940             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
13941             (void)order;
13942             return oldValue;
13943         }
13944     #endif
13945     #if defined(C89ATOMIC_HAS_64)
13946         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
13947         {
13948             c89atomic_uint64 oldValue;
13949             c89atomic_uint64 newValue;
13950             do {
13951                 oldValue = *dst;
13952                 newValue = oldValue | src;
13953             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
13954             (void)order;
13955             return oldValue;
13956         }
13957     #endif
13958     #if defined(C89ATOMIC_HAS_8)
13959         #define c89atomic_test_and_set_explicit_8( dst, order) c89atomic_exchange_explicit_8 (dst, 1, order)
13960     #endif
13961     #if defined(C89ATOMIC_HAS_16)
13962         #define c89atomic_test_and_set_explicit_16(dst, order) c89atomic_exchange_explicit_16(dst, 1, order)
13963     #endif
13964     #if defined(C89ATOMIC_HAS_32)
13965         #define c89atomic_test_and_set_explicit_32(dst, order) c89atomic_exchange_explicit_32(dst, 1, order)
13966     #endif
13967     #if defined(C89ATOMIC_HAS_64)
13968         #define c89atomic_test_and_set_explicit_64(dst, order) c89atomic_exchange_explicit_64(dst, 1, order)
13969     #endif
13970     #if defined(C89ATOMIC_HAS_8)
13971         #define c89atomic_clear_explicit_8( dst, order) c89atomic_store_explicit_8 (dst, 0, order)
13972     #endif
13973     #if defined(C89ATOMIC_HAS_16)
13974         #define c89atomic_clear_explicit_16(dst, order) c89atomic_store_explicit_16(dst, 0, order)
13975     #endif
13976     #if defined(C89ATOMIC_HAS_32)
13977         #define c89atomic_clear_explicit_32(dst, order) c89atomic_store_explicit_32(dst, 0, order)
13978     #endif
13979     #if defined(C89ATOMIC_HAS_64)
13980         #define c89atomic_clear_explicit_64(dst, order) c89atomic_store_explicit_64(dst, 0, order)
13981     #endif
13982     #if defined(C89ATOMIC_HAS_8)
13983         typedef c89atomic_uint8 c89atomic_flag;
13984         #define c89atomic_flag_test_and_set_explicit(ptr, order)    (c89atomic_bool)c89atomic_test_and_set_explicit_8(ptr, order)
13985         #define c89atomic_flag_clear_explicit(ptr, order)           c89atomic_clear_explicit_8(ptr, order)
13986         #define c89atoimc_flag_load_explicit(ptr, order)            c89atomic_load_explicit_8(ptr, order)
13987     #else
13988         typedef c89atomic_uint32 c89atomic_flag;
13989         #define c89atomic_flag_test_and_set_explicit(ptr, order)    (c89atomic_bool)c89atomic_test_and_set_explicit_32(ptr, order)
13990         #define c89atomic_flag_clear_explicit(ptr, order)           c89atomic_clear_explicit_32(ptr, order)
13991         #define c89atoimc_flag_load_explicit(ptr, order)            c89atomic_load_explicit_32(ptr, order)
13992     #endif
13993 #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))
13994     #define C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE
13995     #define C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE
13996     #define c89atomic_memory_order_relaxed                          __ATOMIC_RELAXED
13997     #define c89atomic_memory_order_consume                          __ATOMIC_CONSUME
13998     #define c89atomic_memory_order_acquire                          __ATOMIC_ACQUIRE
13999     #define c89atomic_memory_order_release                          __ATOMIC_RELEASE
14000     #define c89atomic_memory_order_acq_rel                          __ATOMIC_ACQ_REL
14001     #define c89atomic_memory_order_seq_cst                          __ATOMIC_SEQ_CST
14002     #define c89atomic_compiler_fence()                              __asm__ __volatile__("":::"memory")
14003     #define c89atomic_thread_fence(order)                           __atomic_thread_fence(order)
14004     #define c89atomic_signal_fence(order)                           __atomic_signal_fence(order)
14005     #define c89atomic_is_lock_free_8(ptr)                           __atomic_is_lock_free(1, ptr)
14006     #define c89atomic_is_lock_free_16(ptr)                          __atomic_is_lock_free(2, ptr)
14007     #define c89atomic_is_lock_free_32(ptr)                          __atomic_is_lock_free(4, ptr)
14008     #define c89atomic_is_lock_free_64(ptr)                          __atomic_is_lock_free(8, ptr)
14009     #define c89atomic_test_and_set_explicit_8( dst, order)          __atomic_exchange_n(dst, 1, order)
14010     #define c89atomic_test_and_set_explicit_16(dst, order)          __atomic_exchange_n(dst, 1, order)
14011     #define c89atomic_test_and_set_explicit_32(dst, order)          __atomic_exchange_n(dst, 1, order)
14012     #define c89atomic_test_and_set_explicit_64(dst, order)          __atomic_exchange_n(dst, 1, order)
14013     #define c89atomic_clear_explicit_8( dst, order)                 __atomic_store_n(dst, 0, order)
14014     #define c89atomic_clear_explicit_16(dst, order)                 __atomic_store_n(dst, 0, order)
14015     #define c89atomic_clear_explicit_32(dst, order)                 __atomic_store_n(dst, 0, order)
14016     #define c89atomic_clear_explicit_64(dst, order)                 __atomic_store_n(dst, 0, order)
14017     #define c89atomic_store_explicit_8( dst, src, order)            __atomic_store_n(dst, src, order)
14018     #define c89atomic_store_explicit_16(dst, src, order)            __atomic_store_n(dst, src, order)
14019     #define c89atomic_store_explicit_32(dst, src, order)            __atomic_store_n(dst, src, order)
14020     #define c89atomic_store_explicit_64(dst, src, order)            __atomic_store_n(dst, src, order)
14021     #define c89atomic_load_explicit_8( dst, order)                  __atomic_load_n(dst, order)
14022     #define c89atomic_load_explicit_16(dst, order)                  __atomic_load_n(dst, order)
14023     #define c89atomic_load_explicit_32(dst, order)                  __atomic_load_n(dst, order)
14024     #define c89atomic_load_explicit_64(dst, order)                  __atomic_load_n(dst, order)
14025     #define c89atomic_exchange_explicit_8( dst, src, order)         __atomic_exchange_n(dst, src, order)
14026     #define c89atomic_exchange_explicit_16(dst, src, order)         __atomic_exchange_n(dst, src, order)
14027     #define c89atomic_exchange_explicit_32(dst, src, order)         __atomic_exchange_n(dst, src, order)
14028     #define c89atomic_exchange_explicit_64(dst, src, order)         __atomic_exchange_n(dst, src, order)
14029     #define c89atomic_compare_exchange_strong_explicit_8( dst, expected, desired, successOrder, failureOrder)   __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
14030     #define c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder)   __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
14031     #define c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder)   __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
14032     #define c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder)   __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
14033     #define c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder)     __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
14034     #define c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder)     __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
14035     #define c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder)     __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
14036     #define c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder)     __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
14037     #define c89atomic_fetch_add_explicit_8( dst, src, order)        __atomic_fetch_add(dst, src, order)
14038     #define c89atomic_fetch_add_explicit_16(dst, src, order)        __atomic_fetch_add(dst, src, order)
14039     #define c89atomic_fetch_add_explicit_32(dst, src, order)        __atomic_fetch_add(dst, src, order)
14040     #define c89atomic_fetch_add_explicit_64(dst, src, order)        __atomic_fetch_add(dst, src, order)
14041     #define c89atomic_fetch_sub_explicit_8( dst, src, order)        __atomic_fetch_sub(dst, src, order)
14042     #define c89atomic_fetch_sub_explicit_16(dst, src, order)        __atomic_fetch_sub(dst, src, order)
14043     #define c89atomic_fetch_sub_explicit_32(dst, src, order)        __atomic_fetch_sub(dst, src, order)
14044     #define c89atomic_fetch_sub_explicit_64(dst, src, order)        __atomic_fetch_sub(dst, src, order)
14045     #define c89atomic_fetch_or_explicit_8( dst, src, order)         __atomic_fetch_or(dst, src, order)
14046     #define c89atomic_fetch_or_explicit_16(dst, src, order)         __atomic_fetch_or(dst, src, order)
14047     #define c89atomic_fetch_or_explicit_32(dst, src, order)         __atomic_fetch_or(dst, src, order)
14048     #define c89atomic_fetch_or_explicit_64(dst, src, order)         __atomic_fetch_or(dst, src, order)
14049     #define c89atomic_fetch_xor_explicit_8( dst, src, order)        __atomic_fetch_xor(dst, src, order)
14050     #define c89atomic_fetch_xor_explicit_16(dst, src, order)        __atomic_fetch_xor(dst, src, order)
14051     #define c89atomic_fetch_xor_explicit_32(dst, src, order)        __atomic_fetch_xor(dst, src, order)
14052     #define c89atomic_fetch_xor_explicit_64(dst, src, order)        __atomic_fetch_xor(dst, src, order)
14053     #define c89atomic_fetch_and_explicit_8( dst, src, order)        __atomic_fetch_and(dst, src, order)
14054     #define c89atomic_fetch_and_explicit_16(dst, src, order)        __atomic_fetch_and(dst, src, order)
14055     #define c89atomic_fetch_and_explicit_32(dst, src, order)        __atomic_fetch_and(dst, src, order)
14056     #define c89atomic_fetch_and_explicit_64(dst, src, order)        __atomic_fetch_and(dst, src, order)
14057     #define c89atomic_compare_and_swap_8 (dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
14058     #define c89atomic_compare_and_swap_16(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
14059     #define c89atomic_compare_and_swap_32(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
14060     #define c89atomic_compare_and_swap_64(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
14061     typedef c89atomic_uint8 c89atomic_flag;
14062     #define c89atomic_flag_test_and_set_explicit(dst, order)        (c89atomic_bool)__atomic_test_and_set(dst, order)
14063     #define c89atomic_flag_clear_explicit(dst, order)               __atomic_clear(dst, order)
14064     #define c89atoimc_flag_load_explicit(ptr, order)                c89atomic_load_explicit_8(ptr, order)
14065 #else
14066     #define c89atomic_memory_order_relaxed  1
14067     #define c89atomic_memory_order_consume  2
14068     #define c89atomic_memory_order_acquire  3
14069     #define c89atomic_memory_order_release  4
14070     #define c89atomic_memory_order_acq_rel  5
14071     #define c89atomic_memory_order_seq_cst  6
14072     #define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory")
14073     #if defined(__GNUC__)
14074         #define c89atomic_thread_fence(order) __sync_synchronize(), (void)order
14075         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14076         {
14077             if (order > c89atomic_memory_order_acquire) {
14078                 __sync_synchronize();
14079             }
14080             return __sync_lock_test_and_set(dst, src);
14081         }
14082         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14083         {
14084             c89atomic_uint16 oldValue;
14085             do {
14086                 oldValue = *dst;
14087             } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue);
14088             (void)order;
14089             return oldValue;
14090         }
14091         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14092         {
14093             c89atomic_uint32 oldValue;
14094             do {
14095                 oldValue = *dst;
14096             } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue);
14097             (void)order;
14098             return oldValue;
14099         }
14100         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14101         {
14102             c89atomic_uint64 oldValue;
14103             do {
14104                 oldValue = *dst;
14105             } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue);
14106             (void)order;
14107             return oldValue;
14108         }
14109         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14110         {
14111             (void)order;
14112             return __sync_fetch_and_add(dst, src);
14113         }
14114         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14115         {
14116             (void)order;
14117             return __sync_fetch_and_add(dst, src);
14118         }
14119         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14120         {
14121             (void)order;
14122             return __sync_fetch_and_add(dst, src);
14123         }
14124         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14125         {
14126             (void)order;
14127             return __sync_fetch_and_add(dst, src);
14128         }
14129         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14130         {
14131             (void)order;
14132             return __sync_fetch_and_sub(dst, src);
14133         }
14134         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14135         {
14136             (void)order;
14137             return __sync_fetch_and_sub(dst, src);
14138         }
14139         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14140         {
14141             (void)order;
14142             return __sync_fetch_and_sub(dst, src);
14143         }
14144         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14145         {
14146             (void)order;
14147             return __sync_fetch_and_sub(dst, src);
14148         }
14149         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14150         {
14151             (void)order;
14152             return __sync_fetch_and_or(dst, src);
14153         }
14154         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14155         {
14156             (void)order;
14157             return __sync_fetch_and_or(dst, src);
14158         }
14159         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14160         {
14161             (void)order;
14162             return __sync_fetch_and_or(dst, src);
14163         }
14164         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14165         {
14166             (void)order;
14167             return __sync_fetch_and_or(dst, src);
14168         }
14169         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14170         {
14171             (void)order;
14172             return __sync_fetch_and_xor(dst, src);
14173         }
14174         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14175         {
14176             (void)order;
14177             return __sync_fetch_and_xor(dst, src);
14178         }
14179         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14180         {
14181             (void)order;
14182             return __sync_fetch_and_xor(dst, src);
14183         }
14184         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14185         {
14186             (void)order;
14187             return __sync_fetch_and_xor(dst, src);
14188         }
14189         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14190         {
14191             (void)order;
14192             return __sync_fetch_and_and(dst, src);
14193         }
14194         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14195         {
14196             (void)order;
14197             return __sync_fetch_and_and(dst, src);
14198         }
14199         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14200         {
14201             (void)order;
14202             return __sync_fetch_and_and(dst, src);
14203         }
14204         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14205         {
14206             (void)order;
14207             return __sync_fetch_and_and(dst, src);
14208         }
14209         #define c89atomic_compare_and_swap_8( dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
14210         #define c89atomic_compare_and_swap_16(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
14211         #define c89atomic_compare_and_swap_32(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
14212         #define c89atomic_compare_and_swap_64(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
14213     #else
14214         #if defined(C89ATOMIC_X86)
14215             #define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory", "cc")
14216         #elif defined(C89ATOMIC_X64)
14217             #define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory", "cc")
14218         #else
14219             #error Unsupported architecture. Please submit a feature request.
14220         #endif
14221         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 desired)
14222         {
14223             c89atomic_uint8 result;
14224         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
14225             __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc");
14226         #else
14227             #error Unsupported architecture. Please submit a feature request.
14228         #endif
14229             return result;
14230         }
14231         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 desired)
14232         {
14233             c89atomic_uint16 result;
14234         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
14235             __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc");
14236         #else
14237             #error Unsupported architecture. Please submit a feature request.
14238         #endif
14239             return result;
14240         }
14241         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 desired)
14242         {
14243             c89atomic_uint32 result;
14244         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
14245             __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc");
14246         #else
14247             #error Unsupported architecture. Please submit a feature request.
14248         #endif
14249             return result;
14250         }
14251         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 desired)
14252         {
14253             volatile c89atomic_uint64 result;
14254         #if defined(C89ATOMIC_X86)
14255             c89atomic_uint32 resultEAX;
14256             c89atomic_uint32 resultEDX;
14257             __asm__ __volatile__("push %%ebx; xchg %5, %%ebx; lock; cmpxchg8b %0; pop %%ebx" : "+m"(*dst), "=a"(resultEAX), "=d"(resultEDX) : "a"(expected & 0xFFFFFFFF), "d"(expected >> 32), "r"(desired & 0xFFFFFFFF), "c"(desired >> 32) : "cc");
14258             result = ((c89atomic_uint64)resultEDX << 32) | resultEAX;
14259         #elif defined(C89ATOMIC_X64)
14260             __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc");
14261         #else
14262             #error Unsupported architecture. Please submit a feature request.
14263         #endif
14264             return result;
14265         }
14266         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14267         {
14268             c89atomic_uint8 result = 0;
14269             (void)order;
14270         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
14271             __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src));
14272         #else
14273             #error Unsupported architecture. Please submit a feature request.
14274         #endif
14275             return result;
14276         }
14277         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14278         {
14279             c89atomic_uint16 result = 0;
14280             (void)order;
14281         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
14282             __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src));
14283         #else
14284             #error Unsupported architecture. Please submit a feature request.
14285         #endif
14286             return result;
14287         }
14288         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14289         {
14290             c89atomic_uint32 result;
14291             (void)order;
14292         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
14293             __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src));
14294         #else
14295             #error Unsupported architecture. Please submit a feature request.
14296         #endif
14297             return result;
14298         }
14299         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14300         {
14301             c89atomic_uint64 result;
14302             (void)order;
14303         #if defined(C89ATOMIC_X86)
14304             do {
14305                 result = *dst;
14306             } while (c89atomic_compare_and_swap_64(dst, result, src) != result);
14307         #elif defined(C89ATOMIC_X64)
14308             __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src));
14309         #else
14310             #error Unsupported architecture. Please submit a feature request.
14311         #endif
14312             return result;
14313         }
14314         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14315         {
14316             c89atomic_uint8 result;
14317             (void)order;
14318         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
14319             __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc");
14320         #else
14321             #error Unsupported architecture. Please submit a feature request.
14322         #endif
14323             return result;
14324         }
14325         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14326         {
14327             c89atomic_uint16 result;
14328             (void)order;
14329         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
14330             __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc");
14331         #else
14332             #error Unsupported architecture. Please submit a feature request.
14333         #endif
14334             return result;
14335         }
14336         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14337         {
14338             c89atomic_uint32 result;
14339             (void)order;
14340         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
14341             __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc");
14342         #else
14343             #error Unsupported architecture. Please submit a feature request.
14344         #endif
14345             return result;
14346         }
14347         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14348         {
14349         #if defined(C89ATOMIC_X86)
14350             c89atomic_uint64 oldValue;
14351             c89atomic_uint64 newValue;
14352             (void)order;
14353             do {
14354                 oldValue = *dst;
14355                 newValue = oldValue + src;
14356             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
14357             return oldValue;
14358         #elif defined(C89ATOMIC_X64)
14359             c89atomic_uint64 result;
14360             (void)order;
14361             __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc");
14362             return result;
14363         #endif
14364         }
14365         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14366         {
14367             c89atomic_uint8 oldValue;
14368             c89atomic_uint8 newValue;
14369             do {
14370                 oldValue = *dst;
14371                 newValue = (c89atomic_uint8)(oldValue - src);
14372             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
14373             (void)order;
14374             return oldValue;
14375         }
14376         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14377         {
14378             c89atomic_uint16 oldValue;
14379             c89atomic_uint16 newValue;
14380             do {
14381                 oldValue = *dst;
14382                 newValue = (c89atomic_uint16)(oldValue - src);
14383             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
14384             (void)order;
14385             return oldValue;
14386         }
14387         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14388         {
14389             c89atomic_uint32 oldValue;
14390             c89atomic_uint32 newValue;
14391             do {
14392                 oldValue = *dst;
14393                 newValue = oldValue - src;
14394             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
14395             (void)order;
14396             return oldValue;
14397         }
14398         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14399         {
14400             c89atomic_uint64 oldValue;
14401             c89atomic_uint64 newValue;
14402             do {
14403                 oldValue = *dst;
14404                 newValue = oldValue - src;
14405             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
14406             (void)order;
14407             return oldValue;
14408         }
14409         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14410         {
14411             c89atomic_uint8 oldValue;
14412             c89atomic_uint8 newValue;
14413             do {
14414                 oldValue = *dst;
14415                 newValue = (c89atomic_uint8)(oldValue & src);
14416             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
14417             (void)order;
14418             return oldValue;
14419         }
14420         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14421         {
14422             c89atomic_uint16 oldValue;
14423             c89atomic_uint16 newValue;
14424             do {
14425                 oldValue = *dst;
14426                 newValue = (c89atomic_uint16)(oldValue & src);
14427             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
14428             (void)order;
14429             return oldValue;
14430         }
14431         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14432         {
14433             c89atomic_uint32 oldValue;
14434             c89atomic_uint32 newValue;
14435             do {
14436                 oldValue = *dst;
14437                 newValue = oldValue & src;
14438             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
14439             (void)order;
14440             return oldValue;
14441         }
14442         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14443         {
14444             c89atomic_uint64 oldValue;
14445             c89atomic_uint64 newValue;
14446             do {
14447                 oldValue = *dst;
14448                 newValue = oldValue & src;
14449             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
14450             (void)order;
14451             return oldValue;
14452         }
14453         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14454         {
14455             c89atomic_uint8 oldValue;
14456             c89atomic_uint8 newValue;
14457             do {
14458                 oldValue = *dst;
14459                 newValue = (c89atomic_uint8)(oldValue ^ src);
14460             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
14461             (void)order;
14462             return oldValue;
14463         }
14464         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14465         {
14466             c89atomic_uint16 oldValue;
14467             c89atomic_uint16 newValue;
14468             do {
14469                 oldValue = *dst;
14470                 newValue = (c89atomic_uint16)(oldValue ^ src);
14471             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
14472             (void)order;
14473             return oldValue;
14474         }
14475         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14476         {
14477             c89atomic_uint32 oldValue;
14478             c89atomic_uint32 newValue;
14479             do {
14480                 oldValue = *dst;
14481                 newValue = oldValue ^ src;
14482             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
14483             (void)order;
14484             return oldValue;
14485         }
14486         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14487         {
14488             c89atomic_uint64 oldValue;
14489             c89atomic_uint64 newValue;
14490             do {
14491                 oldValue = *dst;
14492                 newValue = oldValue ^ src;
14493             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
14494             (void)order;
14495             return oldValue;
14496         }
14497         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
14498         {
14499             c89atomic_uint8 oldValue;
14500             c89atomic_uint8 newValue;
14501             do {
14502                 oldValue = *dst;
14503                 newValue = (c89atomic_uint8)(oldValue | src);
14504             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
14505             (void)order;
14506             return oldValue;
14507         }
14508         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
14509         {
14510             c89atomic_uint16 oldValue;
14511             c89atomic_uint16 newValue;
14512             do {
14513                 oldValue = *dst;
14514                 newValue = (c89atomic_uint16)(oldValue | src);
14515             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
14516             (void)order;
14517             return oldValue;
14518         }
14519         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
14520         {
14521             c89atomic_uint32 oldValue;
14522             c89atomic_uint32 newValue;
14523             do {
14524                 oldValue = *dst;
14525                 newValue = oldValue | src;
14526             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
14527             (void)order;
14528             return oldValue;
14529         }
14530         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
14531         {
14532             c89atomic_uint64 oldValue;
14533             c89atomic_uint64 newValue;
14534             do {
14535                 oldValue = *dst;
14536                 newValue = oldValue | src;
14537             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
14538             (void)order;
14539             return oldValue;
14540         }
14541     #endif
14542     #define c89atomic_signal_fence(order)                           c89atomic_thread_fence(order)
14543     static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order)
14544     {
14545         (void)order;
14546         return c89atomic_compare_and_swap_8((c89atomic_uint8*)ptr, 0, 0);
14547     }
14548     static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order)
14549     {
14550         (void)order;
14551         return c89atomic_compare_and_swap_16((c89atomic_uint16*)ptr, 0, 0);
14552     }
14553     static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order)
14554     {
14555         (void)order;
14556         return c89atomic_compare_and_swap_32((c89atomic_uint32*)ptr, 0, 0);
14557     }
14558     static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order)
14559     {
14560         (void)order;
14561         return c89atomic_compare_and_swap_64((c89atomic_uint64*)ptr, 0, 0);
14562     }
14563     #define c89atomic_store_explicit_8( dst, src, order)            (void)c89atomic_exchange_explicit_8 (dst, src, order)
14564     #define c89atomic_store_explicit_16(dst, src, order)            (void)c89atomic_exchange_explicit_16(dst, src, order)
14565     #define c89atomic_store_explicit_32(dst, src, order)            (void)c89atomic_exchange_explicit_32(dst, src, order)
14566     #define c89atomic_store_explicit_64(dst, src, order)            (void)c89atomic_exchange_explicit_64(dst, src, order)
14567     #define c89atomic_test_and_set_explicit_8( dst, order)          c89atomic_exchange_explicit_8 (dst, 1, order)
14568     #define c89atomic_test_and_set_explicit_16(dst, order)          c89atomic_exchange_explicit_16(dst, 1, order)
14569     #define c89atomic_test_and_set_explicit_32(dst, order)          c89atomic_exchange_explicit_32(dst, 1, order)
14570     #define c89atomic_test_and_set_explicit_64(dst, order)          c89atomic_exchange_explicit_64(dst, 1, order)
14571     #define c89atomic_clear_explicit_8( dst, order)                 c89atomic_store_explicit_8 (dst, 0, order)
14572     #define c89atomic_clear_explicit_16(dst, order)                 c89atomic_store_explicit_16(dst, 0, order)
14573     #define c89atomic_clear_explicit_32(dst, order)                 c89atomic_store_explicit_32(dst, 0, order)
14574     #define c89atomic_clear_explicit_64(dst, order)                 c89atomic_store_explicit_64(dst, 0, order)
14575     typedef c89atomic_uint8 c89atomic_flag;
14576     #define c89atomic_flag_test_and_set_explicit(ptr, order)        (c89atomic_bool)c89atomic_test_and_set_explicit_8(ptr, order)
14577     #define c89atomic_flag_clear_explicit(ptr, order)               c89atomic_clear_explicit_8(ptr, order)
14578     #define c89atoimc_flag_load_explicit(ptr, order)                c89atomic_load_explicit_8(ptr, order)
14579 #endif
14580 #if !defined(C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE)
14581     #if defined(C89ATOMIC_HAS_8)
14582         c89atomic_bool c89atomic_compare_exchange_strong_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8* expected, c89atomic_uint8 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
14583         {
14584             c89atomic_uint8 expectedValue;
14585             c89atomic_uint8 result;
14586             (void)successOrder;
14587             (void)failureOrder;
14588             expectedValue = c89atomic_load_explicit_8(expected, c89atomic_memory_order_seq_cst);
14589             result = c89atomic_compare_and_swap_8(dst, expectedValue, desired);
14590             if (result == expectedValue) {
14591                 return 1;
14592             } else {
14593                 c89atomic_store_explicit_8(expected, result, failureOrder);
14594                 return 0;
14595             }
14596         }
14597     #endif
14598     #if defined(C89ATOMIC_HAS_16)
14599         c89atomic_bool c89atomic_compare_exchange_strong_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16* expected, c89atomic_uint16 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
14600         {
14601             c89atomic_uint16 expectedValue;
14602             c89atomic_uint16 result;
14603             (void)successOrder;
14604             (void)failureOrder;
14605             expectedValue = c89atomic_load_explicit_16(expected, c89atomic_memory_order_seq_cst);
14606             result = c89atomic_compare_and_swap_16(dst, expectedValue, desired);
14607             if (result == expectedValue) {
14608                 return 1;
14609             } else {
14610                 c89atomic_store_explicit_16(expected, result, failureOrder);
14611                 return 0;
14612             }
14613         }
14614     #endif
14615     #if defined(C89ATOMIC_HAS_32)
14616         c89atomic_bool c89atomic_compare_exchange_strong_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32* expected, c89atomic_uint32 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
14617         {
14618             c89atomic_uint32 expectedValue;
14619             c89atomic_uint32 result;
14620             (void)successOrder;
14621             (void)failureOrder;
14622             expectedValue = c89atomic_load_explicit_32(expected, c89atomic_memory_order_seq_cst);
14623             result = c89atomic_compare_and_swap_32(dst, expectedValue, desired);
14624             if (result == expectedValue) {
14625                 return 1;
14626             } else {
14627                 c89atomic_store_explicit_32(expected, result, failureOrder);
14628                 return 0;
14629             }
14630         }
14631     #endif
14632     #if defined(C89ATOMIC_HAS_64)
14633         c89atomic_bool c89atomic_compare_exchange_strong_explicit_64(volatile c89atomic_uint64* dst, volatile c89atomic_uint64* expected, c89atomic_uint64 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
14634         {
14635             c89atomic_uint64 expectedValue;
14636             c89atomic_uint64 result;
14637             (void)successOrder;
14638             (void)failureOrder;
14639             expectedValue = c89atomic_load_explicit_64(expected, c89atomic_memory_order_seq_cst);
14640             result = c89atomic_compare_and_swap_64(dst, expectedValue, desired);
14641             if (result == expectedValue) {
14642                 return 1;
14643             } else {
14644                 c89atomic_store_explicit_64(expected, result, failureOrder);
14645                 return 0;
14646             }
14647         }
14648     #endif
14649     #define c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_8 (dst, expected, desired, successOrder, failureOrder)
14650     #define c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder)
14651     #define c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder)
14652     #define c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder)
14653 #endif
14654 #if !defined(C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE)
14655     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_8(volatile void* ptr)
14656     {
14657         (void)ptr;
14658         return 1;
14659     }
14660     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_16(volatile void* ptr)
14661     {
14662         (void)ptr;
14663         return 1;
14664     }
14665     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_32(volatile void* ptr)
14666     {
14667         (void)ptr;
14668         return 1;
14669     }
14670     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_64(volatile void* ptr)
14671     {
14672         (void)ptr;
14673     #if defined(C89ATOMIC_64BIT)
14674         return 1;
14675     #else
14676         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
14677             return 1;
14678         #else
14679             return 0;
14680         #endif
14681     #endif
14682     }
14683 #endif
14684 #if defined(C89ATOMIC_64BIT)
14685     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_ptr(volatile void** ptr)
14686     {
14687         return c89atomic_is_lock_free_64((volatile c89atomic_uint64*)ptr);
14688     }
14689     static C89ATOMIC_INLINE void* c89atomic_load_explicit_ptr(volatile void** ptr, c89atomic_memory_order order)
14690     {
14691         return (void*)c89atomic_load_explicit_64((volatile c89atomic_uint64*)ptr, order);
14692     }
14693     static C89ATOMIC_INLINE void c89atomic_store_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
14694     {
14695         c89atomic_store_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)src, order);
14696     }
14697     static C89ATOMIC_INLINE void* c89atomic_exchange_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
14698     {
14699         return (void*)c89atomic_exchange_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)src, order);
14700     }
14701     static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
14702     {
14703         return c89atomic_compare_exchange_strong_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder);
14704     }
14705     static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
14706     {
14707         return c89atomic_compare_exchange_weak_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder);
14708     }
14709     static C89ATOMIC_INLINE void* c89atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired)
14710     {
14711         return (void*)c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)expected, (c89atomic_uint64)desired);
14712     }
14713 #elif defined(C89ATOMIC_32BIT)
14714     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_ptr(volatile void** ptr)
14715     {
14716         return c89atomic_is_lock_free_32((volatile c89atomic_uint32*)ptr);
14717     }
14718     static C89ATOMIC_INLINE void* c89atomic_load_explicit_ptr(volatile void** ptr, c89atomic_memory_order order)
14719     {
14720         return (void*)c89atomic_load_explicit_32((volatile c89atomic_uint32*)ptr, order);
14721     }
14722     static C89ATOMIC_INLINE void c89atomic_store_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
14723     {
14724         c89atomic_store_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)src, order);
14725     }
14726     static C89ATOMIC_INLINE void* c89atomic_exchange_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
14727     {
14728         return (void*)c89atomic_exchange_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)src, order);
14729     }
14730     static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_strong_explicit_ptr(volatile void** dst, void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
14731     {
14732         return c89atomic_compare_exchange_strong_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder);
14733     }
14734     static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
14735     {
14736         return c89atomic_compare_exchange_weak_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder);
14737     }
14738     static C89ATOMIC_INLINE void* c89atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired)
14739     {
14740         return (void*)c89atomic_compare_and_swap_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)expected, (c89atomic_uint32)desired);
14741     }
14742 #else
14743     #error Unsupported architecture.
14744 #endif
14745 #define c89atomic_flag_test_and_set(ptr)                                c89atomic_flag_test_and_set_explicit(ptr, c89atomic_memory_order_seq_cst)
14746 #define c89atomic_flag_clear(ptr)                                       c89atomic_flag_clear_explicit(ptr, c89atomic_memory_order_seq_cst)
14747 #define c89atomic_store_ptr(dst, src)                                   c89atomic_store_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst)
14748 #define c89atomic_load_ptr(ptr)                                         c89atomic_load_explicit_ptr((volatile void**)ptr, c89atomic_memory_order_seq_cst)
14749 #define c89atomic_exchange_ptr(dst, src)                                c89atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst)
14750 #define c89atomic_compare_exchange_strong_ptr(dst, expected, desired)   c89atomic_compare_exchange_strong_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14751 #define c89atomic_compare_exchange_weak_ptr(dst, expected, desired)     c89atomic_compare_exchange_weak_explicit_ptr((volatile void**)dst, (void**)expected, (void*)desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14752 #define c89atomic_test_and_set_8( ptr)                                  c89atomic_test_and_set_explicit_8( ptr, c89atomic_memory_order_seq_cst)
14753 #define c89atomic_test_and_set_16(ptr)                                  c89atomic_test_and_set_explicit_16(ptr, c89atomic_memory_order_seq_cst)
14754 #define c89atomic_test_and_set_32(ptr)                                  c89atomic_test_and_set_explicit_32(ptr, c89atomic_memory_order_seq_cst)
14755 #define c89atomic_test_and_set_64(ptr)                                  c89atomic_test_and_set_explicit_64(ptr, c89atomic_memory_order_seq_cst)
14756 #define c89atomic_clear_8( ptr)                                         c89atomic_clear_explicit_8( ptr, c89atomic_memory_order_seq_cst)
14757 #define c89atomic_clear_16(ptr)                                         c89atomic_clear_explicit_16(ptr, c89atomic_memory_order_seq_cst)
14758 #define c89atomic_clear_32(ptr)                                         c89atomic_clear_explicit_32(ptr, c89atomic_memory_order_seq_cst)
14759 #define c89atomic_clear_64(ptr)                                         c89atomic_clear_explicit_64(ptr, c89atomic_memory_order_seq_cst)
14760 #define c89atomic_store_8( dst, src)                                    c89atomic_store_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
14761 #define c89atomic_store_16(dst, src)                                    c89atomic_store_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
14762 #define c89atomic_store_32(dst, src)                                    c89atomic_store_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
14763 #define c89atomic_store_64(dst, src)                                    c89atomic_store_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
14764 #define c89atomic_load_8( ptr)                                          c89atomic_load_explicit_8( ptr, c89atomic_memory_order_seq_cst)
14765 #define c89atomic_load_16(ptr)                                          c89atomic_load_explicit_16(ptr, c89atomic_memory_order_seq_cst)
14766 #define c89atomic_load_32(ptr)                                          c89atomic_load_explicit_32(ptr, c89atomic_memory_order_seq_cst)
14767 #define c89atomic_load_64(ptr)                                          c89atomic_load_explicit_64(ptr, c89atomic_memory_order_seq_cst)
14768 #define c89atomic_exchange_8( dst, src)                                 c89atomic_exchange_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
14769 #define c89atomic_exchange_16(dst, src)                                 c89atomic_exchange_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
14770 #define c89atomic_exchange_32(dst, src)                                 c89atomic_exchange_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
14771 #define c89atomic_exchange_64(dst, src)                                 c89atomic_exchange_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
14772 #define c89atomic_compare_exchange_strong_8( dst, expected, desired)    c89atomic_compare_exchange_strong_explicit_8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14773 #define c89atomic_compare_exchange_strong_16(dst, expected, desired)    c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14774 #define c89atomic_compare_exchange_strong_32(dst, expected, desired)    c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14775 #define c89atomic_compare_exchange_strong_64(dst, expected, desired)    c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14776 #define c89atomic_compare_exchange_weak_8(  dst, expected, desired)     c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14777 #define c89atomic_compare_exchange_weak_16( dst, expected, desired)     c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14778 #define c89atomic_compare_exchange_weak_32( dst, expected, desired)     c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14779 #define c89atomic_compare_exchange_weak_64( dst, expected, desired)     c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14780 #define c89atomic_fetch_add_8( dst, src)                                c89atomic_fetch_add_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
14781 #define c89atomic_fetch_add_16(dst, src)                                c89atomic_fetch_add_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
14782 #define c89atomic_fetch_add_32(dst, src)                                c89atomic_fetch_add_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
14783 #define c89atomic_fetch_add_64(dst, src)                                c89atomic_fetch_add_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
14784 #define c89atomic_fetch_sub_8( dst, src)                                c89atomic_fetch_sub_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
14785 #define c89atomic_fetch_sub_16(dst, src)                                c89atomic_fetch_sub_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
14786 #define c89atomic_fetch_sub_32(dst, src)                                c89atomic_fetch_sub_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
14787 #define c89atomic_fetch_sub_64(dst, src)                                c89atomic_fetch_sub_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
14788 #define c89atomic_fetch_or_8( dst, src)                                 c89atomic_fetch_or_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
14789 #define c89atomic_fetch_or_16(dst, src)                                 c89atomic_fetch_or_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
14790 #define c89atomic_fetch_or_32(dst, src)                                 c89atomic_fetch_or_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
14791 #define c89atomic_fetch_or_64(dst, src)                                 c89atomic_fetch_or_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
14792 #define c89atomic_fetch_xor_8( dst, src)                                c89atomic_fetch_xor_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
14793 #define c89atomic_fetch_xor_16(dst, src)                                c89atomic_fetch_xor_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
14794 #define c89atomic_fetch_xor_32(dst, src)                                c89atomic_fetch_xor_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
14795 #define c89atomic_fetch_xor_64(dst, src)                                c89atomic_fetch_xor_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
14796 #define c89atomic_fetch_and_8( dst, src)                                c89atomic_fetch_and_explicit_8 (dst, src, c89atomic_memory_order_seq_cst)
14797 #define c89atomic_fetch_and_16(dst, src)                                c89atomic_fetch_and_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
14798 #define c89atomic_fetch_and_32(dst, src)                                c89atomic_fetch_and_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
14799 #define c89atomic_fetch_and_64(dst, src)                                c89atomic_fetch_and_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
14800 #define c89atomic_test_and_set_explicit_i8( ptr, order)                 (c89atomic_int8 )c89atomic_test_and_set_explicit_8( (c89atomic_uint8* )ptr, order)
14801 #define c89atomic_test_and_set_explicit_i16(ptr, order)                 (c89atomic_int16)c89atomic_test_and_set_explicit_16((c89atomic_uint16*)ptr, order)
14802 #define c89atomic_test_and_set_explicit_i32(ptr, order)                 (c89atomic_int32)c89atomic_test_and_set_explicit_32((c89atomic_uint32*)ptr, order)
14803 #define c89atomic_test_and_set_explicit_i64(ptr, order)                 (c89atomic_int64)c89atomic_test_and_set_explicit_64((c89atomic_uint64*)ptr, order)
14804 #define c89atomic_clear_explicit_i8( ptr, order)                        c89atomic_clear_explicit_8( (c89atomic_uint8* )ptr, order)
14805 #define c89atomic_clear_explicit_i16(ptr, order)                        c89atomic_clear_explicit_16((c89atomic_uint16*)ptr, order)
14806 #define c89atomic_clear_explicit_i32(ptr, order)                        c89atomic_clear_explicit_32((c89atomic_uint32*)ptr, order)
14807 #define c89atomic_clear_explicit_i64(ptr, order)                        c89atomic_clear_explicit_64((c89atomic_uint64*)ptr, order)
14808 #define c89atomic_store_explicit_i8( dst, src, order)                   (c89atomic_int8 )c89atomic_store_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
14809 #define c89atomic_store_explicit_i16(dst, src, order)                   (c89atomic_int16)c89atomic_store_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
14810 #define c89atomic_store_explicit_i32(dst, src, order)                   (c89atomic_int32)c89atomic_store_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
14811 #define c89atomic_store_explicit_i64(dst, src, order)                   (c89atomic_int64)c89atomic_store_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
14812 #define c89atomic_load_explicit_i8( ptr, order)                         (c89atomic_int8 )c89atomic_load_explicit_8( (c89atomic_uint8* )ptr, order)
14813 #define c89atomic_load_explicit_i16(ptr, order)                         (c89atomic_int16)c89atomic_load_explicit_16((c89atomic_uint16*)ptr, order)
14814 #define c89atomic_load_explicit_i32(ptr, order)                         (c89atomic_int32)c89atomic_load_explicit_32((c89atomic_uint32*)ptr, order)
14815 #define c89atomic_load_explicit_i64(ptr, order)                         (c89atomic_int64)c89atomic_load_explicit_64((c89atomic_uint64*)ptr, order)
14816 #define c89atomic_exchange_explicit_i8( dst, src, order)                (c89atomic_int8 )c89atomic_exchange_explicit_8 ((c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
14817 #define c89atomic_exchange_explicit_i16(dst, src, order)                (c89atomic_int16)c89atomic_exchange_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
14818 #define c89atomic_exchange_explicit_i32(dst, src, order)                (c89atomic_int32)c89atomic_exchange_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
14819 #define c89atomic_exchange_explicit_i64(dst, src, order)                (c89atomic_int64)c89atomic_exchange_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
14820 #define c89atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, successOrder, failureOrder)  c89atomic_compare_exchange_strong_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8* )expected, (c89atomic_uint8 )desired, successOrder, failureOrder)
14821 #define c89atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, successOrder, failureOrder)  c89atomic_compare_exchange_strong_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16*)expected, (c89atomic_uint16)desired, successOrder, failureOrder)
14822 #define c89atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, successOrder, failureOrder)  c89atomic_compare_exchange_strong_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder)
14823 #define c89atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, successOrder, failureOrder)  c89atomic_compare_exchange_strong_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder)
14824 #define c89atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, successOrder, failureOrder)    c89atomic_compare_exchange_weak_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8* )expected, (c89atomic_uint8 )desired, successOrder, failureOrder)
14825 #define c89atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, successOrder, failureOrder)    c89atomic_compare_exchange_weak_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16*)expected, (c89atomic_uint16)desired, successOrder, failureOrder)
14826 #define c89atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, successOrder, failureOrder)    c89atomic_compare_exchange_weak_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder)
14827 #define c89atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, successOrder, failureOrder)    c89atomic_compare_exchange_weak_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder)
14828 #define c89atomic_fetch_add_explicit_i8( dst, src, order)               (c89atomic_int8 )c89atomic_fetch_add_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
14829 #define c89atomic_fetch_add_explicit_i16(dst, src, order)               (c89atomic_int16)c89atomic_fetch_add_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
14830 #define c89atomic_fetch_add_explicit_i32(dst, src, order)               (c89atomic_int32)c89atomic_fetch_add_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
14831 #define c89atomic_fetch_add_explicit_i64(dst, src, order)               (c89atomic_int64)c89atomic_fetch_add_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
14832 #define c89atomic_fetch_sub_explicit_i8( dst, src, order)               (c89atomic_int8 )c89atomic_fetch_sub_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
14833 #define c89atomic_fetch_sub_explicit_i16(dst, src, order)               (c89atomic_int16)c89atomic_fetch_sub_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
14834 #define c89atomic_fetch_sub_explicit_i32(dst, src, order)               (c89atomic_int32)c89atomic_fetch_sub_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
14835 #define c89atomic_fetch_sub_explicit_i64(dst, src, order)               (c89atomic_int64)c89atomic_fetch_sub_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
14836 #define c89atomic_fetch_or_explicit_i8( dst, src, order)                (c89atomic_int8 )c89atomic_fetch_or_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
14837 #define c89atomic_fetch_or_explicit_i16(dst, src, order)                (c89atomic_int16)c89atomic_fetch_or_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
14838 #define c89atomic_fetch_or_explicit_i32(dst, src, order)                (c89atomic_int32)c89atomic_fetch_or_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
14839 #define c89atomic_fetch_or_explicit_i64(dst, src, order)                (c89atomic_int64)c89atomic_fetch_or_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
14840 #define c89atomic_fetch_xor_explicit_i8( dst, src, order)               (c89atomic_int8 )c89atomic_fetch_xor_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
14841 #define c89atomic_fetch_xor_explicit_i16(dst, src, order)               (c89atomic_int16)c89atomic_fetch_xor_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
14842 #define c89atomic_fetch_xor_explicit_i32(dst, src, order)               (c89atomic_int32)c89atomic_fetch_xor_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
14843 #define c89atomic_fetch_xor_explicit_i64(dst, src, order)               (c89atomic_int64)c89atomic_fetch_xor_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
14844 #define c89atomic_fetch_and_explicit_i8( dst, src, order)               (c89atomic_int8 )c89atomic_fetch_and_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
14845 #define c89atomic_fetch_and_explicit_i16(dst, src, order)               (c89atomic_int16)c89atomic_fetch_and_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
14846 #define c89atomic_fetch_and_explicit_i32(dst, src, order)               (c89atomic_int32)c89atomic_fetch_and_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
14847 #define c89atomic_fetch_and_explicit_i64(dst, src, order)               (c89atomic_int64)c89atomic_fetch_and_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
14848 #define c89atomic_test_and_set_i8( ptr)                                 c89atomic_test_and_set_explicit_i8( ptr, c89atomic_memory_order_seq_cst)
14849 #define c89atomic_test_and_set_i16(ptr)                                 c89atomic_test_and_set_explicit_i16(ptr, c89atomic_memory_order_seq_cst)
14850 #define c89atomic_test_and_set_i32(ptr)                                 c89atomic_test_and_set_explicit_i32(ptr, c89atomic_memory_order_seq_cst)
14851 #define c89atomic_test_and_set_i64(ptr)                                 c89atomic_test_and_set_explicit_i64(ptr, c89atomic_memory_order_seq_cst)
14852 #define c89atomic_clear_i8( ptr)                                        c89atomic_clear_explicit_i8( ptr, c89atomic_memory_order_seq_cst)
14853 #define c89atomic_clear_i16(ptr)                                        c89atomic_clear_explicit_i16(ptr, c89atomic_memory_order_seq_cst)
14854 #define c89atomic_clear_i32(ptr)                                        c89atomic_clear_explicit_i32(ptr, c89atomic_memory_order_seq_cst)
14855 #define c89atomic_clear_i64(ptr)                                        c89atomic_clear_explicit_i64(ptr, c89atomic_memory_order_seq_cst)
14856 #define c89atomic_store_i8( dst, src)                                   c89atomic_store_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
14857 #define c89atomic_store_i16(dst, src)                                   c89atomic_store_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
14858 #define c89atomic_store_i32(dst, src)                                   c89atomic_store_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
14859 #define c89atomic_store_i64(dst, src)                                   c89atomic_store_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
14860 #define c89atomic_load_i8( ptr)                                         c89atomic_load_explicit_i8( ptr, c89atomic_memory_order_seq_cst)
14861 #define c89atomic_load_i16(ptr)                                         c89atomic_load_explicit_i16(ptr, c89atomic_memory_order_seq_cst)
14862 #define c89atomic_load_i32(ptr)                                         c89atomic_load_explicit_i32(ptr, c89atomic_memory_order_seq_cst)
14863 #define c89atomic_load_i64(ptr)                                         c89atomic_load_explicit_i64(ptr, c89atomic_memory_order_seq_cst)
14864 #define c89atomic_exchange_i8( dst, src)                                c89atomic_exchange_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
14865 #define c89atomic_exchange_i16(dst, src)                                c89atomic_exchange_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
14866 #define c89atomic_exchange_i32(dst, src)                                c89atomic_exchange_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
14867 #define c89atomic_exchange_i64(dst, src)                                c89atomic_exchange_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
14868 #define c89atomic_compare_exchange_strong_i8( dst, expected, desired)   c89atomic_compare_exchange_strong_explicit_i8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14869 #define c89atomic_compare_exchange_strong_i16(dst, expected, desired)   c89atomic_compare_exchange_strong_explicit_i16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14870 #define c89atomic_compare_exchange_strong_i32(dst, expected, desired)   c89atomic_compare_exchange_strong_explicit_i32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14871 #define c89atomic_compare_exchange_strong_i64(dst, expected, desired)   c89atomic_compare_exchange_strong_explicit_i64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14872 #define c89atomic_compare_exchange_weak_i8( dst, expected, desired)     c89atomic_compare_exchange_weak_explicit_i8( dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14873 #define c89atomic_compare_exchange_weak_i16(dst, expected, desired)     c89atomic_compare_exchange_weak_explicit_i16(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14874 #define c89atomic_compare_exchange_weak_i32(dst, expected, desired)     c89atomic_compare_exchange_weak_explicit_i32(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14875 #define c89atomic_compare_exchange_weak_i64(dst, expected, desired)     c89atomic_compare_exchange_weak_explicit_i64(dst, expected, desired, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst)
14876 #define c89atomic_fetch_add_i8( dst, src)                               c89atomic_fetch_add_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
14877 #define c89atomic_fetch_add_i16(dst, src)                               c89atomic_fetch_add_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
14878 #define c89atomic_fetch_add_i32(dst, src)                               c89atomic_fetch_add_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
14879 #define c89atomic_fetch_add_i64(dst, src)                               c89atomic_fetch_add_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
14880 #define c89atomic_fetch_sub_i8( dst, src)                               c89atomic_fetch_sub_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
14881 #define c89atomic_fetch_sub_i16(dst, src)                               c89atomic_fetch_sub_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
14882 #define c89atomic_fetch_sub_i32(dst, src)                               c89atomic_fetch_sub_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
14883 #define c89atomic_fetch_sub_i64(dst, src)                               c89atomic_fetch_sub_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
14884 #define c89atomic_fetch_or_i8( dst, src)                                c89atomic_fetch_or_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
14885 #define c89atomic_fetch_or_i16(dst, src)                                c89atomic_fetch_or_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
14886 #define c89atomic_fetch_or_i32(dst, src)                                c89atomic_fetch_or_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
14887 #define c89atomic_fetch_or_i64(dst, src)                                c89atomic_fetch_or_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
14888 #define c89atomic_fetch_xor_i8( dst, src)                               c89atomic_fetch_xor_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
14889 #define c89atomic_fetch_xor_i16(dst, src)                               c89atomic_fetch_xor_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
14890 #define c89atomic_fetch_xor_i32(dst, src)                               c89atomic_fetch_xor_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
14891 #define c89atomic_fetch_xor_i64(dst, src)                               c89atomic_fetch_xor_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
14892 #define c89atomic_fetch_and_i8( dst, src)                               c89atomic_fetch_and_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
14893 #define c89atomic_fetch_and_i16(dst, src)                               c89atomic_fetch_and_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
14894 #define c89atomic_fetch_and_i32(dst, src)                               c89atomic_fetch_and_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
14895 #define c89atomic_fetch_and_i64(dst, src)                               c89atomic_fetch_and_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
14896 #define c89atomic_compare_and_swap_i8( dst, expected, dedsired)         (c89atomic_int8 )c89atomic_compare_and_swap_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )expected, (c89atomic_uint8 )dedsired)
14897 #define c89atomic_compare_and_swap_i16(dst, expected, dedsired)         (c89atomic_int16)c89atomic_compare_and_swap_16((c89atomic_uint16*)dst, (c89atomic_uint16)expected, (c89atomic_uint16)dedsired)
14898 #define c89atomic_compare_and_swap_i32(dst, expected, dedsired)         (c89atomic_int32)c89atomic_compare_and_swap_32((c89atomic_uint32*)dst, (c89atomic_uint32)expected, (c89atomic_uint32)dedsired)
14899 #define c89atomic_compare_and_swap_i64(dst, expected, dedsired)         (c89atomic_int64)c89atomic_compare_and_swap_64((c89atomic_uint64*)dst, (c89atomic_uint64)expected, (c89atomic_uint64)dedsired)
14900 typedef union
14901 {
14902     c89atomic_uint32 i;
14903     float f;
14904 } c89atomic_if32;
14905 typedef union
14906 {
14907     c89atomic_uint64 i;
14908     double f;
14909 } c89atomic_if64;
14910 #define c89atomic_clear_explicit_f32(ptr, order)                        c89atomic_clear_explicit_32((c89atomic_uint32*)ptr, order)
14911 #define c89atomic_clear_explicit_f64(ptr, order)                        c89atomic_clear_explicit_64((c89atomic_uint64*)ptr, order)
14912 static C89ATOMIC_INLINE void c89atomic_store_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order)
14913 {
14914     c89atomic_if32 x;
14915     x.f = src;
14916     c89atomic_store_explicit_32((volatile c89atomic_uint32*)dst, x.i, order);
14917 }
14918 static C89ATOMIC_INLINE void c89atomic_store_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order)
14919 {
14920     c89atomic_if64 x;
14921     x.f = src;
14922     c89atomic_store_explicit_64((volatile c89atomic_uint64*)dst, x.i, order);
14923 }
14924 static C89ATOMIC_INLINE float c89atomic_load_explicit_f32(volatile const float* ptr, c89atomic_memory_order order)
14925 {
14926     c89atomic_if32 r;
14927     r.i = c89atomic_load_explicit_32((volatile const c89atomic_uint32*)ptr, order);
14928     return r.f;
14929 }
14930 static C89ATOMIC_INLINE double c89atomic_load_explicit_f64(volatile const double* ptr, c89atomic_memory_order order)
14931 {
14932     c89atomic_if64 r;
14933     r.i = c89atomic_load_explicit_64((volatile const c89atomic_uint64*)ptr, order);
14934     return r.f;
14935 }
14936 static C89ATOMIC_INLINE float c89atomic_exchange_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order)
14937 {
14938     c89atomic_if32 r;
14939     c89atomic_if32 x;
14940     x.f = src;
14941     r.i = c89atomic_exchange_explicit_32((volatile c89atomic_uint32*)dst, x.i, order);
14942     return r.f;
14943 }
14944 static C89ATOMIC_INLINE double c89atomic_exchange_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order)
14945 {
14946     c89atomic_if64 r;
14947     c89atomic_if64 x;
14948     x.f = src;
14949     r.i = c89atomic_exchange_explicit_64((volatile c89atomic_uint64*)dst, x.i, order);
14950     return r.f;
14951 }
14952 #define c89atomic_clear_f32(ptr)                                        (float )c89atomic_clear_explicit_f32(ptr, c89atomic_memory_order_seq_cst)
14953 #define c89atomic_clear_f64(ptr)                                        (double)c89atomic_clear_explicit_f64(ptr, c89atomic_memory_order_seq_cst)
14954 #define c89atomic_store_f32(dst, src)                                   c89atomic_store_explicit_f32(dst, src, c89atomic_memory_order_seq_cst)
14955 #define c89atomic_store_f64(dst, src)                                   c89atomic_store_explicit_f64(dst, src, c89atomic_memory_order_seq_cst)
14956 #define c89atomic_load_f32(ptr)                                         (float )c89atomic_load_explicit_f32(ptr, c89atomic_memory_order_seq_cst)
14957 #define c89atomic_load_f64(ptr)                                         (double)c89atomic_load_explicit_f64(ptr, c89atomic_memory_order_seq_cst)
14958 #define c89atomic_exchange_f32(dst, src)                                (float )c89atomic_exchange_explicit_f32(dst, src, c89atomic_memory_order_seq_cst)
14959 #define c89atomic_exchange_f64(dst, src)                                (double)c89atomic_exchange_explicit_f64(dst, src, c89atomic_memory_order_seq_cst)
14960 typedef c89atomic_flag c89atomic_spinlock;
14961 static C89ATOMIC_INLINE void c89atomic_spinlock_lock(volatile c89atomic_spinlock* pSpinlock)
14962 {
14963     for (;;) {
14964         if (c89atomic_flag_test_and_set_explicit(pSpinlock, c89atomic_memory_order_acquire) == 0) {
14965             break;
14966         }
14967         while (c89atoimc_flag_load_explicit(pSpinlock, c89atomic_memory_order_relaxed) == 1) {
14968         }
14969     }
14970 }
14971 static C89ATOMIC_INLINE void c89atomic_spinlock_unlock(volatile c89atomic_spinlock* pSpinlock)
14972 {
14973     c89atomic_flag_clear_explicit(pSpinlock, c89atomic_memory_order_release);
14974 }
14975 #if defined(__cplusplus)
14976 }
14977 #endif
14978 #endif
14979 /* c89atomic.h end */
14980
14981
14982
14983 MA_API ma_uint64 ma_calculate_frame_count_after_resampling(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 frameCountIn)
14984 {
14985     /* This is based on the calculation in ma_linear_resampler_get_expected_output_frame_count(). */
14986     ma_uint64 outputFrameCount;
14987     ma_uint64 preliminaryInputFrameCountFromFrac;
14988     ma_uint64 preliminaryInputFrameCount;
14989
14990     if (sampleRateIn == 0 || sampleRateOut == 0 || frameCountIn == 0) {
14991         return 0;
14992     }
14993
14994     if (sampleRateOut == sampleRateIn) {
14995         return frameCountIn;
14996     }
14997
14998     outputFrameCount = (frameCountIn * sampleRateOut) / sampleRateIn;
14999
15000     preliminaryInputFrameCountFromFrac = (outputFrameCount * (sampleRateIn / sampleRateOut)) / sampleRateOut;
15001     preliminaryInputFrameCount         = (outputFrameCount * (sampleRateIn % sampleRateOut)) + preliminaryInputFrameCountFromFrac;
15002
15003     if (preliminaryInputFrameCount <= frameCountIn) {
15004         outputFrameCount += 1;
15005     }
15006
15007     return outputFrameCount;
15008 }
15009
15010 #ifndef MA_DATA_CONVERTER_STACK_BUFFER_SIZE
15011 #define MA_DATA_CONVERTER_STACK_BUFFER_SIZE     4096
15012 #endif
15013
15014
15015
15016 #if defined(MA_WIN32)
15017 static ma_result ma_result_from_GetLastError(DWORD error)
15018 {
15019     switch (error)
15020     {
15021         case ERROR_SUCCESS:             return MA_SUCCESS;
15022         case ERROR_PATH_NOT_FOUND:      return MA_DOES_NOT_EXIST;
15023         case ERROR_TOO_MANY_OPEN_FILES: return MA_TOO_MANY_OPEN_FILES;
15024         case ERROR_NOT_ENOUGH_MEMORY:   return MA_OUT_OF_MEMORY;
15025         case ERROR_DISK_FULL:           return MA_NO_SPACE;
15026         case ERROR_HANDLE_EOF:          return MA_AT_END;
15027         case ERROR_NEGATIVE_SEEK:       return MA_BAD_SEEK;
15028         case ERROR_INVALID_PARAMETER:   return MA_INVALID_ARGS;
15029         case ERROR_ACCESS_DENIED:       return MA_ACCESS_DENIED;
15030         case ERROR_SEM_TIMEOUT:         return MA_TIMEOUT;
15031         case ERROR_FILE_NOT_FOUND:      return MA_DOES_NOT_EXIST;
15032         default: break;
15033     }
15034
15035     return MA_ERROR;
15036 }
15037 #endif  /* MA_WIN32 */
15038
15039
15040 /*******************************************************************************
15041
15042 Threading
15043
15044 *******************************************************************************/
15045 static MA_INLINE ma_result ma_spinlock_lock_ex(volatile ma_spinlock* pSpinlock, ma_bool32 yield)
15046 {
15047     if (pSpinlock == NULL) {
15048         return MA_INVALID_ARGS;
15049     }
15050
15051     for (;;) {
15052         if (c89atomic_exchange_explicit_32(pSpinlock, 1, c89atomic_memory_order_acquire) == 0) {
15053             break;
15054         }
15055
15056         while (c89atomic_load_explicit_32(pSpinlock, c89atomic_memory_order_relaxed) == 1) {
15057             if (yield) {
15058                 ma_yield();
15059             }
15060         }
15061     }
15062
15063     return MA_SUCCESS;
15064 }
15065
15066 MA_API ma_result ma_spinlock_lock(volatile ma_spinlock* pSpinlock)
15067 {
15068     return ma_spinlock_lock_ex(pSpinlock, MA_TRUE);
15069 }
15070
15071 MA_API ma_result ma_spinlock_lock_noyield(volatile ma_spinlock* pSpinlock)
15072 {
15073     return ma_spinlock_lock_ex(pSpinlock, MA_FALSE);
15074 }
15075
15076 MA_API ma_result ma_spinlock_unlock(volatile ma_spinlock* pSpinlock)
15077 {
15078     if (pSpinlock == NULL) {
15079         return MA_INVALID_ARGS;
15080     }
15081
15082     c89atomic_store_explicit_32(pSpinlock, 0, c89atomic_memory_order_release);
15083     return MA_SUCCESS;
15084 }
15085
15086
15087 #ifndef MA_NO_THREADING
15088 #ifdef MA_WIN32
15089     #define MA_THREADCALL WINAPI
15090     typedef unsigned long ma_thread_result;
15091 #else
15092     #define MA_THREADCALL
15093     typedef void* ma_thread_result;
15094 #endif
15095 typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData);
15096
15097 #ifdef MA_WIN32
15098 static int ma_thread_priority_to_win32(ma_thread_priority priority)
15099 {
15100     switch (priority) {
15101         case ma_thread_priority_idle:     return THREAD_PRIORITY_IDLE;
15102         case ma_thread_priority_lowest:   return THREAD_PRIORITY_LOWEST;
15103         case ma_thread_priority_low:      return THREAD_PRIORITY_BELOW_NORMAL;
15104         case ma_thread_priority_normal:   return THREAD_PRIORITY_NORMAL;
15105         case ma_thread_priority_high:     return THREAD_PRIORITY_ABOVE_NORMAL;
15106         case ma_thread_priority_highest:  return THREAD_PRIORITY_HIGHEST;
15107         case ma_thread_priority_realtime: return THREAD_PRIORITY_TIME_CRITICAL;
15108         default:                          return THREAD_PRIORITY_NORMAL;
15109     }
15110 }
15111
15112 static ma_result ma_thread_create__win32(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
15113 {
15114     *pThread = CreateThread(NULL, stackSize, entryProc, pData, 0, NULL);
15115     if (*pThread == NULL) {
15116         return ma_result_from_GetLastError(GetLastError());
15117     }
15118
15119     SetThreadPriority((HANDLE)*pThread, ma_thread_priority_to_win32(priority));
15120
15121     return MA_SUCCESS;
15122 }
15123
15124 static void ma_thread_wait__win32(ma_thread* pThread)
15125 {
15126     WaitForSingleObject((HANDLE)*pThread, INFINITE);
15127     CloseHandle((HANDLE)*pThread);
15128 }
15129
15130
15131 static ma_result ma_mutex_init__win32(ma_mutex* pMutex)
15132 {
15133     *pMutex = CreateEventW(NULL, FALSE, TRUE, NULL);
15134     if (*pMutex == NULL) {
15135         return ma_result_from_GetLastError(GetLastError());
15136     }
15137
15138     return MA_SUCCESS;
15139 }
15140
15141 static void ma_mutex_uninit__win32(ma_mutex* pMutex)
15142 {
15143     CloseHandle((HANDLE)*pMutex);
15144 }
15145
15146 static void ma_mutex_lock__win32(ma_mutex* pMutex)
15147 {
15148     WaitForSingleObject((HANDLE)*pMutex, INFINITE);
15149 }
15150
15151 static void ma_mutex_unlock__win32(ma_mutex* pMutex)
15152 {
15153     SetEvent((HANDLE)*pMutex);
15154 }
15155
15156
15157 static ma_result ma_event_init__win32(ma_event* pEvent)
15158 {
15159     *pEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
15160     if (*pEvent == NULL) {
15161         return ma_result_from_GetLastError(GetLastError());
15162     }
15163
15164     return MA_SUCCESS;
15165 }
15166
15167 static void ma_event_uninit__win32(ma_event* pEvent)
15168 {
15169     CloseHandle((HANDLE)*pEvent);
15170 }
15171
15172 static ma_result ma_event_wait__win32(ma_event* pEvent)
15173 {
15174     DWORD result = WaitForSingleObject((HANDLE)*pEvent, INFINITE);
15175     if (result == WAIT_OBJECT_0) {
15176         return MA_SUCCESS;
15177     }
15178
15179     if (result == WAIT_TIMEOUT) {
15180         return MA_TIMEOUT;
15181     }
15182
15183     return ma_result_from_GetLastError(GetLastError());
15184 }
15185
15186 static ma_result ma_event_signal__win32(ma_event* pEvent)
15187 {
15188     BOOL result = SetEvent((HANDLE)*pEvent);
15189     if (result == 0) {
15190         return ma_result_from_GetLastError(GetLastError());
15191     }
15192
15193     return MA_SUCCESS;
15194 }
15195
15196
15197 static ma_result ma_semaphore_init__win32(int initialValue, ma_semaphore* pSemaphore)
15198 {
15199     *pSemaphore = CreateSemaphoreW(NULL, (LONG)initialValue, LONG_MAX, NULL);
15200     if (*pSemaphore == NULL) {
15201         return ma_result_from_GetLastError(GetLastError());
15202     }
15203
15204     return MA_SUCCESS;
15205 }
15206
15207 static void ma_semaphore_uninit__win32(ma_semaphore* pSemaphore)
15208 {
15209     CloseHandle((HANDLE)*pSemaphore);
15210 }
15211
15212 static ma_result ma_semaphore_wait__win32(ma_semaphore* pSemaphore)
15213 {
15214     DWORD result = WaitForSingleObject((HANDLE)*pSemaphore, INFINITE);
15215     if (result == WAIT_OBJECT_0) {
15216         return MA_SUCCESS;
15217     }
15218
15219     if (result == WAIT_TIMEOUT) {
15220         return MA_TIMEOUT;
15221     }
15222
15223     return ma_result_from_GetLastError(GetLastError());
15224 }
15225
15226 static ma_result ma_semaphore_release__win32(ma_semaphore* pSemaphore)
15227 {
15228     BOOL result = ReleaseSemaphore((HANDLE)*pSemaphore, 1, NULL);
15229     if (result == 0) {
15230         return ma_result_from_GetLastError(GetLastError());
15231     }
15232
15233     return MA_SUCCESS;
15234 }
15235 #endif
15236
15237
15238 #ifdef MA_POSIX
15239 static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
15240 {
15241     int result;
15242     pthread_attr_t* pAttr = NULL;
15243
15244 #if !defined(__EMSCRIPTEN__)
15245     /* Try setting the thread priority. It's not critical if anything fails here. */
15246     pthread_attr_t attr;
15247     if (pthread_attr_init(&attr) == 0) {
15248         int scheduler = -1;
15249         if (priority == ma_thread_priority_idle) {
15250 #ifdef SCHED_IDLE
15251             if (pthread_attr_setschedpolicy(&attr, SCHED_IDLE) == 0) {
15252                 scheduler = SCHED_IDLE;
15253             }
15254 #endif
15255         } else if (priority == ma_thread_priority_realtime) {
15256 #ifdef SCHED_FIFO
15257             if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0) {
15258                 scheduler = SCHED_FIFO;
15259             }
15260 #endif
15261 #ifdef MA_LINUX
15262         } else {
15263             scheduler = sched_getscheduler(0);
15264 #endif
15265         }
15266
15267         if (stackSize > 0) {
15268             pthread_attr_setstacksize(&attr, stackSize);
15269         }
15270
15271         if (scheduler != -1) {
15272             int priorityMin = sched_get_priority_min(scheduler);
15273             int priorityMax = sched_get_priority_max(scheduler);
15274             int priorityStep = (priorityMax - priorityMin) / 7;  /* 7 = number of priorities supported by miniaudio. */
15275
15276             struct sched_param sched;
15277             if (pthread_attr_getschedparam(&attr, &sched) == 0) {
15278                 if (priority == ma_thread_priority_idle) {
15279                     sched.sched_priority = priorityMin;
15280                 } else if (priority == ma_thread_priority_realtime) {
15281                     sched.sched_priority = priorityMax;
15282                 } else {
15283                     sched.sched_priority += ((int)priority + 5) * priorityStep;  /* +5 because the lowest priority is -5. */
15284                     if (sched.sched_priority < priorityMin) {
15285                         sched.sched_priority = priorityMin;
15286                     }
15287                     if (sched.sched_priority > priorityMax) {
15288                         sched.sched_priority = priorityMax;
15289                     }
15290                 }
15291
15292                 if (pthread_attr_setschedparam(&attr, &sched) == 0) {
15293                     pAttr = &attr;
15294                 }
15295             }
15296         }
15297     }
15298 #else
15299     /* It's the emscripten build. We'll have a few unused parameters. */
15300     (void)priority;
15301     (void)stackSize;
15302 #endif
15303
15304     result = pthread_create((pthread_t*)pThread, pAttr, entryProc, pData);
15305
15306     /* The thread attributes object is no longer required. */
15307     if (pAttr != NULL) {
15308         pthread_attr_destroy(pAttr);
15309     }
15310
15311     if (result != 0) {
15312         return ma_result_from_errno(result);
15313     }
15314
15315     return MA_SUCCESS;
15316 }
15317
15318 static void ma_thread_wait__posix(ma_thread* pThread)
15319 {
15320     pthread_join((pthread_t)*pThread, NULL);
15321     pthread_detach((pthread_t)*pThread);
15322 }
15323
15324
15325 static ma_result ma_mutex_init__posix(ma_mutex* pMutex)
15326 {
15327     int result = pthread_mutex_init((pthread_mutex_t*)pMutex, NULL);
15328     if (result != 0) {
15329         return ma_result_from_errno(result);
15330     }
15331
15332     return MA_SUCCESS;
15333 }
15334
15335 static void ma_mutex_uninit__posix(ma_mutex* pMutex)
15336 {
15337     pthread_mutex_destroy((pthread_mutex_t*)pMutex);
15338 }
15339
15340 static void ma_mutex_lock__posix(ma_mutex* pMutex)
15341 {
15342     pthread_mutex_lock((pthread_mutex_t*)pMutex);
15343 }
15344
15345 static void ma_mutex_unlock__posix(ma_mutex* pMutex)
15346 {
15347     pthread_mutex_unlock((pthread_mutex_t*)pMutex);
15348 }
15349
15350
15351 static ma_result ma_event_init__posix(ma_event* pEvent)
15352 {
15353     int result;
15354
15355     result = pthread_mutex_init((pthread_mutex_t*)&pEvent->lock, NULL);
15356     if (result != 0) {
15357         return ma_result_from_errno(result);
15358     }
15359
15360     result = pthread_cond_init((pthread_cond_t*)&pEvent->cond, NULL);
15361     if (result != 0) {
15362         pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock);
15363         return ma_result_from_errno(result);
15364     }
15365
15366     pEvent->value = 0;
15367     return MA_SUCCESS;
15368 }
15369
15370 static void ma_event_uninit__posix(ma_event* pEvent)
15371 {
15372     pthread_cond_destroy((pthread_cond_t*)&pEvent->cond);
15373     pthread_mutex_destroy((pthread_mutex_t*)&pEvent->lock);
15374 }
15375
15376 static ma_result ma_event_wait__posix(ma_event* pEvent)
15377 {
15378     pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock);
15379     {
15380         while (pEvent->value == 0) {
15381             pthread_cond_wait((pthread_cond_t*)&pEvent->cond, (pthread_mutex_t*)&pEvent->lock);
15382         }
15383         pEvent->value = 0;  /* Auto-reset. */
15384     }
15385     pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock);
15386
15387     return MA_SUCCESS;
15388 }
15389
15390 static ma_result ma_event_signal__posix(ma_event* pEvent)
15391 {
15392     pthread_mutex_lock((pthread_mutex_t*)&pEvent->lock);
15393     {
15394         pEvent->value = 1;
15395         pthread_cond_signal((pthread_cond_t*)&pEvent->cond);
15396     }
15397     pthread_mutex_unlock((pthread_mutex_t*)&pEvent->lock);
15398
15399     return MA_SUCCESS;
15400 }
15401
15402
15403 static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore* pSemaphore)
15404 {
15405     int result;
15406
15407     if (pSemaphore == NULL) {
15408         return MA_INVALID_ARGS;
15409     }
15410
15411     pSemaphore->value = initialValue;
15412
15413     result = pthread_mutex_init((pthread_mutex_t*)&pSemaphore->lock, NULL);
15414     if (result != 0) {
15415         return ma_result_from_errno(result);  /* Failed to create mutex. */
15416     }
15417
15418     result = pthread_cond_init((pthread_cond_t*)&pSemaphore->cond, NULL);
15419     if (result != 0) {
15420         pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock);
15421         return ma_result_from_errno(result);  /* Failed to create condition variable. */
15422     }
15423
15424     return MA_SUCCESS;
15425 }
15426
15427 static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore)
15428 {
15429     if (pSemaphore == NULL) {
15430         return;
15431     }
15432
15433     pthread_cond_destroy((pthread_cond_t*)&pSemaphore->cond);
15434     pthread_mutex_destroy((pthread_mutex_t*)&pSemaphore->lock);
15435 }
15436
15437 static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore)
15438 {
15439     if (pSemaphore == NULL) {
15440         return MA_INVALID_ARGS;
15441     }
15442
15443     pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock);
15444     {
15445         /* We need to wait on a condition variable before escaping. We can't return from this function until the semaphore has been signaled. */
15446         while (pSemaphore->value == 0) {
15447             pthread_cond_wait((pthread_cond_t*)&pSemaphore->cond, (pthread_mutex_t*)&pSemaphore->lock);
15448         }
15449
15450         pSemaphore->value -= 1;
15451     }
15452     pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock);
15453
15454     return MA_SUCCESS;
15455 }
15456
15457 static ma_result ma_semaphore_release__posix(ma_semaphore* pSemaphore)
15458 {
15459     if (pSemaphore == NULL) {
15460         return MA_INVALID_ARGS;
15461     }
15462
15463     pthread_mutex_lock((pthread_mutex_t*)&pSemaphore->lock);
15464     {
15465         pSemaphore->value += 1;
15466         pthread_cond_signal((pthread_cond_t*)&pSemaphore->cond);
15467     }
15468     pthread_mutex_unlock((pthread_mutex_t*)&pSemaphore->lock);
15469
15470     return MA_SUCCESS;
15471 }
15472 #endif
15473
15474 typedef struct
15475 {
15476     ma_thread_entry_proc entryProc;
15477     void* pData;
15478     ma_allocation_callbacks allocationCallbacks;
15479 } ma_thread_proxy_data;
15480
15481 static ma_thread_result MA_THREADCALL ma_thread_entry_proxy(void* pData)
15482 {
15483     ma_thread_proxy_data* pProxyData = (ma_thread_proxy_data*)pData;
15484     ma_thread_entry_proc entryProc;
15485     void* pEntryProcData;
15486     ma_thread_result result;
15487
15488     #if defined(MA_ON_THREAD_ENTRY)
15489         MA_ON_THREAD_ENTRY
15490     #endif
15491
15492     entryProc = pProxyData->entryProc;
15493     pEntryProcData = pProxyData->pData;
15494
15495     /* Free the proxy data before getting into the real thread entry proc. */
15496     ma_free(pProxyData, &pProxyData->allocationCallbacks);
15497
15498     result = entryProc(pEntryProcData);
15499
15500     #if defined(MA_ON_THREAD_EXIT)
15501         MA_ON_THREAD_EXIT
15502     #endif
15503
15504     return result;
15505 }
15506
15507 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)
15508 {
15509     ma_result result;
15510     ma_thread_proxy_data* pProxyData;
15511
15512     if (pThread == NULL || entryProc == NULL) {
15513         return MA_INVALID_ARGS;
15514     }
15515
15516     pProxyData = (ma_thread_proxy_data*)ma_malloc(sizeof(*pProxyData), pAllocationCallbacks);   /* Will be freed by the proxy entry proc. */
15517     if (pProxyData == NULL) {
15518         return MA_OUT_OF_MEMORY;
15519     }
15520
15521     pProxyData->entryProc = entryProc;
15522     pProxyData->pData     = pData;
15523     ma_allocation_callbacks_init_copy(&pProxyData->allocationCallbacks, pAllocationCallbacks);
15524
15525 #ifdef MA_WIN32
15526     result = ma_thread_create__win32(pThread, priority, stackSize, ma_thread_entry_proxy, pProxyData);
15527 #endif
15528 #ifdef MA_POSIX
15529     result = ma_thread_create__posix(pThread, priority, stackSize, ma_thread_entry_proxy, pProxyData);
15530 #endif
15531
15532     if (result != MA_SUCCESS) {
15533         ma_free(pProxyData, pAllocationCallbacks);
15534         return result;
15535     }
15536
15537     return MA_SUCCESS;
15538 }
15539
15540 static void ma_thread_wait(ma_thread* pThread)
15541 {
15542     if (pThread == NULL) {
15543         return;
15544     }
15545
15546 #ifdef MA_WIN32
15547     ma_thread_wait__win32(pThread);
15548 #endif
15549 #ifdef MA_POSIX
15550     ma_thread_wait__posix(pThread);
15551 #endif
15552 }
15553
15554
15555 MA_API ma_result ma_mutex_init(ma_mutex* pMutex)
15556 {
15557     if (pMutex == NULL) {
15558         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
15559         return MA_INVALID_ARGS;
15560     }
15561
15562 #ifdef MA_WIN32
15563     return ma_mutex_init__win32(pMutex);
15564 #endif
15565 #ifdef MA_POSIX
15566     return ma_mutex_init__posix(pMutex);
15567 #endif
15568 }
15569
15570 MA_API void ma_mutex_uninit(ma_mutex* pMutex)
15571 {
15572     if (pMutex == NULL) {
15573         return;
15574     }
15575
15576 #ifdef MA_WIN32
15577     ma_mutex_uninit__win32(pMutex);
15578 #endif
15579 #ifdef MA_POSIX
15580     ma_mutex_uninit__posix(pMutex);
15581 #endif
15582 }
15583
15584 MA_API void ma_mutex_lock(ma_mutex* pMutex)
15585 {
15586     if (pMutex == NULL) {
15587         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
15588         return;
15589     }
15590
15591 #ifdef MA_WIN32
15592     ma_mutex_lock__win32(pMutex);
15593 #endif
15594 #ifdef MA_POSIX
15595     ma_mutex_lock__posix(pMutex);
15596 #endif
15597 }
15598
15599 MA_API void ma_mutex_unlock(ma_mutex* pMutex)
15600 {
15601     if (pMutex == NULL) {
15602         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
15603         return;
15604 }
15605
15606 #ifdef MA_WIN32
15607     ma_mutex_unlock__win32(pMutex);
15608 #endif
15609 #ifdef MA_POSIX
15610     ma_mutex_unlock__posix(pMutex);
15611 #endif
15612 }
15613
15614
15615 MA_API ma_result ma_event_init(ma_event* pEvent)
15616 {
15617     if (pEvent == NULL) {
15618         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
15619         return MA_INVALID_ARGS;
15620     }
15621
15622 #ifdef MA_WIN32
15623     return ma_event_init__win32(pEvent);
15624 #endif
15625 #ifdef MA_POSIX
15626     return ma_event_init__posix(pEvent);
15627 #endif
15628 }
15629
15630 #if 0
15631 static ma_result ma_event_alloc_and_init(ma_event** ppEvent, ma_allocation_callbacks* pAllocationCallbacks)
15632 {
15633     ma_result result;
15634     ma_event* pEvent;
15635
15636     if (ppEvent == NULL) {
15637         return MA_INVALID_ARGS;
15638     }
15639
15640     *ppEvent = NULL;
15641
15642     pEvent = ma_malloc(sizeof(*pEvent), pAllocationCallbacks);
15643     if (pEvent == NULL) {
15644         return MA_OUT_OF_MEMORY;
15645     }
15646
15647     result = ma_event_init(pEvent);
15648     if (result != MA_SUCCESS) {
15649         ma_free(pEvent, pAllocationCallbacks);
15650         return result;
15651     }
15652
15653     *ppEvent = pEvent;
15654     return result;
15655 }
15656 #endif
15657
15658 MA_API void ma_event_uninit(ma_event* pEvent)
15659 {
15660     if (pEvent == NULL) {
15661         return;
15662     }
15663
15664 #ifdef MA_WIN32
15665     ma_event_uninit__win32(pEvent);
15666 #endif
15667 #ifdef MA_POSIX
15668     ma_event_uninit__posix(pEvent);
15669 #endif
15670 }
15671
15672 #if 0
15673 static void ma_event_uninit_and_free(ma_event* pEvent, ma_allocation_callbacks* pAllocationCallbacks)
15674 {
15675     if (pEvent == NULL) {
15676         return;
15677     }
15678
15679     ma_event_uninit(pEvent);
15680     ma_free(pEvent, pAllocationCallbacks);
15681 }
15682 #endif
15683
15684 MA_API ma_result ma_event_wait(ma_event* pEvent)
15685 {
15686     if (pEvent == NULL) {
15687         MA_ASSERT(MA_FALSE);    /* Fire an assert to the caller is aware of this bug. */
15688         return MA_INVALID_ARGS;
15689     }
15690
15691 #ifdef MA_WIN32
15692     return ma_event_wait__win32(pEvent);
15693 #endif
15694 #ifdef MA_POSIX
15695     return ma_event_wait__posix(pEvent);
15696 #endif
15697 }
15698
15699 MA_API ma_result ma_event_signal(ma_event* pEvent)
15700 {
15701     if (pEvent == NULL) {
15702         MA_ASSERT(MA_FALSE);    /* Fire an assert to the caller is aware of this bug. */
15703         return MA_INVALID_ARGS;
15704     }
15705
15706 #ifdef MA_WIN32
15707     return ma_event_signal__win32(pEvent);
15708 #endif
15709 #ifdef MA_POSIX
15710     return ma_event_signal__posix(pEvent);
15711 #endif
15712 }
15713
15714
15715 MA_API ma_result ma_semaphore_init(int initialValue, ma_semaphore* pSemaphore)
15716 {
15717     if (pSemaphore == NULL) {
15718         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
15719         return MA_INVALID_ARGS;
15720     }
15721
15722 #ifdef MA_WIN32
15723     return ma_semaphore_init__win32(initialValue, pSemaphore);
15724 #endif
15725 #ifdef MA_POSIX
15726     return ma_semaphore_init__posix(initialValue, pSemaphore);
15727 #endif
15728 }
15729
15730 MA_API void ma_semaphore_uninit(ma_semaphore* pSemaphore)
15731 {
15732     if (pSemaphore == NULL) {
15733         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
15734         return;
15735     }
15736
15737 #ifdef MA_WIN32
15738     ma_semaphore_uninit__win32(pSemaphore);
15739 #endif
15740 #ifdef MA_POSIX
15741     ma_semaphore_uninit__posix(pSemaphore);
15742 #endif
15743 }
15744
15745 MA_API ma_result ma_semaphore_wait(ma_semaphore* pSemaphore)
15746 {
15747     if (pSemaphore == NULL) {
15748         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
15749         return MA_INVALID_ARGS;
15750     }
15751
15752 #ifdef MA_WIN32
15753     return ma_semaphore_wait__win32(pSemaphore);
15754 #endif
15755 #ifdef MA_POSIX
15756     return ma_semaphore_wait__posix(pSemaphore);
15757 #endif
15758 }
15759
15760 MA_API ma_result ma_semaphore_release(ma_semaphore* pSemaphore)
15761 {
15762     if (pSemaphore == NULL) {
15763         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
15764         return MA_INVALID_ARGS;
15765     }
15766
15767 #ifdef MA_WIN32
15768     return ma_semaphore_release__win32(pSemaphore);
15769 #endif
15770 #ifdef MA_POSIX
15771     return ma_semaphore_release__posix(pSemaphore);
15772 #endif
15773 }
15774 #else
15775 /* MA_NO_THREADING is set which means threading is disabled. Threading is required by some API families. If any of these are enabled we need to throw an error. */
15776 #ifndef MA_NO_DEVICE_IO
15777 #error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
15778 #endif
15779 #endif  /* MA_NO_THREADING */
15780
15781
15782
15783 #define MA_FENCE_COUNTER_MAX    0x7FFFFFFF
15784
15785 MA_API ma_result ma_fence_init(ma_fence* pFence)
15786 {
15787     if (pFence == NULL) {
15788         return MA_INVALID_ARGS;
15789     }
15790
15791     MA_ZERO_OBJECT(pFence);
15792     pFence->counter = 0;
15793
15794     #ifndef MA_NO_THREADING
15795     {
15796         ma_result result;
15797
15798         result = ma_event_init(&pFence->e);
15799         if (result != MA_SUCCESS) {
15800             return result;
15801         }
15802     }
15803     #endif
15804
15805     return MA_SUCCESS;
15806 }
15807
15808 MA_API void ma_fence_uninit(ma_fence* pFence)
15809 {
15810     if (pFence == NULL) {
15811         return;
15812     }
15813
15814     #ifndef MA_NO_THREADING
15815     {
15816         ma_event_uninit(&pFence->e);
15817     }
15818     #endif
15819
15820     MA_ZERO_OBJECT(pFence);
15821 }
15822
15823 MA_API ma_result ma_fence_acquire(ma_fence* pFence)
15824 {
15825     if (pFence == NULL) {
15826         return MA_INVALID_ARGS;
15827     }
15828
15829     for (;;) {
15830         ma_uint32 oldCounter = c89atomic_load_32(&pFence->counter);
15831         ma_uint32 newCounter = oldCounter + 1;
15832
15833         /* Make sure we're not about to exceed our maximum value. */
15834         if (newCounter > MA_FENCE_COUNTER_MAX) {
15835             MA_ASSERT(MA_FALSE);
15836             return MA_OUT_OF_RANGE;
15837         }
15838
15839         if (c89atomic_compare_exchange_weak_32(&pFence->counter, &oldCounter, newCounter)) {
15840             return MA_SUCCESS;
15841         } else {
15842             if (oldCounter == MA_FENCE_COUNTER_MAX) {
15843                 MA_ASSERT(MA_FALSE);
15844                 return MA_OUT_OF_RANGE; /* The other thread took the last available slot. Abort. */
15845             }
15846         }
15847     }
15848
15849     /* Should never get here. */
15850     /*return MA_SUCCESS;*/
15851 }
15852
15853 MA_API ma_result ma_fence_release(ma_fence* pFence)
15854 {
15855     if (pFence == NULL) {
15856         return MA_INVALID_ARGS;
15857     }
15858
15859     for (;;) {
15860         ma_uint32 oldCounter = c89atomic_load_32(&pFence->counter);
15861         ma_uint32 newCounter = oldCounter - 1;
15862
15863         if (oldCounter == 0) {
15864             MA_ASSERT(MA_FALSE);
15865             return MA_INVALID_OPERATION;    /* Acquire/release mismatch. */
15866         }
15867
15868         if (c89atomic_compare_exchange_weak_32(&pFence->counter, &oldCounter, newCounter)) {
15869             #ifndef MA_NO_THREADING
15870             {
15871                 if (newCounter == 0) {
15872                     ma_event_signal(&pFence->e);    /* <-- ma_fence_wait() will be waiting on this. */
15873                 }
15874             }
15875             #endif
15876
15877             return MA_SUCCESS;
15878         } else {
15879             if (oldCounter == 0) {
15880                 MA_ASSERT(MA_FALSE);
15881                 return MA_INVALID_OPERATION;    /* Another thread has taken the 0 slot. Acquire/release mismatch. */
15882             }
15883         }
15884     }
15885
15886     /* Should never get here. */
15887     /*return MA_SUCCESS;*/
15888 }
15889
15890 MA_API ma_result ma_fence_wait(ma_fence* pFence)
15891 {
15892     if (pFence == NULL) {
15893         return MA_INVALID_ARGS;
15894     }
15895
15896     for (;;) {
15897         ma_uint32 counter;
15898
15899         counter = c89atomic_load_32(&pFence->counter);
15900         if (counter == 0) {
15901             /*
15902             Counter has hit zero. By the time we get here some other thread may have acquired the
15903             fence again, but that is where the caller needs to take care with how they se the fence.
15904             */
15905             return MA_SUCCESS;
15906         }
15907
15908         /* Getting here means the counter is > 0. We'll need to wait for something to happen. */
15909         #ifndef MA_NO_THREADING
15910         {
15911             ma_result result;
15912
15913             result = ma_event_wait(&pFence->e);
15914             if (result != MA_SUCCESS) {
15915                 return result;
15916             }
15917         }
15918         #endif
15919     }
15920
15921     /* Should never get here. */
15922     /*return MA_INVALID_OPERATION;*/
15923 }
15924
15925
15926 MA_API ma_result ma_async_notification_signal(ma_async_notification* pNotification)
15927 {
15928     ma_async_notification_callbacks* pNotificationCallbacks = (ma_async_notification_callbacks*)pNotification;
15929
15930     if (pNotification == NULL) {
15931         return MA_INVALID_ARGS;
15932     }
15933
15934     if (pNotificationCallbacks->onSignal == NULL) {
15935         return MA_NOT_IMPLEMENTED;
15936     }
15937
15938     pNotificationCallbacks->onSignal(pNotification);
15939     return MA_INVALID_ARGS;
15940 }
15941
15942
15943 static void ma_async_notification_poll__on_signal(ma_async_notification* pNotification)
15944 {
15945     ((ma_async_notification_poll*)pNotification)->signalled = MA_TRUE;
15946 }
15947
15948 MA_API ma_result ma_async_notification_poll_init(ma_async_notification_poll* pNotificationPoll)
15949 {
15950     if (pNotificationPoll == NULL) {
15951         return MA_INVALID_ARGS;
15952     }
15953
15954     pNotificationPoll->cb.onSignal = ma_async_notification_poll__on_signal;
15955     pNotificationPoll->signalled = MA_FALSE;
15956
15957     return MA_SUCCESS;
15958 }
15959
15960 MA_API ma_bool32 ma_async_notification_poll_is_signalled(const ma_async_notification_poll* pNotificationPoll)
15961 {
15962     if (pNotificationPoll == NULL) {
15963         return MA_FALSE;
15964     }
15965
15966     return pNotificationPoll->signalled;
15967 }
15968
15969
15970 static void ma_async_notification_event__on_signal(ma_async_notification* pNotification)
15971 {
15972     ma_async_notification_event_signal((ma_async_notification_event*)pNotification);
15973 }
15974
15975 MA_API ma_result ma_async_notification_event_init(ma_async_notification_event* pNotificationEvent)
15976 {
15977     if (pNotificationEvent == NULL) {
15978         return MA_INVALID_ARGS;
15979     }
15980
15981     pNotificationEvent->cb.onSignal = ma_async_notification_event__on_signal;
15982
15983     #ifndef MA_NO_THREADING
15984     {
15985         ma_result result;
15986
15987         result = ma_event_init(&pNotificationEvent->e);
15988         if (result != MA_SUCCESS) {
15989             return result;
15990         }
15991
15992         return MA_SUCCESS;
15993     }
15994     #else
15995     {
15996         return MA_NOT_IMPLEMENTED;  /* Threading is disabled. */
15997     }
15998     #endif
15999 }
16000
16001 MA_API ma_result ma_async_notification_event_uninit(ma_async_notification_event* pNotificationEvent)
16002 {
16003     if (pNotificationEvent == NULL) {
16004         return MA_INVALID_ARGS;
16005     }
16006
16007     #ifndef MA_NO_THREADING
16008     {
16009         ma_event_uninit(&pNotificationEvent->e);
16010         return MA_SUCCESS;
16011     }
16012     #else
16013     {
16014         return MA_NOT_IMPLEMENTED;  /* Threading is disabled. */
16015     }
16016     #endif
16017 }
16018
16019 MA_API ma_result ma_async_notification_event_wait(ma_async_notification_event* pNotificationEvent)
16020 {
16021     if (pNotificationEvent == NULL) {
16022         return MA_INVALID_ARGS;
16023     }
16024
16025     #ifndef MA_NO_THREADING
16026     {
16027         return ma_event_wait(&pNotificationEvent->e);
16028     }
16029     #else
16030     {
16031         return MA_NOT_IMPLEMENTED;  /* Threading is disabled. */
16032     }
16033     #endif
16034 }
16035
16036 MA_API ma_result ma_async_notification_event_signal(ma_async_notification_event* pNotificationEvent)
16037 {
16038     if (pNotificationEvent == NULL) {
16039         return MA_INVALID_ARGS;
16040     }
16041
16042     #ifndef MA_NO_THREADING
16043     {
16044         return ma_event_signal(&pNotificationEvent->e);
16045     }
16046     #else
16047     {
16048         return MA_NOT_IMPLEMENTED;  /* Threading is disabled. */
16049     }
16050     #endif
16051 }
16052
16053
16054
16055
16056 /************************************************************************************************************************************************************
16057 *************************************************************************************************************************************************************
16058
16059 DEVICE I/O
16060 ==========
16061
16062 *************************************************************************************************************************************************************
16063 ************************************************************************************************************************************************************/
16064 #ifndef MA_NO_DEVICE_IO
16065 #ifdef MA_WIN32
16066     #include <objbase.h>
16067     #include <mmreg.h>
16068     #include <mmsystem.h>
16069 #endif
16070
16071 #if defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
16072     #include <mach/mach_time.h> /* For mach_absolute_time() */
16073 #endif
16074
16075 #ifdef MA_POSIX
16076     #include <sys/types.h>
16077     #include <unistd.h>
16078     #include <dlfcn.h>
16079 #endif
16080
16081 /*
16082 Unfortunately using runtime linking for pthreads causes problems. This has occurred for me when testing on FreeBSD. When
16083 using runtime linking, deadlocks can occur (for me it happens when loading data from fread()). It turns out that doing
16084 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
16085 disable runtime linking by default. To enable runtime linking, #define this before the implementation of this file. I am
16086 not officially supporting this, but I'm leaving it here in case it's useful for somebody, somewhere.
16087 */
16088 /*#define MA_USE_RUNTIME_LINKING_FOR_PTHREAD*/
16089
16090 /* Disable run-time linking on certain backends. */
16091 #ifndef MA_NO_RUNTIME_LINKING
16092     #if defined(MA_EMSCRIPTEN)
16093         #define MA_NO_RUNTIME_LINKING
16094     #endif
16095 #endif
16096
16097
16098 MA_API void ma_device_info_add_native_data_format(ma_device_info* pDeviceInfo, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 flags)
16099 {
16100     if (pDeviceInfo == NULL) {
16101         return;
16102     }
16103
16104     if (pDeviceInfo->nativeDataFormatCount < ma_countof(pDeviceInfo->nativeDataFormats)) {
16105         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = format;
16106         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
16107         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate;
16108         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = flags;
16109         pDeviceInfo->nativeDataFormatCount += 1;
16110     }
16111 }
16112
16113
16114 MA_API const char* ma_get_backend_name(ma_backend backend)
16115 {
16116     switch (backend)
16117     {
16118         case ma_backend_wasapi:     return "WASAPI";
16119         case ma_backend_dsound:     return "DirectSound";
16120         case ma_backend_winmm:      return "WinMM";
16121         case ma_backend_coreaudio:  return "Core Audio";
16122         case ma_backend_sndio:      return "sndio";
16123         case ma_backend_audio4:     return "audio(4)";
16124         case ma_backend_oss:        return "OSS";
16125         case ma_backend_pulseaudio: return "PulseAudio";
16126         case ma_backend_alsa:       return "ALSA";
16127         case ma_backend_jack:       return "JACK";
16128         case ma_backend_aaudio:     return "AAudio";
16129         case ma_backend_opensl:     return "OpenSL|ES";
16130         case ma_backend_webaudio:   return "Web Audio";
16131         case ma_backend_custom:     return "Custom";
16132         case ma_backend_null:       return "Null";
16133         default:                    return "Unknown";
16134     }
16135 }
16136
16137 MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend)
16138 {
16139     /*
16140     This looks a little bit gross, but we want all backends to be included in the switch to avoid warnings on some compilers
16141     about some enums not being handled by the switch statement.
16142     */
16143     switch (backend)
16144     {
16145         case ma_backend_wasapi:
16146         #if defined(MA_HAS_WASAPI)
16147             return MA_TRUE;
16148         #else
16149             return MA_FALSE;
16150         #endif
16151         case ma_backend_dsound:
16152         #if defined(MA_HAS_DSOUND)
16153             return MA_TRUE;
16154         #else
16155             return MA_FALSE;
16156         #endif
16157         case ma_backend_winmm:
16158         #if defined(MA_HAS_WINMM)
16159             return MA_TRUE;
16160         #else
16161             return MA_FALSE;
16162         #endif
16163         case ma_backend_coreaudio:
16164         #if defined(MA_HAS_COREAUDIO)
16165             return MA_TRUE;
16166         #else
16167             return MA_FALSE;
16168         #endif
16169         case ma_backend_sndio:
16170         #if defined(MA_HAS_SNDIO)
16171             return MA_TRUE;
16172         #else
16173             return MA_FALSE;
16174         #endif
16175         case ma_backend_audio4:
16176         #if defined(MA_HAS_AUDIO4)
16177             return MA_TRUE;
16178         #else
16179             return MA_FALSE;
16180         #endif
16181         case ma_backend_oss:
16182         #if defined(MA_HAS_OSS)
16183             return MA_TRUE;
16184         #else
16185             return MA_FALSE;
16186         #endif
16187         case ma_backend_pulseaudio:
16188         #if defined(MA_HAS_PULSEAUDIO)
16189             return MA_TRUE;
16190         #else
16191             return MA_FALSE;
16192         #endif
16193         case ma_backend_alsa:
16194         #if defined(MA_HAS_ALSA)
16195             return MA_TRUE;
16196         #else
16197             return MA_FALSE;
16198         #endif
16199         case ma_backend_jack:
16200         #if defined(MA_HAS_JACK)
16201             return MA_TRUE;
16202         #else
16203             return MA_FALSE;
16204         #endif
16205         case ma_backend_aaudio:
16206         #if defined(MA_HAS_AAUDIO)
16207             return MA_TRUE;
16208         #else
16209             return MA_FALSE;
16210         #endif
16211         case ma_backend_opensl:
16212         #if defined(MA_HAS_OPENSL)
16213             return MA_TRUE;
16214         #else
16215             return MA_FALSE;
16216         #endif
16217         case ma_backend_webaudio:
16218         #if defined(MA_HAS_WEBAUDIO)
16219             return MA_TRUE;
16220         #else
16221             return MA_FALSE;
16222         #endif
16223         case ma_backend_custom:
16224         #if defined(MA_HAS_CUSTOM)
16225             return MA_TRUE;
16226         #else
16227             return MA_FALSE;
16228         #endif
16229         case ma_backend_null:
16230         #if defined(MA_HAS_NULL)
16231             return MA_TRUE;
16232         #else
16233             return MA_FALSE;
16234         #endif
16235
16236         default: return MA_FALSE;
16237     }
16238 }
16239
16240 MA_API ma_result ma_get_enabled_backends(ma_backend* pBackends, size_t backendCap, size_t* pBackendCount)
16241 {
16242     size_t backendCount;
16243     size_t iBackend;
16244     ma_result result = MA_SUCCESS;
16245
16246     if (pBackendCount == NULL) {
16247         return MA_INVALID_ARGS;
16248     }
16249
16250     backendCount = 0;
16251
16252     for (iBackend = 0; iBackend <= ma_backend_null; iBackend += 1) {
16253         ma_backend backend = (ma_backend)iBackend;
16254
16255         if (ma_is_backend_enabled(backend)) {
16256             /* The backend is enabled. Try adding it to the list. If there's no room, MA_NO_SPACE needs to be returned. */
16257             if (backendCount == backendCap) {
16258                 result = MA_NO_SPACE;
16259                 break;
16260             } else {
16261                 pBackends[backendCount] = backend;
16262                 backendCount += 1;
16263             }
16264         }
16265     }
16266
16267     if (pBackendCount != NULL) {
16268         *pBackendCount = backendCount;
16269     }
16270
16271     return result;
16272 }
16273
16274 MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend)
16275 {
16276     switch (backend)
16277     {
16278         case ma_backend_wasapi:     return MA_TRUE;
16279         case ma_backend_dsound:     return MA_FALSE;
16280         case ma_backend_winmm:      return MA_FALSE;
16281         case ma_backend_coreaudio:  return MA_FALSE;
16282         case ma_backend_sndio:      return MA_FALSE;
16283         case ma_backend_audio4:     return MA_FALSE;
16284         case ma_backend_oss:        return MA_FALSE;
16285         case ma_backend_pulseaudio: return MA_FALSE;
16286         case ma_backend_alsa:       return MA_FALSE;
16287         case ma_backend_jack:       return MA_FALSE;
16288         case ma_backend_aaudio:     return MA_FALSE;
16289         case ma_backend_opensl:     return MA_FALSE;
16290         case ma_backend_webaudio:   return MA_FALSE;
16291         case ma_backend_custom:     return MA_FALSE;    /* <-- Will depend on the implementation of the backend. */
16292         case ma_backend_null:       return MA_FALSE;
16293         default:                    return MA_FALSE;
16294     }
16295 }
16296
16297
16298
16299 #ifdef MA_WIN32
16300 /* WASAPI error codes. */
16301 #define MA_AUDCLNT_E_NOT_INITIALIZED              ((HRESULT)0x88890001)
16302 #define MA_AUDCLNT_E_ALREADY_INITIALIZED          ((HRESULT)0x88890002)
16303 #define MA_AUDCLNT_E_WRONG_ENDPOINT_TYPE          ((HRESULT)0x88890003)
16304 #define MA_AUDCLNT_E_DEVICE_INVALIDATED           ((HRESULT)0x88890004)
16305 #define MA_AUDCLNT_E_NOT_STOPPED                  ((HRESULT)0x88890005)
16306 #define MA_AUDCLNT_E_BUFFER_TOO_LARGE             ((HRESULT)0x88890006)
16307 #define MA_AUDCLNT_E_OUT_OF_ORDER                 ((HRESULT)0x88890007)
16308 #define MA_AUDCLNT_E_UNSUPPORTED_FORMAT           ((HRESULT)0x88890008)
16309 #define MA_AUDCLNT_E_INVALID_SIZE                 ((HRESULT)0x88890009)
16310 #define MA_AUDCLNT_E_DEVICE_IN_USE                ((HRESULT)0x8889000A)
16311 #define MA_AUDCLNT_E_BUFFER_OPERATION_PENDING     ((HRESULT)0x8889000B)
16312 #define MA_AUDCLNT_E_THREAD_NOT_REGISTERED        ((HRESULT)0x8889000C)
16313 #define MA_AUDCLNT_E_NO_SINGLE_PROCESS            ((HRESULT)0x8889000D)
16314 #define MA_AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED   ((HRESULT)0x8889000E)
16315 #define MA_AUDCLNT_E_ENDPOINT_CREATE_FAILED       ((HRESULT)0x8889000F)
16316 #define MA_AUDCLNT_E_SERVICE_NOT_RUNNING          ((HRESULT)0x88890010)
16317 #define MA_AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED     ((HRESULT)0x88890011)
16318 #define MA_AUDCLNT_E_EXCLUSIVE_MODE_ONLY          ((HRESULT)0x88890012)
16319 #define MA_AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL ((HRESULT)0x88890013)
16320 #define MA_AUDCLNT_E_EVENTHANDLE_NOT_SET          ((HRESULT)0x88890014)
16321 #define MA_AUDCLNT_E_INCORRECT_BUFFER_SIZE        ((HRESULT)0x88890015)
16322 #define MA_AUDCLNT_E_BUFFER_SIZE_ERROR            ((HRESULT)0x88890016)
16323 #define MA_AUDCLNT_E_CPUUSAGE_EXCEEDED            ((HRESULT)0x88890017)
16324 #define MA_AUDCLNT_E_BUFFER_ERROR                 ((HRESULT)0x88890018)
16325 #define MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED      ((HRESULT)0x88890019)
16326 #define MA_AUDCLNT_E_INVALID_DEVICE_PERIOD        ((HRESULT)0x88890020)
16327 #define MA_AUDCLNT_E_INVALID_STREAM_FLAG          ((HRESULT)0x88890021)
16328 #define MA_AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE ((HRESULT)0x88890022)
16329 #define MA_AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES     ((HRESULT)0x88890023)
16330 #define MA_AUDCLNT_E_OFFLOAD_MODE_ONLY            ((HRESULT)0x88890024)
16331 #define MA_AUDCLNT_E_NONOFFLOAD_MODE_ONLY         ((HRESULT)0x88890025)
16332 #define MA_AUDCLNT_E_RESOURCES_INVALIDATED        ((HRESULT)0x88890026)
16333 #define MA_AUDCLNT_E_RAW_MODE_UNSUPPORTED         ((HRESULT)0x88890027)
16334 #define MA_AUDCLNT_E_ENGINE_PERIODICITY_LOCKED    ((HRESULT)0x88890028)
16335 #define MA_AUDCLNT_E_ENGINE_FORMAT_LOCKED         ((HRESULT)0x88890029)
16336 #define MA_AUDCLNT_E_HEADTRACKING_ENABLED         ((HRESULT)0x88890030)
16337 #define MA_AUDCLNT_E_HEADTRACKING_UNSUPPORTED     ((HRESULT)0x88890040)
16338 #define MA_AUDCLNT_S_BUFFER_EMPTY                 ((HRESULT)0x08890001)
16339 #define MA_AUDCLNT_S_THREAD_ALREADY_REGISTERED    ((HRESULT)0x08890002)
16340 #define MA_AUDCLNT_S_POSITION_STALLED             ((HRESULT)0x08890003)
16341
16342 #define MA_DS_OK                                  ((HRESULT)0)
16343 #define MA_DS_NO_VIRTUALIZATION                   ((HRESULT)0x0878000A)
16344 #define MA_DSERR_ALLOCATED                        ((HRESULT)0x8878000A)
16345 #define MA_DSERR_CONTROLUNAVAIL                   ((HRESULT)0x8878001E)
16346 #define MA_DSERR_INVALIDPARAM                     ((HRESULT)0x80070057) /*E_INVALIDARG*/
16347 #define MA_DSERR_INVALIDCALL                      ((HRESULT)0x88780032)
16348 #define MA_DSERR_GENERIC                          ((HRESULT)0x80004005) /*E_FAIL*/
16349 #define MA_DSERR_PRIOLEVELNEEDED                  ((HRESULT)0x88780046)
16350 #define MA_DSERR_OUTOFMEMORY                      ((HRESULT)0x8007000E) /*E_OUTOFMEMORY*/
16351 #define MA_DSERR_BADFORMAT                        ((HRESULT)0x88780064)
16352 #define MA_DSERR_UNSUPPORTED                      ((HRESULT)0x80004001) /*E_NOTIMPL*/
16353 #define MA_DSERR_NODRIVER                         ((HRESULT)0x88780078)
16354 #define MA_DSERR_ALREADYINITIALIZED               ((HRESULT)0x88780082)
16355 #define MA_DSERR_NOAGGREGATION                    ((HRESULT)0x80040110) /*CLASS_E_NOAGGREGATION*/
16356 #define MA_DSERR_BUFFERLOST                       ((HRESULT)0x88780096)
16357 #define MA_DSERR_OTHERAPPHASPRIO                  ((HRESULT)0x887800A0)
16358 #define MA_DSERR_UNINITIALIZED                    ((HRESULT)0x887800AA)
16359 #define MA_DSERR_NOINTERFACE                      ((HRESULT)0x80004002) /*E_NOINTERFACE*/
16360 #define MA_DSERR_ACCESSDENIED                     ((HRESULT)0x80070005) /*E_ACCESSDENIED*/
16361 #define MA_DSERR_BUFFERTOOSMALL                   ((HRESULT)0x887800B4)
16362 #define MA_DSERR_DS8_REQUIRED                     ((HRESULT)0x887800BE)
16363 #define MA_DSERR_SENDLOOP                         ((HRESULT)0x887800C8)
16364 #define MA_DSERR_BADSENDBUFFERGUID                ((HRESULT)0x887800D2)
16365 #define MA_DSERR_OBJECTNOTFOUND                   ((HRESULT)0x88781161)
16366 #define MA_DSERR_FXUNAVAILABLE                    ((HRESULT)0x887800DC)
16367
16368 static ma_result ma_result_from_HRESULT(HRESULT hr)
16369 {
16370     switch (hr)
16371     {
16372         case NOERROR:                                   return MA_SUCCESS;
16373         /*case S_OK:                                      return MA_SUCCESS;*/
16374
16375         case E_POINTER:                                 return MA_INVALID_ARGS;
16376         case E_UNEXPECTED:                              return MA_ERROR;
16377         case E_NOTIMPL:                                 return MA_NOT_IMPLEMENTED;
16378         case E_OUTOFMEMORY:                             return MA_OUT_OF_MEMORY;
16379         case E_INVALIDARG:                              return MA_INVALID_ARGS;
16380         case E_NOINTERFACE:                             return MA_API_NOT_FOUND;
16381         case E_HANDLE:                                  return MA_INVALID_ARGS;
16382         case E_ABORT:                                   return MA_ERROR;
16383         case E_FAIL:                                    return MA_ERROR;
16384         case E_ACCESSDENIED:                            return MA_ACCESS_DENIED;
16385
16386         /* WASAPI */
16387         case MA_AUDCLNT_E_NOT_INITIALIZED:              return MA_DEVICE_NOT_INITIALIZED;
16388         case MA_AUDCLNT_E_ALREADY_INITIALIZED:          return MA_DEVICE_ALREADY_INITIALIZED;
16389         case MA_AUDCLNT_E_WRONG_ENDPOINT_TYPE:          return MA_INVALID_ARGS;
16390         case MA_AUDCLNT_E_DEVICE_INVALIDATED:           return MA_UNAVAILABLE;
16391         case MA_AUDCLNT_E_NOT_STOPPED:                  return MA_DEVICE_NOT_STOPPED;
16392         case MA_AUDCLNT_E_BUFFER_TOO_LARGE:             return MA_TOO_BIG;
16393         case MA_AUDCLNT_E_OUT_OF_ORDER:                 return MA_INVALID_OPERATION;
16394         case MA_AUDCLNT_E_UNSUPPORTED_FORMAT:           return MA_FORMAT_NOT_SUPPORTED;
16395         case MA_AUDCLNT_E_INVALID_SIZE:                 return MA_INVALID_ARGS;
16396         case MA_AUDCLNT_E_DEVICE_IN_USE:                return MA_BUSY;
16397         case MA_AUDCLNT_E_BUFFER_OPERATION_PENDING:     return MA_INVALID_OPERATION;
16398         case MA_AUDCLNT_E_THREAD_NOT_REGISTERED:        return MA_DOES_NOT_EXIST;
16399         case MA_AUDCLNT_E_NO_SINGLE_PROCESS:            return MA_INVALID_OPERATION;
16400         case MA_AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED:   return MA_SHARE_MODE_NOT_SUPPORTED;
16401         case MA_AUDCLNT_E_ENDPOINT_CREATE_FAILED:       return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
16402         case MA_AUDCLNT_E_SERVICE_NOT_RUNNING:          return MA_NOT_CONNECTED;
16403         case MA_AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED:     return MA_INVALID_ARGS;
16404         case MA_AUDCLNT_E_EXCLUSIVE_MODE_ONLY:          return MA_SHARE_MODE_NOT_SUPPORTED;
16405         case MA_AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL: return MA_INVALID_ARGS;
16406         case MA_AUDCLNT_E_EVENTHANDLE_NOT_SET:          return MA_INVALID_ARGS;
16407         case MA_AUDCLNT_E_INCORRECT_BUFFER_SIZE:        return MA_INVALID_ARGS;
16408         case MA_AUDCLNT_E_BUFFER_SIZE_ERROR:            return MA_INVALID_ARGS;
16409         case MA_AUDCLNT_E_CPUUSAGE_EXCEEDED:            return MA_ERROR;
16410         case MA_AUDCLNT_E_BUFFER_ERROR:                 return MA_ERROR;
16411         case MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED:      return MA_INVALID_ARGS;
16412         case MA_AUDCLNT_E_INVALID_DEVICE_PERIOD:        return MA_INVALID_ARGS;
16413         case MA_AUDCLNT_E_INVALID_STREAM_FLAG:          return MA_INVALID_ARGS;
16414         case MA_AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE: return MA_INVALID_OPERATION;
16415         case MA_AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES:     return MA_OUT_OF_MEMORY;
16416         case MA_AUDCLNT_E_OFFLOAD_MODE_ONLY:            return MA_INVALID_OPERATION;
16417         case MA_AUDCLNT_E_NONOFFLOAD_MODE_ONLY:         return MA_INVALID_OPERATION;
16418         case MA_AUDCLNT_E_RESOURCES_INVALIDATED:        return MA_INVALID_DATA;
16419         case MA_AUDCLNT_E_RAW_MODE_UNSUPPORTED:         return MA_INVALID_OPERATION;
16420         case MA_AUDCLNT_E_ENGINE_PERIODICITY_LOCKED:    return MA_INVALID_OPERATION;
16421         case MA_AUDCLNT_E_ENGINE_FORMAT_LOCKED:         return MA_INVALID_OPERATION;
16422         case MA_AUDCLNT_E_HEADTRACKING_ENABLED:         return MA_INVALID_OPERATION;
16423         case MA_AUDCLNT_E_HEADTRACKING_UNSUPPORTED:     return MA_INVALID_OPERATION;
16424         case MA_AUDCLNT_S_BUFFER_EMPTY:                 return MA_NO_SPACE;
16425         case MA_AUDCLNT_S_THREAD_ALREADY_REGISTERED:    return MA_ALREADY_EXISTS;
16426         case MA_AUDCLNT_S_POSITION_STALLED:             return MA_ERROR;
16427
16428         /* DirectSound */
16429         /*case MA_DS_OK:                                  return MA_SUCCESS;*/          /* S_OK */
16430         case MA_DS_NO_VIRTUALIZATION:                   return MA_SUCCESS;
16431         case MA_DSERR_ALLOCATED:                        return MA_ALREADY_IN_USE;
16432         case MA_DSERR_CONTROLUNAVAIL:                   return MA_INVALID_OPERATION;
16433         /*case MA_DSERR_INVALIDPARAM:                    return MA_INVALID_ARGS;*/      /* E_INVALIDARG */
16434         case MA_DSERR_INVALIDCALL:                      return MA_INVALID_OPERATION;
16435         /*case MA_DSERR_GENERIC:                          return MA_ERROR;*/            /* E_FAIL */
16436         case MA_DSERR_PRIOLEVELNEEDED:                  return MA_INVALID_OPERATION;
16437         /*case MA_DSERR_OUTOFMEMORY:                      return MA_OUT_OF_MEMORY;*/    /* E_OUTOFMEMORY */
16438         case MA_DSERR_BADFORMAT:                        return MA_FORMAT_NOT_SUPPORTED;
16439         /*case MA_DSERR_UNSUPPORTED:                      return MA_NOT_IMPLEMENTED;*/  /* E_NOTIMPL */
16440         case MA_DSERR_NODRIVER:                         return MA_FAILED_TO_INIT_BACKEND;
16441         case MA_DSERR_ALREADYINITIALIZED:               return MA_DEVICE_ALREADY_INITIALIZED;
16442         case MA_DSERR_NOAGGREGATION:                    return MA_ERROR;
16443         case MA_DSERR_BUFFERLOST:                       return MA_UNAVAILABLE;
16444         case MA_DSERR_OTHERAPPHASPRIO:                  return MA_ACCESS_DENIED;
16445         case MA_DSERR_UNINITIALIZED:                    return MA_DEVICE_NOT_INITIALIZED;
16446         /*case MA_DSERR_NOINTERFACE:                      return MA_API_NOT_FOUND;*/    /* E_NOINTERFACE */
16447         /*case MA_DSERR_ACCESSDENIED:                     return MA_ACCESS_DENIED;*/    /* E_ACCESSDENIED */
16448         case MA_DSERR_BUFFERTOOSMALL:                   return MA_NO_SPACE;
16449         case MA_DSERR_DS8_REQUIRED:                     return MA_INVALID_OPERATION;
16450         case MA_DSERR_SENDLOOP:                         return MA_DEADLOCK;
16451         case MA_DSERR_BADSENDBUFFERGUID:                return MA_INVALID_ARGS;
16452         case MA_DSERR_OBJECTNOTFOUND:                   return MA_NO_DEVICE;
16453         case MA_DSERR_FXUNAVAILABLE:                    return MA_UNAVAILABLE;
16454
16455         default:                                        return MA_ERROR;
16456     }
16457 }
16458
16459 typedef HRESULT (WINAPI * MA_PFN_CoInitializeEx)(LPVOID pvReserved, DWORD  dwCoInit);
16460 typedef void    (WINAPI * MA_PFN_CoUninitialize)(void);
16461 typedef HRESULT (WINAPI * MA_PFN_CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv);
16462 typedef void    (WINAPI * MA_PFN_CoTaskMemFree)(LPVOID pv);
16463 typedef HRESULT (WINAPI * MA_PFN_PropVariantClear)(PROPVARIANT *pvar);
16464 typedef int     (WINAPI * MA_PFN_StringFromGUID2)(const GUID* const rguid, LPOLESTR lpsz, int cchMax);
16465
16466 typedef HWND (WINAPI * MA_PFN_GetForegroundWindow)(void);
16467 typedef HWND (WINAPI * MA_PFN_GetDesktopWindow)(void);
16468
16469 /* Microsoft documents these APIs as returning LSTATUS, but the Win32 API shipping with some compilers do not define it. It's just a LONG. */
16470 typedef LONG (WINAPI * MA_PFN_RegOpenKeyExA)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
16471 typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey);
16472 typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
16473 #endif
16474
16475
16476 #define MA_DEFAULT_PLAYBACK_DEVICE_NAME    "Default Playback Device"
16477 #define MA_DEFAULT_CAPTURE_DEVICE_NAME     "Default Capture Device"
16478
16479
16480
16481
16482 /*******************************************************************************
16483
16484 Timing
16485
16486 *******************************************************************************/
16487 #ifdef MA_WIN32
16488     static LARGE_INTEGER g_ma_TimerFrequency;   /* <-- Initialized to zero since it's static. */
16489     void ma_timer_init(ma_timer* pTimer)
16490     {
16491         LARGE_INTEGER counter;
16492
16493         if (g_ma_TimerFrequency.QuadPart == 0) {
16494             QueryPerformanceFrequency(&g_ma_TimerFrequency);
16495         }
16496
16497         QueryPerformanceCounter(&counter);
16498         pTimer->counter = counter.QuadPart;
16499     }
16500
16501     double ma_timer_get_time_in_seconds(ma_timer* pTimer)
16502     {
16503         LARGE_INTEGER counter;
16504         if (!QueryPerformanceCounter(&counter)) {
16505             return 0;
16506         }
16507
16508         return (double)(counter.QuadPart - pTimer->counter) / g_ma_TimerFrequency.QuadPart;
16509     }
16510 #elif defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
16511     static ma_uint64 g_ma_TimerFrequency = 0;
16512     static void ma_timer_init(ma_timer* pTimer)
16513     {
16514         mach_timebase_info_data_t baseTime;
16515         mach_timebase_info(&baseTime);
16516         g_ma_TimerFrequency = (baseTime.denom * 1e9) / baseTime.numer;
16517
16518         pTimer->counter = mach_absolute_time();
16519     }
16520
16521     static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
16522     {
16523         ma_uint64 newTimeCounter = mach_absolute_time();
16524         ma_uint64 oldTimeCounter = pTimer->counter;
16525
16526         return (newTimeCounter - oldTimeCounter) / g_ma_TimerFrequency;
16527     }
16528 #elif defined(MA_EMSCRIPTEN)
16529     static MA_INLINE void ma_timer_init(ma_timer* pTimer)
16530     {
16531         pTimer->counterD = emscripten_get_now();
16532     }
16533
16534     static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer)
16535     {
16536         return (emscripten_get_now() - pTimer->counterD) / 1000;    /* Emscripten is in milliseconds. */
16537     }
16538 #else
16539     #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
16540         #if defined(CLOCK_MONOTONIC)
16541             #define MA_CLOCK_ID CLOCK_MONOTONIC
16542         #else
16543             #define MA_CLOCK_ID CLOCK_REALTIME
16544         #endif
16545
16546         static void ma_timer_init(ma_timer* pTimer)
16547         {
16548             struct timespec newTime;
16549             clock_gettime(MA_CLOCK_ID, &newTime);
16550
16551             pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec;
16552         }
16553
16554         static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
16555         {
16556             ma_uint64 newTimeCounter;
16557             ma_uint64 oldTimeCounter;
16558
16559             struct timespec newTime;
16560             clock_gettime(MA_CLOCK_ID, &newTime);
16561
16562             newTimeCounter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec;
16563             oldTimeCounter = pTimer->counter;
16564
16565             return (newTimeCounter - oldTimeCounter) / 1000000000.0;
16566         }
16567     #else
16568         static void ma_timer_init(ma_timer* pTimer)
16569         {
16570             struct timeval newTime;
16571             gettimeofday(&newTime, NULL);
16572
16573             pTimer->counter = (newTime.tv_sec * 1000000) + newTime.tv_usec;
16574         }
16575
16576         static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
16577         {
16578             ma_uint64 newTimeCounter;
16579             ma_uint64 oldTimeCounter;
16580
16581             struct timeval newTime;
16582             gettimeofday(&newTime, NULL);
16583
16584             newTimeCounter = (newTime.tv_sec * 1000000) + newTime.tv_usec;
16585             oldTimeCounter = pTimer->counter;
16586
16587             return (newTimeCounter - oldTimeCounter) / 1000000.0;
16588         }
16589     #endif
16590 #endif
16591
16592
16593 /*******************************************************************************
16594
16595 Dynamic Linking
16596
16597 *******************************************************************************/
16598 MA_API ma_handle ma_dlopen(ma_context* pContext, const char* filename)
16599 {
16600     ma_handle handle;
16601
16602     ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Loading library: %s\n", filename);
16603
16604 #ifdef _WIN32
16605 #ifdef MA_WIN32_DESKTOP
16606     handle = (ma_handle)LoadLibraryA(filename);
16607 #else
16608     /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */
16609     WCHAR filenameW[4096];
16610     if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) {
16611         handle = NULL;
16612     } else {
16613         handle = (ma_handle)LoadPackagedLibrary(filenameW, 0);
16614     }
16615 #endif
16616 #else
16617     handle = (ma_handle)dlopen(filename, RTLD_NOW);
16618 #endif
16619
16620     /*
16621     I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority
16622     backend is a deliberate design choice. Instead I'm logging it as an informational message.
16623     */
16624     if (handle == NULL) {
16625         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "Failed to load library: %s\n", filename);
16626     }
16627
16628     (void)pContext; /* It's possible for pContext to be unused. */
16629     return handle;
16630 }
16631
16632 MA_API void ma_dlclose(ma_context* pContext, ma_handle handle)
16633 {
16634 #ifdef _WIN32
16635     FreeLibrary((HMODULE)handle);
16636 #else
16637     dlclose((void*)handle);
16638 #endif
16639
16640     (void)pContext;
16641 }
16642
16643 MA_API ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symbol)
16644 {
16645     ma_proc proc;
16646
16647     ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Loading symbol: %s\n", symbol);
16648
16649 #ifdef _WIN32
16650     proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol);
16651 #else
16652 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
16653     #pragma GCC diagnostic push
16654     #pragma GCC diagnostic ignored "-Wpedantic"
16655 #endif
16656     proc = (ma_proc)dlsym((void*)handle, symbol);
16657 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
16658     #pragma GCC diagnostic pop
16659 #endif
16660 #endif
16661
16662     if (proc == NULL) {
16663         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Failed to load symbol: %s\n", symbol);
16664     }
16665
16666     (void)pContext; /* It's possible for pContext to be unused. */
16667     return proc;
16668 }
16669
16670
16671 #if 0
16672 static ma_uint32 ma_get_closest_standard_sample_rate(ma_uint32 sampleRateIn)
16673 {
16674     ma_uint32 closestRate = 0;
16675     ma_uint32 closestDiff = 0xFFFFFFFF;
16676     size_t iStandardRate;
16677
16678     for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) {
16679         ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate];
16680         ma_uint32 diff;
16681
16682         if (sampleRateIn > standardRate) {
16683             diff = sampleRateIn - standardRate;
16684         } else {
16685             diff = standardRate - sampleRateIn;
16686         }
16687
16688         if (diff == 0) {
16689             return standardRate;    /* The input sample rate is a standard rate. */
16690         }
16691
16692         if (closestDiff > diff) {
16693             closestDiff = diff;
16694             closestRate = standardRate;
16695         }
16696     }
16697
16698     return closestRate;
16699 }
16700 #endif
16701
16702
16703 static MA_INLINE unsigned int ma_device_disable_denormals(ma_device* pDevice)
16704 {
16705     MA_ASSERT(pDevice != NULL);
16706
16707     if (!pDevice->noDisableDenormals) {
16708         return ma_disable_denormals();
16709     } else {
16710         return 0;
16711     }
16712 }
16713
16714 static MA_INLINE void ma_device_restore_denormals(ma_device* pDevice, unsigned int prevState)
16715 {
16716     MA_ASSERT(pDevice != NULL);
16717
16718     if (!pDevice->noDisableDenormals) {
16719         ma_restore_denormals(prevState);
16720     } else {
16721         /* Do nothing. */
16722         (void)prevState;
16723     }
16724 }
16725
16726 static ma_device_notification ma_device_notification_init(ma_device* pDevice, ma_device_notification_type type)
16727 {
16728     ma_device_notification notification;
16729
16730     MA_ZERO_OBJECT(&notification);
16731     notification.pDevice = pDevice;
16732     notification.type    = type;
16733
16734     return notification;
16735 }
16736
16737 static void ma_device__on_notification(ma_device_notification notification)
16738 {
16739     MA_ASSERT(notification.pDevice != NULL);
16740
16741     if (notification.pDevice->onNotification != NULL) {
16742         notification.pDevice->onNotification(&notification);
16743     }
16744
16745     /* TEMP FOR COMPATIBILITY: If it's a stopped notification, fire the onStop callback as well. This is only for backwards compatibility and will be removed. */
16746     if (notification.pDevice->onStop != NULL && notification.type == ma_device_notification_type_stopped) {
16747         notification.pDevice->onStop(notification.pDevice);
16748     }
16749 }
16750
16751 void ma_device__on_notification_started(ma_device* pDevice)
16752 {
16753     ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_started));
16754 }
16755
16756 void ma_device__on_notification_stopped(ma_device* pDevice)
16757 {
16758     ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_stopped));
16759 }
16760
16761 void ma_device__on_notification_rerouted(ma_device* pDevice)
16762 {
16763     ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_rerouted));
16764 }
16765
16766 void ma_device__on_notification_interruption_began(ma_device* pDevice)
16767 {
16768     ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_interruption_began));
16769 }
16770
16771 void ma_device__on_notification_interruption_ended(ma_device* pDevice)
16772 {
16773     ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_interruption_ended));
16774 }
16775
16776
16777 static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
16778 {
16779     float masterVolumeFactor;
16780
16781     ma_device_get_master_volume(pDevice, &masterVolumeFactor);  /* Use ma_device_get_master_volume() to ensure the volume is loaded atomically. */
16782
16783     if (pDevice->onData) {
16784         unsigned int prevDenormalState = ma_device_disable_denormals(pDevice);
16785         {
16786             if (!pDevice->noPreSilencedOutputBuffer && pFramesOut != NULL) {
16787                 ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels);
16788             }
16789
16790             /* 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. */
16791             if (pFramesIn != NULL && masterVolumeFactor < 1) {
16792                 ma_uint8 tempFramesIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
16793                 ma_uint32 bpfCapture  = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
16794                 ma_uint32 bpfPlayback = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
16795                 ma_uint32 totalFramesProcessed = 0;
16796                 while (totalFramesProcessed < frameCount) {
16797                     ma_uint32 framesToProcessThisIteration = frameCount - totalFramesProcessed;
16798                     if (framesToProcessThisIteration > sizeof(tempFramesIn)/bpfCapture) {
16799                         framesToProcessThisIteration = sizeof(tempFramesIn)/bpfCapture;
16800                     }
16801
16802                     ma_copy_and_apply_volume_factor_pcm_frames(tempFramesIn, ma_offset_ptr(pFramesIn, totalFramesProcessed*bpfCapture), framesToProcessThisIteration, pDevice->capture.format, pDevice->capture.channels, masterVolumeFactor);
16803
16804                     pDevice->onData(pDevice, ma_offset_ptr(pFramesOut, totalFramesProcessed*bpfPlayback), tempFramesIn, framesToProcessThisIteration);
16805
16806                     totalFramesProcessed += framesToProcessThisIteration;
16807                 }
16808             } else {
16809                 pDevice->onData(pDevice, pFramesOut, pFramesIn, frameCount);
16810             }
16811
16812             /* Volume control and clipping for playback devices. */
16813             if (pFramesOut != NULL) {
16814                 if (masterVolumeFactor < 1) {
16815                     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. */
16816                         ma_apply_volume_factor_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels, masterVolumeFactor);
16817                     }
16818                 }
16819
16820                 if (!pDevice->noClip && pDevice->playback.format == ma_format_f32) {
16821                     ma_clip_samples_f32((float*)pFramesOut, (const float*)pFramesOut, frameCount * pDevice->playback.channels);   /* Intentionally specifying the same pointer for both input and output for in-place processing. */
16822                 }
16823             }
16824         }
16825         ma_device_restore_denormals(pDevice, prevDenormalState);
16826     }
16827 }
16828
16829
16830
16831 /* A helper function for reading sample data from the client. */
16832 static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 frameCount, void* pFramesOut)
16833 {
16834     MA_ASSERT(pDevice != NULL);
16835     MA_ASSERT(frameCount > 0);
16836     MA_ASSERT(pFramesOut != NULL);
16837
16838     if (pDevice->playback.converter.isPassthrough) {
16839         ma_device__on_data(pDevice, pFramesOut, NULL, frameCount);
16840     } else {
16841         ma_result result;
16842         ma_uint64 totalFramesReadOut;
16843         void* pRunningFramesOut;
16844
16845         totalFramesReadOut = 0;
16846         pRunningFramesOut  = pFramesOut;
16847
16848         /*
16849         We run slightly different logic depending on whether or not we're using a heap-allocated
16850         buffer for caching input data. This will be the case if the data converter does not have
16851         the ability to retrieve the required input frame count for a given output frame count.
16852         */
16853         if (pDevice->playback.pInputCache != NULL) {
16854             while (totalFramesReadOut < frameCount) {
16855                 ma_uint64 framesToReadThisIterationIn;
16856                 ma_uint64 framesToReadThisIterationOut;
16857
16858                 /* If there's any data available in the cache, that needs to get processed first. */
16859                 if (pDevice->playback.inputCacheRemaining > 0) {
16860                     framesToReadThisIterationOut = (frameCount - totalFramesReadOut);
16861                     framesToReadThisIterationIn  = framesToReadThisIterationOut;
16862                     if (framesToReadThisIterationIn > pDevice->playback.inputCacheRemaining) {
16863                         framesToReadThisIterationIn = pDevice->playback.inputCacheRemaining;
16864                     }
16865
16866                     result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, ma_offset_pcm_frames_ptr(pDevice->playback.pInputCache, pDevice->playback.inputCacheConsumed, pDevice->playback.format, pDevice->playback.channels), &framesToReadThisIterationIn, pRunningFramesOut, &framesToReadThisIterationOut);
16867                     if (result != MA_SUCCESS) {
16868                         break;
16869                     }
16870
16871                     pDevice->playback.inputCacheConsumed  += framesToReadThisIterationIn;
16872                     pDevice->playback.inputCacheRemaining -= framesToReadThisIterationIn;
16873
16874                     totalFramesReadOut += framesToReadThisIterationOut;
16875                     pRunningFramesOut   = ma_offset_ptr(pRunningFramesOut, framesToReadThisIterationOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
16876
16877                     if (framesToReadThisIterationIn == 0 && framesToReadThisIterationOut == 0) {
16878                         break;  /* We're done. */
16879                     }
16880                 }
16881
16882                 /* Getting here means there's no data in the cache and we need to fill it up with data from the client. */
16883                 if (pDevice->playback.inputCacheRemaining == 0) {
16884                     ma_device__on_data(pDevice, pDevice->playback.pInputCache, NULL, (ma_uint32)pDevice->playback.inputCacheCap);
16885
16886                     pDevice->playback.inputCacheConsumed  = 0;
16887                     pDevice->playback.inputCacheRemaining = pDevice->playback.inputCacheCap;
16888                 }
16889             }
16890         } else {
16891             while (totalFramesReadOut < frameCount) {
16892                 ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In client format. */
16893                 ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
16894                 ma_uint64 framesToReadThisIterationIn;
16895                 ma_uint64 framesReadThisIterationIn;
16896                 ma_uint64 framesToReadThisIterationOut;
16897                 ma_uint64 framesReadThisIterationOut;
16898                 ma_uint64 requiredInputFrameCount;
16899
16900                 framesToReadThisIterationOut = (frameCount - totalFramesReadOut);
16901                 framesToReadThisIterationIn = framesToReadThisIterationOut;
16902                 if (framesToReadThisIterationIn > intermediaryBufferCap) {
16903                     framesToReadThisIterationIn = intermediaryBufferCap;
16904                 }
16905
16906                 ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, framesToReadThisIterationOut, &requiredInputFrameCount);
16907                 if (framesToReadThisIterationIn > requiredInputFrameCount) {
16908                     framesToReadThisIterationIn = requiredInputFrameCount;
16909                 }
16910
16911                 if (framesToReadThisIterationIn > 0) {
16912                     ma_device__on_data(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn);
16913                 }
16914
16915                 /*
16916                 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
16917                 input frames, we still want to try processing frames because there may some output frames generated from cached input data.
16918                 */
16919                 framesReadThisIterationIn  = framesToReadThisIterationIn;
16920                 framesReadThisIterationOut = framesToReadThisIterationOut;
16921                 result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut);
16922                 if (result != MA_SUCCESS) {
16923                     break;
16924                 }
16925
16926                 totalFramesReadOut += framesReadThisIterationOut;
16927                 pRunningFramesOut   = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
16928
16929                 if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) {
16930                     break;  /* We're done. */
16931                 }
16932             }
16933         }
16934     }
16935 }
16936
16937 /* A helper for sending sample data to the client. */
16938 static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat)
16939 {
16940     MA_ASSERT(pDevice != NULL);
16941     MA_ASSERT(frameCountInDeviceFormat > 0);
16942     MA_ASSERT(pFramesInDeviceFormat != NULL);
16943
16944     if (pDevice->capture.converter.isPassthrough) {
16945         ma_device__on_data(pDevice, NULL, pFramesInDeviceFormat, frameCountInDeviceFormat);
16946     } else {
16947         ma_result result;
16948         ma_uint8 pFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
16949         ma_uint64 framesInClientFormatCap = sizeof(pFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
16950         ma_uint64 totalDeviceFramesProcessed = 0;
16951         ma_uint64 totalClientFramesProcessed = 0;
16952         const void* pRunningFramesInDeviceFormat = pFramesInDeviceFormat;
16953
16954         /* We just keep going until we've exhaused all of our input frames and cannot generate any more output frames. */
16955         for (;;) {
16956             ma_uint64 deviceFramesProcessedThisIteration;
16957             ma_uint64 clientFramesProcessedThisIteration;
16958
16959             deviceFramesProcessedThisIteration = (frameCountInDeviceFormat - totalDeviceFramesProcessed);
16960             clientFramesProcessedThisIteration = framesInClientFormatCap;
16961
16962             result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningFramesInDeviceFormat, &deviceFramesProcessedThisIteration, pFramesInClientFormat, &clientFramesProcessedThisIteration);
16963             if (result != MA_SUCCESS) {
16964                 break;
16965             }
16966
16967             if (clientFramesProcessedThisIteration > 0) {
16968                 ma_device__on_data(pDevice, NULL, pFramesInClientFormat, (ma_uint32)clientFramesProcessedThisIteration);    /* Safe cast. */
16969             }
16970
16971             pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, deviceFramesProcessedThisIteration * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
16972             totalDeviceFramesProcessed  += deviceFramesProcessedThisIteration;
16973             totalClientFramesProcessed  += clientFramesProcessedThisIteration;
16974
16975             if (deviceFramesProcessedThisIteration == 0 && clientFramesProcessedThisIteration == 0) {
16976                 break;  /* We're done. */
16977             }
16978         }
16979     }
16980 }
16981
16982 static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat, ma_pcm_rb* pRB)
16983 {
16984     ma_result result;
16985     ma_uint32 totalDeviceFramesProcessed = 0;
16986     const void* pRunningFramesInDeviceFormat = pFramesInDeviceFormat;
16987
16988     MA_ASSERT(pDevice != NULL);
16989     MA_ASSERT(frameCountInDeviceFormat > 0);
16990     MA_ASSERT(pFramesInDeviceFormat != NULL);
16991     MA_ASSERT(pRB != NULL);
16992
16993     /* Write to the ring buffer. The ring buffer is in the client format which means we need to convert. */
16994     for (;;) {
16995         ma_uint32 framesToProcessInDeviceFormat = (frameCountInDeviceFormat - totalDeviceFramesProcessed);
16996         ma_uint32 framesToProcessInClientFormat = MA_DATA_CONVERTER_STACK_BUFFER_SIZE / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
16997         ma_uint64 framesProcessedInDeviceFormat;
16998         ma_uint64 framesProcessedInClientFormat;
16999         void* pFramesInClientFormat;
17000
17001         result = ma_pcm_rb_acquire_write(pRB, &framesToProcessInClientFormat, &pFramesInClientFormat);
17002         if (result != MA_SUCCESS) {
17003             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer.");
17004             break;
17005         }
17006
17007         if (framesToProcessInClientFormat == 0) {
17008             if (ma_pcm_rb_pointer_distance(pRB) == (ma_int32)ma_pcm_rb_get_subbuffer_size(pRB)) {
17009                 break;  /* Overrun. Not enough room in the ring buffer for input frame. Excess frames are dropped. */
17010             }
17011         }
17012
17013         /* Convert. */
17014         framesProcessedInDeviceFormat = framesToProcessInDeviceFormat;
17015         framesProcessedInClientFormat = framesToProcessInClientFormat;
17016         result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningFramesInDeviceFormat, &framesProcessedInDeviceFormat, pFramesInClientFormat, &framesProcessedInClientFormat);
17017         if (result != MA_SUCCESS) {
17018             break;
17019         }
17020
17021         result = ma_pcm_rb_commit_write(pRB, (ma_uint32)framesProcessedInClientFormat);  /* Safe cast. */
17022         if (result != MA_SUCCESS) {
17023             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer.");
17024             break;
17025         }
17026
17027         pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, framesProcessedInDeviceFormat * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
17028         totalDeviceFramesProcessed += (ma_uint32)framesProcessedInDeviceFormat; /* Safe cast. */
17029
17030         /* We're done when we're unable to process any client nor device frames. */
17031         if (framesProcessedInClientFormat == 0 && framesProcessedInDeviceFormat == 0) {
17032             break;  /* Done. */
17033         }
17034     }
17035
17036     return MA_SUCCESS;
17037 }
17038
17039 static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, ma_uint32 frameCount, void* pFramesInInternalFormat, ma_pcm_rb* pRB)
17040 {
17041     ma_result result;
17042     ma_uint8 silentInputFrames[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17043     ma_uint32 totalFramesReadOut = 0;
17044
17045     MA_ASSERT(pDevice != NULL);
17046     MA_ASSERT(frameCount > 0);
17047     MA_ASSERT(pFramesInInternalFormat != NULL);
17048     MA_ASSERT(pRB != NULL);
17049     MA_ASSERT(pDevice->playback.pInputCache != NULL);
17050
17051     /*
17052     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
17053     the whole frameCount frames we just use silence instead for the input data.
17054     */
17055     MA_ZERO_MEMORY(silentInputFrames, sizeof(silentInputFrames));
17056
17057     while (totalFramesReadOut < frameCount && ma_device_is_started(pDevice)) {
17058         /*
17059         We should have a buffer allocated on the heap. Any playback frames still sitting in there
17060         need to be sent to the internal device before we process any more data from the client.
17061         */
17062         if (pDevice->playback.inputCacheRemaining > 0) {
17063             ma_uint64 framesConvertedIn  = pDevice->playback.inputCacheRemaining;
17064             ma_uint64 framesConvertedOut = (frameCount - totalFramesReadOut);
17065             ma_data_converter_process_pcm_frames(&pDevice->playback.converter, ma_offset_pcm_frames_ptr(pDevice->playback.pInputCache, pDevice->playback.inputCacheConsumed, pDevice->playback.format, pDevice->playback.channels), &framesConvertedIn, pFramesInInternalFormat, &framesConvertedOut);
17066
17067             pDevice->playback.inputCacheConsumed  += framesConvertedIn;
17068             pDevice->playback.inputCacheRemaining -= framesConvertedIn;
17069
17070             totalFramesReadOut        += (ma_uint32)framesConvertedOut; /* Safe cast. */
17071             pFramesInInternalFormat    = ma_offset_ptr(pFramesInInternalFormat, framesConvertedOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
17072         }
17073
17074         /* If there's no more data in the cache we'll need to fill it with some. */
17075         if (totalFramesReadOut < frameCount && pDevice->playback.inputCacheRemaining == 0) {
17076             ma_uint32 inputFrameCount;
17077             void* pInputFrames;
17078
17079             inputFrameCount = (ma_uint32)pDevice->playback.inputCacheCap;
17080             result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames);
17081             if (result == MA_SUCCESS) {
17082                 if (inputFrameCount > 0) {
17083                     ma_device__on_data(pDevice, pDevice->playback.pInputCache, pInputFrames, inputFrameCount);
17084                 } else {
17085                     if (ma_pcm_rb_pointer_distance(pRB) == 0) {
17086                         break;  /* Underrun. */
17087                     }
17088                 }
17089             } else {
17090                 /* No capture data available. Feed in silence. */
17091                 inputFrameCount = (ma_uint32)ma_min(pDevice->playback.inputCacheCap, sizeof(silentInputFrames) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels));
17092                 ma_device__on_data(pDevice, pDevice->playback.pInputCache, silentInputFrames, inputFrameCount);
17093             }
17094
17095             pDevice->playback.inputCacheConsumed  = 0;
17096             pDevice->playback.inputCacheRemaining = inputFrameCount;
17097
17098             result = ma_pcm_rb_commit_read(pRB, inputFrameCount);
17099             if (result != MA_SUCCESS) {
17100                 return result;  /* Should never happen. */
17101             }
17102         }
17103     }
17104
17105     return MA_SUCCESS;
17106 }
17107
17108 /* A helper for changing the state of the device. */
17109 static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_device_state newState)
17110 {
17111     c89atomic_exchange_i32((ma_int32*)&pDevice->state, (ma_int32)newState);
17112 }
17113
17114
17115 #ifdef MA_WIN32
17116     GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM        = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
17117     GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
17118     /*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW       = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/
17119     /*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW      = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/
17120 #endif
17121
17122
17123
17124 MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = better. */
17125 {
17126     ma_uint32 i;
17127     for (i = 0; i < ma_countof(g_maFormatPriorities); ++i) {
17128         if (g_maFormatPriorities[i] == format) {
17129             return i;
17130         }
17131     }
17132
17133     /* Getting here means the format could not be found or is equal to ma_format_unknown. */
17134     return (ma_uint32)-1;
17135 }
17136
17137 static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType);
17138
17139
17140 static ma_bool32 ma_device_descriptor_is_valid(const ma_device_descriptor* pDeviceDescriptor)
17141 {
17142     if (pDeviceDescriptor == NULL) {
17143         return MA_FALSE;
17144     }
17145
17146     if (pDeviceDescriptor->format == ma_format_unknown) {
17147         return MA_FALSE;
17148     }
17149
17150     if (pDeviceDescriptor->channels == 0 || pDeviceDescriptor->channels > MA_MAX_CHANNELS) {
17151         return MA_FALSE;
17152     }
17153
17154     if (pDeviceDescriptor->sampleRate == 0) {
17155         return MA_FALSE;
17156     }
17157
17158     return MA_TRUE;
17159 }
17160
17161
17162 static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice)
17163 {
17164     ma_result result = MA_SUCCESS;
17165     ma_bool32 exitLoop = MA_FALSE;
17166     ma_uint8  capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17167     ma_uint8  playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17168     ma_uint32 capturedDeviceDataCapInFrames = 0;
17169     ma_uint32 playbackDeviceDataCapInFrames = 0;
17170
17171     MA_ASSERT(pDevice != NULL);
17172
17173     /* Just some quick validation on the device type and the available callbacks. */
17174     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
17175         if (pDevice->pContext->callbacks.onDeviceRead == NULL) {
17176             return MA_NOT_IMPLEMENTED;
17177         }
17178
17179         capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat,  pDevice->capture.internalChannels);
17180     }
17181
17182     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
17183         if (pDevice->pContext->callbacks.onDeviceWrite == NULL) {
17184             return MA_NOT_IMPLEMENTED;
17185         }
17186
17187         playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
17188     }
17189
17190     /* NOTE: The device was started outside of this function, in the worker thread. */
17191
17192     while (ma_device_get_state(pDevice) == ma_device_state_started && !exitLoop) {
17193         switch (pDevice->type) {
17194             case ma_device_type_duplex:
17195             {
17196                 /* The process is: onDeviceRead() -> convert -> callback -> convert -> onDeviceWrite() */
17197                 ma_uint32 totalCapturedDeviceFramesProcessed = 0;
17198                 ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
17199
17200                 while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
17201                     ma_uint32 capturedDeviceFramesRemaining;
17202                     ma_uint32 capturedDeviceFramesProcessed;
17203                     ma_uint32 capturedDeviceFramesToProcess;
17204                     ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed;
17205                     if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) {
17206                         capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames;
17207                     }
17208
17209                     result = pDevice->pContext->callbacks.onDeviceRead(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess);
17210                     if (result != MA_SUCCESS) {
17211                         exitLoop = MA_TRUE;
17212                         break;
17213                     }
17214
17215                     capturedDeviceFramesRemaining = capturedDeviceFramesToProcess;
17216                     capturedDeviceFramesProcessed = 0;
17217
17218                     /* At this point we have our captured data in device format and we now need to convert it to client format. */
17219                     for (;;) {
17220                         ma_uint8  capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17221                         ma_uint8  playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17222                         ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format,  pDevice->capture.channels);
17223                         ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
17224                         ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames);
17225                         ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining;
17226                         ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat,  pDevice->capture.internalChannels));
17227
17228                         /* Convert capture data from device format to client format. */
17229                         result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration);
17230                         if (result != MA_SUCCESS) {
17231                             break;
17232                         }
17233
17234                         /*
17235                         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
17236                         which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
17237                         */
17238                         if (capturedClientFramesToProcessThisIteration == 0) {
17239                             break;
17240                         }
17241
17242                         ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration);    /* Safe cast .*/
17243
17244                         capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
17245                         capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
17246
17247                         /* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */
17248                         for (;;) {
17249                             ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration;
17250                             ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames;
17251                             result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount);
17252                             if (result != MA_SUCCESS) {
17253                                 break;
17254                             }
17255
17256                             result = pDevice->pContext->callbacks.onDeviceWrite(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL);   /* Safe cast. */
17257                             if (result != MA_SUCCESS) {
17258                                 exitLoop = MA_TRUE;
17259                                 break;
17260                             }
17261
17262                             capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount;  /* Safe cast. */
17263                             if (capturedClientFramesToProcessThisIteration == 0) {
17264                                 break;
17265                             }
17266                         }
17267
17268                         /* In case an error happened from ma_device_write__null()... */
17269                         if (result != MA_SUCCESS) {
17270                             exitLoop = MA_TRUE;
17271                             break;
17272                         }
17273                     }
17274
17275                     /* Make sure we don't get stuck in the inner loop. */
17276                     if (capturedDeviceFramesProcessed == 0) {
17277                         break;
17278                     }
17279
17280                     totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed;
17281                 }
17282             } break;
17283
17284             case ma_device_type_capture:
17285             case ma_device_type_loopback:
17286             {
17287                 ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
17288                 ma_uint32 framesReadThisPeriod = 0;
17289                 while (framesReadThisPeriod < periodSizeInFrames) {
17290                     ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
17291                     ma_uint32 framesProcessed;
17292                     ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
17293                     if (framesToReadThisIteration > capturedDeviceDataCapInFrames) {
17294                         framesToReadThisIteration = capturedDeviceDataCapInFrames;
17295                     }
17296
17297                     result = pDevice->pContext->callbacks.onDeviceRead(pDevice, capturedDeviceData, framesToReadThisIteration, &framesProcessed);
17298                     if (result != MA_SUCCESS) {
17299                         exitLoop = MA_TRUE;
17300                         break;
17301                     }
17302
17303                     /* Make sure we don't get stuck in the inner loop. */
17304                     if (framesProcessed == 0) {
17305                         break;
17306                     }
17307
17308                     ma_device__send_frames_to_client(pDevice, framesProcessed, capturedDeviceData);
17309
17310                     framesReadThisPeriod += framesProcessed;
17311                 }
17312             } break;
17313
17314             case ma_device_type_playback:
17315             {
17316                 /* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
17317                 ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
17318                 ma_uint32 framesWrittenThisPeriod = 0;
17319                 while (framesWrittenThisPeriod < periodSizeInFrames) {
17320                     ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
17321                     ma_uint32 framesProcessed;
17322                     ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
17323                     if (framesToWriteThisIteration > playbackDeviceDataCapInFrames) {
17324                         framesToWriteThisIteration = playbackDeviceDataCapInFrames;
17325                     }
17326
17327                     ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, playbackDeviceData);
17328
17329                     result = pDevice->pContext->callbacks.onDeviceWrite(pDevice, playbackDeviceData, framesToWriteThisIteration, &framesProcessed);
17330                     if (result != MA_SUCCESS) {
17331                         exitLoop = MA_TRUE;
17332                         break;
17333                     }
17334
17335                     /* Make sure we don't get stuck in the inner loop. */
17336                     if (framesProcessed == 0) {
17337                         break;
17338                     }
17339
17340                     framesWrittenThisPeriod += framesProcessed;
17341                 }
17342             } break;
17343
17344             /* Should never get here. */
17345             default: break;
17346         }
17347     }
17348
17349     return result;
17350 }
17351
17352
17353
17354 /*******************************************************************************
17355
17356 Null Backend
17357
17358 *******************************************************************************/
17359 #ifdef MA_HAS_NULL
17360
17361 #define MA_DEVICE_OP_NONE__NULL    0
17362 #define MA_DEVICE_OP_START__NULL   1
17363 #define MA_DEVICE_OP_SUSPEND__NULL 2
17364 #define MA_DEVICE_OP_KILL__NULL    3
17365
17366 static ma_thread_result MA_THREADCALL ma_device_thread__null(void* pData)
17367 {
17368     ma_device* pDevice = (ma_device*)pData;
17369     MA_ASSERT(pDevice != NULL);
17370
17371     for (;;) {  /* Keep the thread alive until the device is uninitialized. */
17372         ma_uint32 operation;
17373
17374         /* Wait for an operation to be requested. */
17375         ma_event_wait(&pDevice->null_device.operationEvent);
17376
17377         /* At this point an event should have been triggered. */
17378         operation = pDevice->null_device.operation;
17379
17380         /* Starting the device needs to put the thread into a loop. */
17381         if (operation == MA_DEVICE_OP_START__NULL) {
17382             /* Reset the timer just in case. */
17383             ma_timer_init(&pDevice->null_device.timer);
17384
17385             /* Getting here means a suspend or kill operation has been requested. */
17386             pDevice->null_device.operationResult = MA_SUCCESS;
17387             ma_event_signal(&pDevice->null_device.operationCompletionEvent);
17388             ma_semaphore_release(&pDevice->null_device.operationSemaphore);
17389             continue;
17390         }
17391
17392         /* Suspending the device means we need to stop the timer and just continue the loop. */
17393         if (operation == MA_DEVICE_OP_SUSPEND__NULL) {
17394             /* We need to add the current run time to the prior run time, then reset the timer. */
17395             pDevice->null_device.priorRunTime += ma_timer_get_time_in_seconds(&pDevice->null_device.timer);
17396             ma_timer_init(&pDevice->null_device.timer);
17397
17398             /* We're done. */
17399             pDevice->null_device.operationResult = MA_SUCCESS;
17400             ma_event_signal(&pDevice->null_device.operationCompletionEvent);
17401             ma_semaphore_release(&pDevice->null_device.operationSemaphore);
17402             continue;
17403         }
17404
17405         /* Killing the device means we need to get out of this loop so that this thread can terminate. */
17406         if (operation == MA_DEVICE_OP_KILL__NULL) {
17407             pDevice->null_device.operationResult = MA_SUCCESS;
17408             ma_event_signal(&pDevice->null_device.operationCompletionEvent);
17409             ma_semaphore_release(&pDevice->null_device.operationSemaphore);
17410             break;
17411         }
17412
17413         /* Getting a signal on a "none" operation probably means an error. Return invalid operation. */
17414         if (operation == MA_DEVICE_OP_NONE__NULL) {
17415             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). */
17416             pDevice->null_device.operationResult = MA_INVALID_OPERATION;
17417             ma_event_signal(&pDevice->null_device.operationCompletionEvent);
17418             ma_semaphore_release(&pDevice->null_device.operationSemaphore);
17419             continue;   /* Continue the loop. Don't terminate. */
17420         }
17421     }
17422
17423     return (ma_thread_result)0;
17424 }
17425
17426 static ma_result ma_device_do_operation__null(ma_device* pDevice, ma_uint32 operation)
17427 {
17428     ma_result result;
17429
17430     /*
17431     TODO: Need to review this and consider just using mutual exclusion. I think the original motivation
17432     for this was to just post the event to a queue and return immediately, but that has since changed
17433     and now this function is synchronous. I think this can be simplified to just use a mutex.
17434     */
17435
17436     /*
17437     The first thing to do is wait for an operation slot to become available. We only have a single slot for this, but we could extend this later
17438     to support queing of operations.
17439     */
17440     result = ma_semaphore_wait(&pDevice->null_device.operationSemaphore);
17441     if (result != MA_SUCCESS) {
17442         return result;  /* Failed to wait for the event. */
17443     }
17444
17445     /*
17446     When we get here it means the background thread is not referencing the operation code and it can be changed. After changing this we need to
17447     signal an event to the worker thread to let it know that it can start work.
17448     */
17449     pDevice->null_device.operation = operation;
17450
17451     /* Once the operation code has been set, the worker thread can start work. */
17452     if (ma_event_signal(&pDevice->null_device.operationEvent) != MA_SUCCESS) {
17453         return MA_ERROR;
17454     }
17455
17456     /* We want everything to be synchronous so we're going to wait for the worker thread to complete it's operation. */
17457     if (ma_event_wait(&pDevice->null_device.operationCompletionEvent) != MA_SUCCESS) {
17458         return MA_ERROR;
17459     }
17460
17461     return pDevice->null_device.operationResult;
17462 }
17463
17464 static ma_uint64 ma_device_get_total_run_time_in_frames__null(ma_device* pDevice)
17465 {
17466     ma_uint32 internalSampleRate;
17467     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
17468         internalSampleRate = pDevice->capture.internalSampleRate;
17469     } else {
17470         internalSampleRate = pDevice->playback.internalSampleRate;
17471     }
17472
17473     return (ma_uint64)((pDevice->null_device.priorRunTime + ma_timer_get_time_in_seconds(&pDevice->null_device.timer)) * internalSampleRate);
17474 }
17475
17476 static ma_result ma_context_enumerate_devices__null(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
17477 {
17478     ma_bool32 cbResult = MA_TRUE;
17479
17480     MA_ASSERT(pContext != NULL);
17481     MA_ASSERT(callback != NULL);
17482
17483     /* Playback. */
17484     if (cbResult) {
17485         ma_device_info deviceInfo;
17486         MA_ZERO_OBJECT(&deviceInfo);
17487         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Playback Device", (size_t)-1);
17488         deviceInfo.isDefault = MA_TRUE; /* Only one playback and capture device for the null backend, so might as well mark as default. */
17489         cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
17490     }
17491
17492     /* Capture. */
17493     if (cbResult) {
17494         ma_device_info deviceInfo;
17495         MA_ZERO_OBJECT(&deviceInfo);
17496         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Capture Device", (size_t)-1);
17497         deviceInfo.isDefault = MA_TRUE; /* Only one playback and capture device for the null backend, so might as well mark as default. */
17498         cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
17499     }
17500
17501     (void)cbResult; /* Silence a static analysis warning. */
17502
17503     return MA_SUCCESS;
17504 }
17505
17506 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)
17507 {
17508     MA_ASSERT(pContext != NULL);
17509
17510     if (pDeviceID != NULL && pDeviceID->nullbackend != 0) {
17511         return MA_NO_DEVICE;   /* Don't know the device. */
17512     }
17513
17514     /* Name / Description */
17515     if (deviceType == ma_device_type_playback) {
17516         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Playback Device", (size_t)-1);
17517     } else {
17518         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Capture Device", (size_t)-1);
17519     }
17520
17521     pDeviceInfo->isDefault = MA_TRUE;   /* Only one playback and capture device for the null backend, so might as well mark as default. */
17522
17523     /* Support everything on the null backend. */
17524     pDeviceInfo->nativeDataFormats[0].format     = ma_format_unknown;
17525     pDeviceInfo->nativeDataFormats[0].channels   = 0;
17526     pDeviceInfo->nativeDataFormats[0].sampleRate = 0;
17527     pDeviceInfo->nativeDataFormats[0].flags      = 0;
17528     pDeviceInfo->nativeDataFormatCount = 1;
17529
17530     (void)pContext;
17531     return MA_SUCCESS;
17532 }
17533
17534
17535 static ma_result ma_device_uninit__null(ma_device* pDevice)
17536 {
17537     MA_ASSERT(pDevice != NULL);
17538
17539     /* Keep it clean and wait for the device thread to finish before returning. */
17540     ma_device_do_operation__null(pDevice, MA_DEVICE_OP_KILL__NULL);
17541
17542     /* Wait for the thread to finish before continuing. */
17543     ma_thread_wait(&pDevice->null_device.deviceThread);
17544
17545     /* At this point the loop in the device thread is as good as terminated so we can uninitialize our events. */
17546     ma_semaphore_uninit(&pDevice->null_device.operationSemaphore);
17547     ma_event_uninit(&pDevice->null_device.operationCompletionEvent);
17548     ma_event_uninit(&pDevice->null_device.operationEvent);
17549
17550     return MA_SUCCESS;
17551 }
17552
17553 static ma_result ma_device_init__null(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
17554 {
17555     ma_result result;
17556
17557     MA_ASSERT(pDevice != NULL);
17558
17559     MA_ZERO_OBJECT(&pDevice->null_device);
17560
17561     if (pConfig->deviceType == ma_device_type_loopback) {
17562         return MA_DEVICE_TYPE_NOT_SUPPORTED;
17563     }
17564
17565     /* The null backend supports everything exactly as we specify it. */
17566     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
17567         pDescriptorCapture->format     = (pDescriptorCapture->format     != ma_format_unknown) ? pDescriptorCapture->format     : MA_DEFAULT_FORMAT;
17568         pDescriptorCapture->channels   = (pDescriptorCapture->channels   != 0)                 ? pDescriptorCapture->channels   : MA_DEFAULT_CHANNELS;
17569         pDescriptorCapture->sampleRate = (pDescriptorCapture->sampleRate != 0)                 ? pDescriptorCapture->sampleRate : MA_DEFAULT_SAMPLE_RATE;
17570
17571         if (pDescriptorCapture->channelMap[0] == MA_CHANNEL_NONE) {
17572             ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels);
17573         }
17574
17575         pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile);
17576     }
17577
17578     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
17579         pDescriptorPlayback->format     = (pDescriptorPlayback->format     != ma_format_unknown) ? pDescriptorPlayback->format     : MA_DEFAULT_FORMAT;
17580         pDescriptorPlayback->channels   = (pDescriptorPlayback->channels   != 0)                 ? pDescriptorPlayback->channels   : MA_DEFAULT_CHANNELS;
17581         pDescriptorPlayback->sampleRate = (pDescriptorPlayback->sampleRate != 0)                 ? pDescriptorPlayback->sampleRate : MA_DEFAULT_SAMPLE_RATE;
17582
17583         if (pDescriptorPlayback->channelMap[0] == MA_CHANNEL_NONE) {
17584             ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptorPlayback->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorPlayback->channels);
17585         }
17586
17587         pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
17588     }
17589
17590     /*
17591     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
17592     first period is "written" to it, and then stopped in ma_device_stop__null().
17593     */
17594     result = ma_event_init(&pDevice->null_device.operationEvent);
17595     if (result != MA_SUCCESS) {
17596         return result;
17597     }
17598
17599     result = ma_event_init(&pDevice->null_device.operationCompletionEvent);
17600     if (result != MA_SUCCESS) {
17601         return result;
17602     }
17603
17604     result = ma_semaphore_init(1, &pDevice->null_device.operationSemaphore);    /* <-- It's important that the initial value is set to 1. */
17605     if (result != MA_SUCCESS) {
17606         return result;
17607     }
17608
17609     result = ma_thread_create(&pDevice->null_device.deviceThread, pDevice->pContext->threadPriority, 0, ma_device_thread__null, pDevice, &pDevice->pContext->allocationCallbacks);
17610     if (result != MA_SUCCESS) {
17611         return result;
17612     }
17613
17614     return MA_SUCCESS;
17615 }
17616
17617 static ma_result ma_device_start__null(ma_device* pDevice)
17618 {
17619     MA_ASSERT(pDevice != NULL);
17620
17621     ma_device_do_operation__null(pDevice, MA_DEVICE_OP_START__NULL);
17622
17623     c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_TRUE);
17624     return MA_SUCCESS;
17625 }
17626
17627 static ma_result ma_device_stop__null(ma_device* pDevice)
17628 {
17629     MA_ASSERT(pDevice != NULL);
17630
17631     ma_device_do_operation__null(pDevice, MA_DEVICE_OP_SUSPEND__NULL);
17632
17633     c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_FALSE);
17634     return MA_SUCCESS;
17635 }
17636
17637 static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
17638 {
17639     ma_result result = MA_SUCCESS;
17640     ma_uint32 totalPCMFramesProcessed;
17641     ma_bool32 wasStartedOnEntry;
17642
17643     if (pFramesWritten != NULL) {
17644         *pFramesWritten = 0;
17645     }
17646
17647     wasStartedOnEntry = c89atomic_load_32(&pDevice->null_device.isStarted);
17648
17649     /* Keep going until everything has been read. */
17650     totalPCMFramesProcessed = 0;
17651     while (totalPCMFramesProcessed < frameCount) {
17652         ma_uint64 targetFrame;
17653
17654         /* If there are any frames remaining in the current period, consume those first. */
17655         if (pDevice->null_device.currentPeriodFramesRemainingPlayback > 0) {
17656             ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed);
17657             ma_uint32 framesToProcess = pDevice->null_device.currentPeriodFramesRemainingPlayback;
17658             if (framesToProcess > framesRemaining) {
17659                 framesToProcess = framesRemaining;
17660             }
17661
17662             /* We don't actually do anything with pPCMFrames, so just mark it as unused to prevent a warning. */
17663             (void)pPCMFrames;
17664
17665             pDevice->null_device.currentPeriodFramesRemainingPlayback -= framesToProcess;
17666             totalPCMFramesProcessed += framesToProcess;
17667         }
17668
17669         /* 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. */
17670         if (pDevice->null_device.currentPeriodFramesRemainingPlayback == 0) {
17671             pDevice->null_device.currentPeriodFramesRemainingPlayback = 0;
17672
17673             if (!c89atomic_load_32(&pDevice->null_device.isStarted) && !wasStartedOnEntry) {
17674                 result = ma_device_start__null(pDevice);
17675                 if (result != MA_SUCCESS) {
17676                     break;
17677                 }
17678             }
17679         }
17680
17681         /* If we've consumed the whole buffer we can return now. */
17682         MA_ASSERT(totalPCMFramesProcessed <= frameCount);
17683         if (totalPCMFramesProcessed == frameCount) {
17684             break;
17685         }
17686
17687         /* Getting here means we've still got more frames to consume, we but need to wait for it to become available. */
17688         targetFrame = pDevice->null_device.lastProcessedFramePlayback;
17689         for (;;) {
17690             ma_uint64 currentFrame;
17691
17692             /* Stop waiting if the device has been stopped. */
17693             if (!c89atomic_load_32(&pDevice->null_device.isStarted)) {
17694                 break;
17695             }
17696
17697             currentFrame = ma_device_get_total_run_time_in_frames__null(pDevice);
17698             if (currentFrame >= targetFrame) {
17699                 break;
17700             }
17701
17702             /* Getting here means we haven't yet reached the target sample, so continue waiting. */
17703             ma_sleep(10);
17704         }
17705
17706         pDevice->null_device.lastProcessedFramePlayback          += pDevice->playback.internalPeriodSizeInFrames;
17707         pDevice->null_device.currentPeriodFramesRemainingPlayback = pDevice->playback.internalPeriodSizeInFrames;
17708     }
17709
17710     if (pFramesWritten != NULL) {
17711         *pFramesWritten = totalPCMFramesProcessed;
17712     }
17713
17714     return result;
17715 }
17716
17717 static ma_result ma_device_read__null(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
17718 {
17719     ma_result result = MA_SUCCESS;
17720     ma_uint32 totalPCMFramesProcessed;
17721
17722     if (pFramesRead != NULL) {
17723         *pFramesRead = 0;
17724     }
17725
17726     /* Keep going until everything has been read. */
17727     totalPCMFramesProcessed = 0;
17728     while (totalPCMFramesProcessed < frameCount) {
17729         ma_uint64 targetFrame;
17730
17731         /* If there are any frames remaining in the current period, consume those first. */
17732         if (pDevice->null_device.currentPeriodFramesRemainingCapture > 0) {
17733             ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
17734             ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed);
17735             ma_uint32 framesToProcess = pDevice->null_device.currentPeriodFramesRemainingCapture;
17736             if (framesToProcess > framesRemaining) {
17737                 framesToProcess = framesRemaining;
17738             }
17739
17740             /* We need to ensure the output buffer is zeroed. */
17741             MA_ZERO_MEMORY(ma_offset_ptr(pPCMFrames, totalPCMFramesProcessed*bpf), framesToProcess*bpf);
17742
17743             pDevice->null_device.currentPeriodFramesRemainingCapture -= framesToProcess;
17744             totalPCMFramesProcessed += framesToProcess;
17745         }
17746
17747         /* 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. */
17748         if (pDevice->null_device.currentPeriodFramesRemainingCapture == 0) {
17749             pDevice->null_device.currentPeriodFramesRemainingCapture = 0;
17750         }
17751
17752         /* If we've consumed the whole buffer we can return now. */
17753         MA_ASSERT(totalPCMFramesProcessed <= frameCount);
17754         if (totalPCMFramesProcessed == frameCount) {
17755             break;
17756         }
17757
17758         /* Getting here means we've still got more frames to consume, we but need to wait for it to become available. */
17759         targetFrame = pDevice->null_device.lastProcessedFrameCapture + pDevice->capture.internalPeriodSizeInFrames;
17760         for (;;) {
17761             ma_uint64 currentFrame;
17762
17763             /* Stop waiting if the device has been stopped. */
17764             if (!c89atomic_load_32(&pDevice->null_device.isStarted)) {
17765                 break;
17766             }
17767
17768             currentFrame = ma_device_get_total_run_time_in_frames__null(pDevice);
17769             if (currentFrame >= targetFrame) {
17770                 break;
17771             }
17772
17773             /* Getting here means we haven't yet reached the target sample, so continue waiting. */
17774             ma_sleep(10);
17775         }
17776
17777         pDevice->null_device.lastProcessedFrameCapture          += pDevice->capture.internalPeriodSizeInFrames;
17778         pDevice->null_device.currentPeriodFramesRemainingCapture = pDevice->capture.internalPeriodSizeInFrames;
17779     }
17780
17781     if (pFramesRead != NULL) {
17782         *pFramesRead = totalPCMFramesProcessed;
17783     }
17784
17785     return result;
17786 }
17787
17788 static ma_result ma_context_uninit__null(ma_context* pContext)
17789 {
17790     MA_ASSERT(pContext != NULL);
17791     MA_ASSERT(pContext->backend == ma_backend_null);
17792
17793     (void)pContext;
17794     return MA_SUCCESS;
17795 }
17796
17797 static ma_result ma_context_init__null(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
17798 {
17799     MA_ASSERT(pContext != NULL);
17800
17801     (void)pConfig;
17802     (void)pContext;
17803
17804     pCallbacks->onContextInit             = ma_context_init__null;
17805     pCallbacks->onContextUninit           = ma_context_uninit__null;
17806     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__null;
17807     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__null;
17808     pCallbacks->onDeviceInit              = ma_device_init__null;
17809     pCallbacks->onDeviceUninit            = ma_device_uninit__null;
17810     pCallbacks->onDeviceStart             = ma_device_start__null;
17811     pCallbacks->onDeviceStop              = ma_device_stop__null;
17812     pCallbacks->onDeviceRead              = ma_device_read__null;
17813     pCallbacks->onDeviceWrite             = ma_device_write__null;
17814     pCallbacks->onDeviceDataLoop          = NULL;   /* Our backend is asynchronous with a blocking read-write API which means we can get miniaudio to deal with the audio thread. */
17815
17816     /* The null backend always works. */
17817     return MA_SUCCESS;
17818 }
17819 #endif
17820
17821
17822
17823 /*******************************************************************************
17824
17825 WIN32 COMMON
17826
17827 *******************************************************************************/
17828 #if defined(MA_WIN32)
17829 #if defined(MA_WIN32_DESKTOP)
17830     #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit)                          ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit)
17831     #define ma_CoUninitialize(pContext)                                                ((MA_PFN_CoUninitialize)pContext->win32.CoUninitialize)()
17832     #define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv)  ((MA_PFN_CoCreateInstance)pContext->win32.CoCreateInstance)(rclsid, pUnkOuter, dwClsContext, riid, ppv)
17833     #define ma_CoTaskMemFree(pContext, pv)                                             ((MA_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(pv)
17834     #define ma_PropVariantClear(pContext, pvar)                                        ((MA_PFN_PropVariantClear)pContext->win32.PropVariantClear)(pvar)
17835 #else
17836     #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit)                          CoInitializeEx(pvReserved, dwCoInit)
17837     #define ma_CoUninitialize(pContext)                                                CoUninitialize()
17838     #define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv)  CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv)
17839     #define ma_CoTaskMemFree(pContext, pv)                                             CoTaskMemFree(pv)
17840     #define ma_PropVariantClear(pContext, pvar)                                        PropVariantClear(pvar)
17841 #endif
17842
17843 #if !defined(MAXULONG_PTR) && !defined(__WATCOMC__)
17844 typedef size_t DWORD_PTR;
17845 #endif
17846
17847 #if !defined(WAVE_FORMAT_44M08)
17848 #define WAVE_FORMAT_44M08 0x00000100
17849 #define WAVE_FORMAT_44S08 0x00000200
17850 #define WAVE_FORMAT_44M16 0x00000400
17851 #define WAVE_FORMAT_44S16 0x00000800
17852 #define WAVE_FORMAT_48M08 0x00001000
17853 #define WAVE_FORMAT_48S08 0x00002000
17854 #define WAVE_FORMAT_48M16 0x00004000
17855 #define WAVE_FORMAT_48S16 0x00008000
17856 #define WAVE_FORMAT_96M08 0x00010000
17857 #define WAVE_FORMAT_96S08 0x00020000
17858 #define WAVE_FORMAT_96M16 0x00040000
17859 #define WAVE_FORMAT_96S16 0x00080000
17860 #endif
17861
17862 #ifndef SPEAKER_FRONT_LEFT
17863 #define SPEAKER_FRONT_LEFT            0x1
17864 #define SPEAKER_FRONT_RIGHT           0x2
17865 #define SPEAKER_FRONT_CENTER          0x4
17866 #define SPEAKER_LOW_FREQUENCY         0x8
17867 #define SPEAKER_BACK_LEFT             0x10
17868 #define SPEAKER_BACK_RIGHT            0x20
17869 #define SPEAKER_FRONT_LEFT_OF_CENTER  0x40
17870 #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
17871 #define SPEAKER_BACK_CENTER           0x100
17872 #define SPEAKER_SIDE_LEFT             0x200
17873 #define SPEAKER_SIDE_RIGHT            0x400
17874 #define SPEAKER_TOP_CENTER            0x800
17875 #define SPEAKER_TOP_FRONT_LEFT        0x1000
17876 #define SPEAKER_TOP_FRONT_CENTER      0x2000
17877 #define SPEAKER_TOP_FRONT_RIGHT       0x4000
17878 #define SPEAKER_TOP_BACK_LEFT         0x8000
17879 #define SPEAKER_TOP_BACK_CENTER       0x10000
17880 #define SPEAKER_TOP_BACK_RIGHT        0x20000
17881 #endif
17882
17883 /*
17884 The SDK that comes with old versions of MSVC (VC6, for example) does not appear to define WAVEFORMATEXTENSIBLE. We
17885 define our own implementation in this case.
17886 */
17887 #if (defined(_MSC_VER) && !defined(_WAVEFORMATEXTENSIBLE_)) || defined(__DMC__)
17888 typedef struct
17889 {
17890     WAVEFORMATEX Format;
17891     union
17892     {
17893         WORD wValidBitsPerSample;
17894         WORD wSamplesPerBlock;
17895         WORD wReserved;
17896     } Samples;
17897     DWORD dwChannelMask;
17898     GUID SubFormat;
17899 } WAVEFORMATEXTENSIBLE;
17900 #endif
17901
17902 #ifndef WAVE_FORMAT_EXTENSIBLE
17903 #define WAVE_FORMAT_EXTENSIBLE  0xFFFE
17904 #endif
17905
17906 #ifndef WAVE_FORMAT_IEEE_FLOAT
17907 #define WAVE_FORMAT_IEEE_FLOAT  0x0003
17908 #endif
17909
17910 /* Converts an individual Win32-style channel identifier (SPEAKER_FRONT_LEFT, etc.) to miniaudio. */
17911 static ma_uint8 ma_channel_id_to_ma__win32(DWORD id)
17912 {
17913     switch (id)
17914     {
17915         case SPEAKER_FRONT_LEFT:            return MA_CHANNEL_FRONT_LEFT;
17916         case SPEAKER_FRONT_RIGHT:           return MA_CHANNEL_FRONT_RIGHT;
17917         case SPEAKER_FRONT_CENTER:          return MA_CHANNEL_FRONT_CENTER;
17918         case SPEAKER_LOW_FREQUENCY:         return MA_CHANNEL_LFE;
17919         case SPEAKER_BACK_LEFT:             return MA_CHANNEL_BACK_LEFT;
17920         case SPEAKER_BACK_RIGHT:            return MA_CHANNEL_BACK_RIGHT;
17921         case SPEAKER_FRONT_LEFT_OF_CENTER:  return MA_CHANNEL_FRONT_LEFT_CENTER;
17922         case SPEAKER_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER;
17923         case SPEAKER_BACK_CENTER:           return MA_CHANNEL_BACK_CENTER;
17924         case SPEAKER_SIDE_LEFT:             return MA_CHANNEL_SIDE_LEFT;
17925         case SPEAKER_SIDE_RIGHT:            return MA_CHANNEL_SIDE_RIGHT;
17926         case SPEAKER_TOP_CENTER:            return MA_CHANNEL_TOP_CENTER;
17927         case SPEAKER_TOP_FRONT_LEFT:        return MA_CHANNEL_TOP_FRONT_LEFT;
17928         case SPEAKER_TOP_FRONT_CENTER:      return MA_CHANNEL_TOP_FRONT_CENTER;
17929         case SPEAKER_TOP_FRONT_RIGHT:       return MA_CHANNEL_TOP_FRONT_RIGHT;
17930         case SPEAKER_TOP_BACK_LEFT:         return MA_CHANNEL_TOP_BACK_LEFT;
17931         case SPEAKER_TOP_BACK_CENTER:       return MA_CHANNEL_TOP_BACK_CENTER;
17932         case SPEAKER_TOP_BACK_RIGHT:        return MA_CHANNEL_TOP_BACK_RIGHT;
17933         default: return 0;
17934     }
17935 }
17936
17937 /* Converts an individual miniaudio channel identifier (MA_CHANNEL_FRONT_LEFT, etc.) to Win32-style. */
17938 static DWORD ma_channel_id_to_win32(DWORD id)
17939 {
17940     switch (id)
17941     {
17942         case MA_CHANNEL_MONO:               return SPEAKER_FRONT_CENTER;
17943         case MA_CHANNEL_FRONT_LEFT:         return SPEAKER_FRONT_LEFT;
17944         case MA_CHANNEL_FRONT_RIGHT:        return SPEAKER_FRONT_RIGHT;
17945         case MA_CHANNEL_FRONT_CENTER:       return SPEAKER_FRONT_CENTER;
17946         case MA_CHANNEL_LFE:                return SPEAKER_LOW_FREQUENCY;
17947         case MA_CHANNEL_BACK_LEFT:          return SPEAKER_BACK_LEFT;
17948         case MA_CHANNEL_BACK_RIGHT:         return SPEAKER_BACK_RIGHT;
17949         case MA_CHANNEL_FRONT_LEFT_CENTER:  return SPEAKER_FRONT_LEFT_OF_CENTER;
17950         case MA_CHANNEL_FRONT_RIGHT_CENTER: return SPEAKER_FRONT_RIGHT_OF_CENTER;
17951         case MA_CHANNEL_BACK_CENTER:        return SPEAKER_BACK_CENTER;
17952         case MA_CHANNEL_SIDE_LEFT:          return SPEAKER_SIDE_LEFT;
17953         case MA_CHANNEL_SIDE_RIGHT:         return SPEAKER_SIDE_RIGHT;
17954         case MA_CHANNEL_TOP_CENTER:         return SPEAKER_TOP_CENTER;
17955         case MA_CHANNEL_TOP_FRONT_LEFT:     return SPEAKER_TOP_FRONT_LEFT;
17956         case MA_CHANNEL_TOP_FRONT_CENTER:   return SPEAKER_TOP_FRONT_CENTER;
17957         case MA_CHANNEL_TOP_FRONT_RIGHT:    return SPEAKER_TOP_FRONT_RIGHT;
17958         case MA_CHANNEL_TOP_BACK_LEFT:      return SPEAKER_TOP_BACK_LEFT;
17959         case MA_CHANNEL_TOP_BACK_CENTER:    return SPEAKER_TOP_BACK_CENTER;
17960         case MA_CHANNEL_TOP_BACK_RIGHT:     return SPEAKER_TOP_BACK_RIGHT;
17961         default: return 0;
17962     }
17963 }
17964
17965 /* Converts a channel mapping to a Win32-style channel mask. */
17966 static DWORD ma_channel_map_to_channel_mask__win32(const ma_channel* pChannelMap, ma_uint32 channels)
17967 {
17968     DWORD dwChannelMask = 0;
17969     ma_uint32 iChannel;
17970
17971     for (iChannel = 0; iChannel < channels; ++iChannel) {
17972         dwChannelMask |= ma_channel_id_to_win32(pChannelMap[iChannel]);
17973     }
17974
17975     return dwChannelMask;
17976 }
17977
17978 /* Converts a Win32-style channel mask to a miniaudio channel map. */
17979 static void ma_channel_mask_to_channel_map__win32(DWORD dwChannelMask, ma_uint32 channels, ma_channel* pChannelMap)
17980 {
17981     if (channels == 1 && dwChannelMask == 0) {
17982         pChannelMap[0] = MA_CHANNEL_MONO;
17983     } else if (channels == 2 && dwChannelMask == 0) {
17984         pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
17985         pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
17986     } else {
17987         if (channels == 1 && (dwChannelMask & SPEAKER_FRONT_CENTER) != 0) {
17988             pChannelMap[0] = MA_CHANNEL_MONO;
17989         } else {
17990             /* Just iterate over each bit. */
17991             ma_uint32 iChannel = 0;
17992             ma_uint32 iBit;
17993
17994             for (iBit = 0; iBit < 32 && iChannel < channels; ++iBit) {
17995                 DWORD bitValue = (dwChannelMask & (1UL << iBit));
17996                 if (bitValue != 0) {
17997                     /* The bit is set. */
17998                     pChannelMap[iChannel] = ma_channel_id_to_ma__win32(bitValue);
17999                     iChannel += 1;
18000                 }
18001             }
18002         }
18003     }
18004 }
18005
18006 #ifdef __cplusplus
18007 static ma_bool32 ma_is_guid_equal(const void* a, const void* b)
18008 {
18009     return IsEqualGUID(*(const GUID*)a, *(const GUID*)b);
18010 }
18011 #else
18012 #define ma_is_guid_equal(a, b) IsEqualGUID((const GUID*)a, (const GUID*)b)
18013 #endif
18014
18015 static MA_INLINE ma_bool32 ma_is_guid_null(const void* guid)
18016 {
18017     static GUID nullguid = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
18018     return ma_is_guid_equal(guid, &nullguid);
18019 }
18020
18021 static ma_format ma_format_from_WAVEFORMATEX(const WAVEFORMATEX* pWF)
18022 {
18023     MA_ASSERT(pWF != NULL);
18024
18025     if (pWF->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
18026         const WAVEFORMATEXTENSIBLE* pWFEX = (const WAVEFORMATEXTENSIBLE*)pWF;
18027         if (ma_is_guid_equal(&pWFEX->SubFormat, &MA_GUID_KSDATAFORMAT_SUBTYPE_PCM)) {
18028             if (pWFEX->Samples.wValidBitsPerSample == 32) {
18029                 return ma_format_s32;
18030             }
18031             if (pWFEX->Samples.wValidBitsPerSample == 24) {
18032                 if (pWFEX->Format.wBitsPerSample == 32) {
18033                     /*return ma_format_s24_32;*/
18034                 }
18035                 if (pWFEX->Format.wBitsPerSample == 24) {
18036                     return ma_format_s24;
18037                 }
18038             }
18039             if (pWFEX->Samples.wValidBitsPerSample == 16) {
18040                 return ma_format_s16;
18041             }
18042             if (pWFEX->Samples.wValidBitsPerSample == 8) {
18043                 return ma_format_u8;
18044             }
18045         }
18046         if (ma_is_guid_equal(&pWFEX->SubFormat, &MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
18047             if (pWFEX->Samples.wValidBitsPerSample == 32) {
18048                 return ma_format_f32;
18049             }
18050             /*
18051             if (pWFEX->Samples.wValidBitsPerSample == 64) {
18052                 return ma_format_f64;
18053             }
18054             */
18055         }
18056     } else {
18057         if (pWF->wFormatTag == WAVE_FORMAT_PCM) {
18058             if (pWF->wBitsPerSample == 32) {
18059                 return ma_format_s32;
18060             }
18061             if (pWF->wBitsPerSample == 24) {
18062                 return ma_format_s24;
18063             }
18064             if (pWF->wBitsPerSample == 16) {
18065                 return ma_format_s16;
18066             }
18067             if (pWF->wBitsPerSample == 8) {
18068                 return ma_format_u8;
18069             }
18070         }
18071         if (pWF->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
18072             if (pWF->wBitsPerSample == 32) {
18073                 return ma_format_f32;
18074             }
18075             if (pWF->wBitsPerSample == 64) {
18076                 /*return ma_format_f64;*/
18077             }
18078         }
18079     }
18080
18081     return ma_format_unknown;
18082 }
18083 #endif
18084
18085
18086 /*******************************************************************************
18087
18088 WASAPI Backend
18089
18090 *******************************************************************************/
18091 #ifdef MA_HAS_WASAPI
18092 #if 0
18093 #if defined(_MSC_VER)
18094     #pragma warning(push)
18095     #pragma warning(disable:4091)   /* 'typedef ': ignored on left of '' when no variable is declared */
18096 #endif
18097 #include <audioclient.h>
18098 #include <mmdeviceapi.h>
18099 #if defined(_MSC_VER)
18100     #pragma warning(pop)
18101 #endif
18102 #endif  /* 0 */
18103
18104 static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type deviceType);
18105
18106 /* Some compilers don't define VerifyVersionInfoW. Need to write this ourselves. */
18107 #define MA_WIN32_WINNT_VISTA    0x0600
18108 #define MA_VER_MINORVERSION     0x01
18109 #define MA_VER_MAJORVERSION     0x02
18110 #define MA_VER_SERVICEPACKMAJOR 0x20
18111 #define MA_VER_GREATER_EQUAL    0x03
18112
18113 typedef struct  {
18114     DWORD dwOSVersionInfoSize;
18115     DWORD dwMajorVersion;
18116     DWORD dwMinorVersion;
18117     DWORD dwBuildNumber;
18118     DWORD dwPlatformId;
18119     WCHAR szCSDVersion[128];
18120     WORD  wServicePackMajor;
18121     WORD  wServicePackMinor;
18122     WORD  wSuiteMask;
18123     BYTE  wProductType;
18124     BYTE  wReserved;
18125 } ma_OSVERSIONINFOEXW;
18126
18127 typedef BOOL      (WINAPI * ma_PFNVerifyVersionInfoW) (ma_OSVERSIONINFOEXW* lpVersionInfo, DWORD dwTypeMask, DWORDLONG dwlConditionMask);
18128 typedef ULONGLONG (WINAPI * ma_PFNVerSetConditionMask)(ULONGLONG dwlConditionMask, DWORD dwTypeBitMask, BYTE dwConditionMask);
18129
18130
18131 #ifndef PROPERTYKEY_DEFINED
18132 #define PROPERTYKEY_DEFINED
18133 #ifndef __WATCOMC__
18134 typedef struct
18135 {
18136     GUID fmtid;
18137     DWORD pid;
18138 } PROPERTYKEY;
18139 #endif
18140 #endif
18141
18142 /* Some compilers don't define PropVariantInit(). We just do this ourselves since it's just a memset(). */
18143 static MA_INLINE void ma_PropVariantInit(PROPVARIANT* pProp)
18144 {
18145     MA_ZERO_OBJECT(pProp);
18146 }
18147
18148
18149 static const PROPERTYKEY MA_PKEY_Device_FriendlyName             = {{0xA45C254E, 0xDF1C, 0x4EFD, {0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0}}, 14};
18150 static const PROPERTYKEY MA_PKEY_AudioEngine_DeviceFormat        = {{0xF19F064D, 0x82C,  0x4E27, {0xBC, 0x73, 0x68, 0x82, 0xA1, 0xBB, 0x8E, 0x4C}},  0};
18151
18152 static const IID MA_IID_IUnknown                                 = {0x00000000, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; /* 00000000-0000-0000-C000-000000000046 */
18153 #ifndef MA_WIN32_DESKTOP
18154 static const IID MA_IID_IAgileObject                             = {0x94EA2B94, 0xE9CC, 0x49E0, {0xC0, 0xFF, 0xEE, 0x64, 0xCA, 0x8F, 0x5B, 0x90}}; /* 94EA2B94-E9CC-49E0-C0FF-EE64CA8F5B90 */
18155 #endif
18156
18157 static const IID MA_IID_IAudioClient                             = {0x1CB9AD4C, 0xDBFA, 0x4C32, {0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2}}; /* 1CB9AD4C-DBFA-4C32-B178-C2F568A703B2 = __uuidof(IAudioClient) */
18158 static const IID MA_IID_IAudioClient2                            = {0x726778CD, 0xF60A, 0x4EDA, {0x82, 0xDE, 0xE4, 0x76, 0x10, 0xCD, 0x78, 0xAA}}; /* 726778CD-F60A-4EDA-82DE-E47610CD78AA = __uuidof(IAudioClient2) */
18159 static const IID MA_IID_IAudioClient3                            = {0x7ED4EE07, 0x8E67, 0x4CD4, {0x8C, 0x1A, 0x2B, 0x7A, 0x59, 0x87, 0xAD, 0x42}}; /* 7ED4EE07-8E67-4CD4-8C1A-2B7A5987AD42 = __uuidof(IAudioClient3) */
18160 static const IID MA_IID_IAudioRenderClient                       = {0xF294ACFC, 0x3146, 0x4483, {0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2}}; /* F294ACFC-3146-4483-A7BF-ADDCA7C260E2 = __uuidof(IAudioRenderClient) */
18161 static const IID MA_IID_IAudioCaptureClient                      = {0xC8ADBD64, 0xE71E, 0x48A0, {0xA4, 0xDE, 0x18, 0x5C, 0x39, 0x5C, 0xD3, 0x17}}; /* C8ADBD64-E71E-48A0-A4DE-185C395CD317 = __uuidof(IAudioCaptureClient) */
18162 static const IID MA_IID_IMMNotificationClient                    = {0x7991EEC9, 0x7E89, 0x4D85, {0x83, 0x90, 0x6C, 0x70, 0x3C, 0xEC, 0x60, 0xC0}}; /* 7991EEC9-7E89-4D85-8390-6C703CEC60C0 = __uuidof(IMMNotificationClient) */
18163 #ifndef MA_WIN32_DESKTOP
18164 static const IID MA_IID_DEVINTERFACE_AUDIO_RENDER                = {0xE6327CAD, 0xDCEC, 0x4949, {0xAE, 0x8A, 0x99, 0x1E, 0x97, 0x6A, 0x79, 0xD2}}; /* E6327CAD-DCEC-4949-AE8A-991E976A79D2 */
18165 static const IID MA_IID_DEVINTERFACE_AUDIO_CAPTURE               = {0x2EEF81BE, 0x33FA, 0x4800, {0x96, 0x70, 0x1C, 0xD4, 0x74, 0x97, 0x2C, 0x3F}}; /* 2EEF81BE-33FA-4800-9670-1CD474972C3F */
18166 static const IID MA_IID_IActivateAudioInterfaceCompletionHandler = {0x41D949AB, 0x9862, 0x444A, {0x80, 0xF6, 0xC2, 0x61, 0x33, 0x4D, 0xA5, 0xEB}}; /* 41D949AB-9862-444A-80F6-C261334DA5EB */
18167 #endif
18168
18169 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) */
18170 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) */
18171 #ifdef __cplusplus
18172 #define MA_CLSID_MMDeviceEnumerator MA_CLSID_MMDeviceEnumerator_Instance
18173 #define MA_IID_IMMDeviceEnumerator  MA_IID_IMMDeviceEnumerator_Instance
18174 #else
18175 #define MA_CLSID_MMDeviceEnumerator &MA_CLSID_MMDeviceEnumerator_Instance
18176 #define MA_IID_IMMDeviceEnumerator  &MA_IID_IMMDeviceEnumerator_Instance
18177 #endif
18178
18179 typedef struct ma_IUnknown                                 ma_IUnknown;
18180 #ifdef MA_WIN32_DESKTOP
18181 #define MA_MM_DEVICE_STATE_ACTIVE                          1
18182 #define MA_MM_DEVICE_STATE_DISABLED                        2
18183 #define MA_MM_DEVICE_STATE_NOTPRESENT                      4
18184 #define MA_MM_DEVICE_STATE_UNPLUGGED                       8
18185
18186 typedef struct ma_IMMDeviceEnumerator                      ma_IMMDeviceEnumerator;
18187 typedef struct ma_IMMDeviceCollection                      ma_IMMDeviceCollection;
18188 typedef struct ma_IMMDevice                                ma_IMMDevice;
18189 #else
18190 typedef struct ma_IActivateAudioInterfaceCompletionHandler ma_IActivateAudioInterfaceCompletionHandler;
18191 typedef struct ma_IActivateAudioInterfaceAsyncOperation    ma_IActivateAudioInterfaceAsyncOperation;
18192 #endif
18193 typedef struct ma_IPropertyStore                           ma_IPropertyStore;
18194 typedef struct ma_IAudioClient                             ma_IAudioClient;
18195 typedef struct ma_IAudioClient2                            ma_IAudioClient2;
18196 typedef struct ma_IAudioClient3                            ma_IAudioClient3;
18197 typedef struct ma_IAudioRenderClient                       ma_IAudioRenderClient;
18198 typedef struct ma_IAudioCaptureClient                      ma_IAudioCaptureClient;
18199
18200 typedef ma_int64                                           MA_REFERENCE_TIME;
18201
18202 #define MA_AUDCLNT_STREAMFLAGS_CROSSPROCESS                0x00010000
18203 #define MA_AUDCLNT_STREAMFLAGS_LOOPBACK                    0x00020000
18204 #define MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK               0x00040000
18205 #define MA_AUDCLNT_STREAMFLAGS_NOPERSIST                   0x00080000
18206 #define MA_AUDCLNT_STREAMFLAGS_RATEADJUST                  0x00100000
18207 #define MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY         0x08000000
18208 #define MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM              0x80000000
18209 #define MA_AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED          0x10000000
18210 #define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE               0x20000000
18211 #define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED    0x40000000
18212
18213 /* Buffer flags. */
18214 #define MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY          1
18215 #define MA_AUDCLNT_BUFFERFLAGS_SILENT                      2
18216 #define MA_AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR             4
18217
18218 typedef enum
18219 {
18220     ma_eRender  = 0,
18221     ma_eCapture = 1,
18222     ma_eAll     = 2
18223 } ma_EDataFlow;
18224
18225 typedef enum
18226 {
18227     ma_eConsole        = 0,
18228     ma_eMultimedia     = 1,
18229     ma_eCommunications = 2
18230 } ma_ERole;
18231
18232 typedef enum
18233 {
18234     MA_AUDCLNT_SHAREMODE_SHARED,
18235     MA_AUDCLNT_SHAREMODE_EXCLUSIVE
18236 } MA_AUDCLNT_SHAREMODE;
18237
18238 typedef enum
18239 {
18240     MA_AudioCategory_Other = 0  /* <-- miniaudio is only caring about Other. */
18241 } MA_AUDIO_STREAM_CATEGORY;
18242
18243 typedef struct
18244 {
18245     ma_uint32 cbSize;
18246     BOOL bIsOffload;
18247     MA_AUDIO_STREAM_CATEGORY eCategory;
18248 } ma_AudioClientProperties;
18249
18250 /* IUnknown */
18251 typedef struct
18252 {
18253     /* IUnknown */
18254     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IUnknown* pThis, const IID* const riid, void** ppObject);
18255     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IUnknown* pThis);
18256     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IUnknown* pThis);
18257 } ma_IUnknownVtbl;
18258 struct ma_IUnknown
18259 {
18260     ma_IUnknownVtbl* lpVtbl;
18261 };
18262 static MA_INLINE HRESULT ma_IUnknown_QueryInterface(ma_IUnknown* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
18263 static MA_INLINE ULONG   ma_IUnknown_AddRef(ma_IUnknown* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
18264 static MA_INLINE ULONG   ma_IUnknown_Release(ma_IUnknown* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
18265
18266 #ifdef MA_WIN32_DESKTOP
18267     /* IMMNotificationClient */
18268     typedef struct
18269     {
18270         /* IUnknown */
18271         HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject);
18272         ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IMMNotificationClient* pThis);
18273         ULONG   (STDMETHODCALLTYPE * Release)       (ma_IMMNotificationClient* pThis);
18274
18275         /* IMMNotificationClient */
18276         HRESULT (STDMETHODCALLTYPE * OnDeviceStateChanged)  (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState);
18277         HRESULT (STDMETHODCALLTYPE * OnDeviceAdded)         (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID);
18278         HRESULT (STDMETHODCALLTYPE * OnDeviceRemoved)       (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID);
18279         HRESULT (STDMETHODCALLTYPE * OnDefaultDeviceChanged)(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, LPCWSTR pDefaultDeviceID);
18280         HRESULT (STDMETHODCALLTYPE * OnPropertyValueChanged)(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key);
18281     } ma_IMMNotificationClientVtbl;
18282
18283     /* IMMDeviceEnumerator */
18284     typedef struct
18285     {
18286         /* IUnknown */
18287         HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDeviceEnumerator* pThis, const IID* const riid, void** ppObject);
18288         ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IMMDeviceEnumerator* pThis);
18289         ULONG   (STDMETHODCALLTYPE * Release)       (ma_IMMDeviceEnumerator* pThis);
18290
18291         /* IMMDeviceEnumerator */
18292         HRESULT (STDMETHODCALLTYPE * EnumAudioEndpoints)                    (ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, DWORD dwStateMask, ma_IMMDeviceCollection** ppDevices);
18293         HRESULT (STDMETHODCALLTYPE * GetDefaultAudioEndpoint)               (ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, ma_ERole role, ma_IMMDevice** ppEndpoint);
18294         HRESULT (STDMETHODCALLTYPE * GetDevice)                             (ma_IMMDeviceEnumerator* pThis, LPCWSTR pID, ma_IMMDevice** ppDevice);
18295         HRESULT (STDMETHODCALLTYPE * RegisterEndpointNotificationCallback)  (ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient);
18296         HRESULT (STDMETHODCALLTYPE * UnregisterEndpointNotificationCallback)(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient);
18297     } ma_IMMDeviceEnumeratorVtbl;
18298     struct ma_IMMDeviceEnumerator
18299     {
18300         ma_IMMDeviceEnumeratorVtbl* lpVtbl;
18301     };
18302     static MA_INLINE HRESULT ma_IMMDeviceEnumerator_QueryInterface(ma_IMMDeviceEnumerator* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
18303     static MA_INLINE ULONG   ma_IMMDeviceEnumerator_AddRef(ma_IMMDeviceEnumerator* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
18304     static MA_INLINE ULONG   ma_IMMDeviceEnumerator_Release(ma_IMMDeviceEnumerator* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
18305     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); }
18306     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); }
18307     static MA_INLINE HRESULT ma_IMMDeviceEnumerator_GetDevice(ma_IMMDeviceEnumerator* pThis, LPCWSTR pID, ma_IMMDevice** ppDevice)        { return pThis->lpVtbl->GetDevice(pThis, pID, ppDevice); }
18308     static MA_INLINE HRESULT ma_IMMDeviceEnumerator_RegisterEndpointNotificationCallback(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient) { return pThis->lpVtbl->RegisterEndpointNotificationCallback(pThis, pClient); }
18309     static MA_INLINE HRESULT ma_IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient) { return pThis->lpVtbl->UnregisterEndpointNotificationCallback(pThis, pClient); }
18310
18311
18312     /* IMMDeviceCollection */
18313     typedef struct
18314     {
18315         /* IUnknown */
18316         HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDeviceCollection* pThis, const IID* const riid, void** ppObject);
18317         ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IMMDeviceCollection* pThis);
18318         ULONG   (STDMETHODCALLTYPE * Release)       (ma_IMMDeviceCollection* pThis);
18319
18320         /* IMMDeviceCollection */
18321         HRESULT (STDMETHODCALLTYPE * GetCount)(ma_IMMDeviceCollection* pThis, UINT* pDevices);
18322         HRESULT (STDMETHODCALLTYPE * Item)    (ma_IMMDeviceCollection* pThis, UINT nDevice, ma_IMMDevice** ppDevice);
18323     } ma_IMMDeviceCollectionVtbl;
18324     struct ma_IMMDeviceCollection
18325     {
18326         ma_IMMDeviceCollectionVtbl* lpVtbl;
18327     };
18328     static MA_INLINE HRESULT ma_IMMDeviceCollection_QueryInterface(ma_IMMDeviceCollection* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
18329     static MA_INLINE ULONG   ma_IMMDeviceCollection_AddRef(ma_IMMDeviceCollection* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
18330     static MA_INLINE ULONG   ma_IMMDeviceCollection_Release(ma_IMMDeviceCollection* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
18331     static MA_INLINE HRESULT ma_IMMDeviceCollection_GetCount(ma_IMMDeviceCollection* pThis, UINT* pDevices)                               { return pThis->lpVtbl->GetCount(pThis, pDevices); }
18332     static MA_INLINE HRESULT ma_IMMDeviceCollection_Item(ma_IMMDeviceCollection* pThis, UINT nDevice, ma_IMMDevice** ppDevice)            { return pThis->lpVtbl->Item(pThis, nDevice, ppDevice); }
18333
18334
18335     /* IMMDevice */
18336     typedef struct
18337     {
18338         /* IUnknown */
18339         HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDevice* pThis, const IID* const riid, void** ppObject);
18340         ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IMMDevice* pThis);
18341         ULONG   (STDMETHODCALLTYPE * Release)       (ma_IMMDevice* pThis);
18342
18343         /* IMMDevice */
18344         HRESULT (STDMETHODCALLTYPE * Activate)         (ma_IMMDevice* pThis, const IID* const iid, DWORD dwClsCtx, PROPVARIANT* pActivationParams, void** ppInterface);
18345         HRESULT (STDMETHODCALLTYPE * OpenPropertyStore)(ma_IMMDevice* pThis, DWORD stgmAccess, ma_IPropertyStore** ppProperties);
18346         HRESULT (STDMETHODCALLTYPE * GetId)            (ma_IMMDevice* pThis, LPWSTR *pID);
18347         HRESULT (STDMETHODCALLTYPE * GetState)         (ma_IMMDevice* pThis, DWORD *pState);
18348     } ma_IMMDeviceVtbl;
18349     struct ma_IMMDevice
18350     {
18351         ma_IMMDeviceVtbl* lpVtbl;
18352     };
18353     static MA_INLINE HRESULT ma_IMMDevice_QueryInterface(ma_IMMDevice* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
18354     static MA_INLINE ULONG   ma_IMMDevice_AddRef(ma_IMMDevice* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
18355     static MA_INLINE ULONG   ma_IMMDevice_Release(ma_IMMDevice* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
18356     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); }
18357     static MA_INLINE HRESULT ma_IMMDevice_OpenPropertyStore(ma_IMMDevice* pThis, DWORD stgmAccess, ma_IPropertyStore** ppProperties) { return pThis->lpVtbl->OpenPropertyStore(pThis, stgmAccess, ppProperties); }
18358     static MA_INLINE HRESULT ma_IMMDevice_GetId(ma_IMMDevice* pThis, LPWSTR *pID)                                     { return pThis->lpVtbl->GetId(pThis, pID); }
18359     static MA_INLINE HRESULT ma_IMMDevice_GetState(ma_IMMDevice* pThis, DWORD *pState)                                { return pThis->lpVtbl->GetState(pThis, pState); }
18360 #else
18361     /* IActivateAudioInterfaceAsyncOperation */
18362     typedef struct
18363     {
18364         /* IUnknown */
18365         HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IActivateAudioInterfaceAsyncOperation* pThis, const IID* const riid, void** ppObject);
18366         ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IActivateAudioInterfaceAsyncOperation* pThis);
18367         ULONG   (STDMETHODCALLTYPE * Release)       (ma_IActivateAudioInterfaceAsyncOperation* pThis);
18368
18369         /* IActivateAudioInterfaceAsyncOperation */
18370         HRESULT (STDMETHODCALLTYPE * GetActivateResult)(ma_IActivateAudioInterfaceAsyncOperation* pThis, HRESULT *pActivateResult, ma_IUnknown** ppActivatedInterface);
18371     } ma_IActivateAudioInterfaceAsyncOperationVtbl;
18372     struct ma_IActivateAudioInterfaceAsyncOperation
18373     {
18374         ma_IActivateAudioInterfaceAsyncOperationVtbl* lpVtbl;
18375     };
18376     static MA_INLINE HRESULT ma_IActivateAudioInterfaceAsyncOperation_QueryInterface(ma_IActivateAudioInterfaceAsyncOperation* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
18377     static MA_INLINE ULONG   ma_IActivateAudioInterfaceAsyncOperation_AddRef(ma_IActivateAudioInterfaceAsyncOperation* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
18378     static MA_INLINE ULONG   ma_IActivateAudioInterfaceAsyncOperation_Release(ma_IActivateAudioInterfaceAsyncOperation* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
18379     static MA_INLINE HRESULT ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(ma_IActivateAudioInterfaceAsyncOperation* pThis, HRESULT *pActivateResult, ma_IUnknown** ppActivatedInterface) { return pThis->lpVtbl->GetActivateResult(pThis, pActivateResult, ppActivatedInterface); }
18380 #endif
18381
18382 /* IPropertyStore */
18383 typedef struct
18384 {
18385     /* IUnknown */
18386     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IPropertyStore* pThis, const IID* const riid, void** ppObject);
18387     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IPropertyStore* pThis);
18388     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IPropertyStore* pThis);
18389
18390     /* IPropertyStore */
18391     HRESULT (STDMETHODCALLTYPE * GetCount)(ma_IPropertyStore* pThis, DWORD* pPropCount);
18392     HRESULT (STDMETHODCALLTYPE * GetAt)   (ma_IPropertyStore* pThis, DWORD propIndex, PROPERTYKEY* pPropKey);
18393     HRESULT (STDMETHODCALLTYPE * GetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, PROPVARIANT* pPropVar);
18394     HRESULT (STDMETHODCALLTYPE * SetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, const PROPVARIANT* const pPropVar);
18395     HRESULT (STDMETHODCALLTYPE * Commit)  (ma_IPropertyStore* pThis);
18396 } ma_IPropertyStoreVtbl;
18397 struct ma_IPropertyStore
18398 {
18399     ma_IPropertyStoreVtbl* lpVtbl;
18400 };
18401 static MA_INLINE HRESULT ma_IPropertyStore_QueryInterface(ma_IPropertyStore* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
18402 static MA_INLINE ULONG   ma_IPropertyStore_AddRef(ma_IPropertyStore* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
18403 static MA_INLINE ULONG   ma_IPropertyStore_Release(ma_IPropertyStore* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
18404 static MA_INLINE HRESULT ma_IPropertyStore_GetCount(ma_IPropertyStore* pThis, DWORD* pPropCount)                            { return pThis->lpVtbl->GetCount(pThis, pPropCount); }
18405 static MA_INLINE HRESULT ma_IPropertyStore_GetAt(ma_IPropertyStore* pThis, DWORD propIndex, PROPERTYKEY* pPropKey)          { return pThis->lpVtbl->GetAt(pThis, propIndex, pPropKey); }
18406 static MA_INLINE HRESULT ma_IPropertyStore_GetValue(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, PROPVARIANT* pPropVar) { return pThis->lpVtbl->GetValue(pThis, pKey, pPropVar); }
18407 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); }
18408 static MA_INLINE HRESULT ma_IPropertyStore_Commit(ma_IPropertyStore* pThis)                                                 { return pThis->lpVtbl->Commit(pThis); }
18409
18410
18411 /* IAudioClient */
18412 typedef struct
18413 {
18414     /* IUnknown */
18415     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient* pThis, const IID* const riid, void** ppObject);
18416     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IAudioClient* pThis);
18417     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IAudioClient* pThis);
18418
18419     /* IAudioClient */
18420     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);
18421     HRESULT (STDMETHODCALLTYPE * GetBufferSize)    (ma_IAudioClient* pThis, ma_uint32* pNumBufferFrames);
18422     HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient* pThis, MA_REFERENCE_TIME* pLatency);
18423     HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient* pThis, ma_uint32* pNumPaddingFrames);
18424     HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch);
18425     HRESULT (STDMETHODCALLTYPE * GetMixFormat)     (ma_IAudioClient* pThis, WAVEFORMATEX** ppDeviceFormat);
18426     HRESULT (STDMETHODCALLTYPE * GetDevicePeriod)  (ma_IAudioClient* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod);
18427     HRESULT (STDMETHODCALLTYPE * Start)            (ma_IAudioClient* pThis);
18428     HRESULT (STDMETHODCALLTYPE * Stop)             (ma_IAudioClient* pThis);
18429     HRESULT (STDMETHODCALLTYPE * Reset)            (ma_IAudioClient* pThis);
18430     HRESULT (STDMETHODCALLTYPE * SetEventHandle)   (ma_IAudioClient* pThis, HANDLE eventHandle);
18431     HRESULT (STDMETHODCALLTYPE * GetService)       (ma_IAudioClient* pThis, const IID* const riid, void** pp);
18432 } ma_IAudioClientVtbl;
18433 struct ma_IAudioClient
18434 {
18435     ma_IAudioClientVtbl* lpVtbl;
18436 };
18437 static MA_INLINE HRESULT ma_IAudioClient_QueryInterface(ma_IAudioClient* pThis, const IID* const riid, void** ppObject)    { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
18438 static MA_INLINE ULONG   ma_IAudioClient_AddRef(ma_IAudioClient* pThis)                                                    { return pThis->lpVtbl->AddRef(pThis); }
18439 static MA_INLINE ULONG   ma_IAudioClient_Release(ma_IAudioClient* pThis)                                                   { return pThis->lpVtbl->Release(pThis); }
18440 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); }
18441 static MA_INLINE HRESULT ma_IAudioClient_GetBufferSize(ma_IAudioClient* pThis, ma_uint32* pNumBufferFrames)                { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); }
18442 static MA_INLINE HRESULT ma_IAudioClient_GetStreamLatency(ma_IAudioClient* pThis, MA_REFERENCE_TIME* pLatency)             { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); }
18443 static MA_INLINE HRESULT ma_IAudioClient_GetCurrentPadding(ma_IAudioClient* pThis, ma_uint32* pNumPaddingFrames)           { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); }
18444 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); }
18445 static MA_INLINE HRESULT ma_IAudioClient_GetMixFormat(ma_IAudioClient* pThis, WAVEFORMATEX** ppDeviceFormat)               { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); }
18446 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); }
18447 static MA_INLINE HRESULT ma_IAudioClient_Start(ma_IAudioClient* pThis)                                                     { return pThis->lpVtbl->Start(pThis); }
18448 static MA_INLINE HRESULT ma_IAudioClient_Stop(ma_IAudioClient* pThis)                                                      { return pThis->lpVtbl->Stop(pThis); }
18449 static MA_INLINE HRESULT ma_IAudioClient_Reset(ma_IAudioClient* pThis)                                                     { return pThis->lpVtbl->Reset(pThis); }
18450 static MA_INLINE HRESULT ma_IAudioClient_SetEventHandle(ma_IAudioClient* pThis, HANDLE eventHandle)                        { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); }
18451 static MA_INLINE HRESULT ma_IAudioClient_GetService(ma_IAudioClient* pThis, const IID* const riid, void** pp)              { return pThis->lpVtbl->GetService(pThis, riid, pp); }
18452
18453 /* IAudioClient2 */
18454 typedef struct
18455 {
18456     /* IUnknown */
18457     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient2* pThis, const IID* const riid, void** ppObject);
18458     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IAudioClient2* pThis);
18459     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IAudioClient2* pThis);
18460
18461     /* IAudioClient */
18462     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);
18463     HRESULT (STDMETHODCALLTYPE * GetBufferSize)    (ma_IAudioClient2* pThis, ma_uint32* pNumBufferFrames);
18464     HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pLatency);
18465     HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient2* pThis, ma_uint32* pNumPaddingFrames);
18466     HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch);
18467     HRESULT (STDMETHODCALLTYPE * GetMixFormat)     (ma_IAudioClient2* pThis, WAVEFORMATEX** ppDeviceFormat);
18468     HRESULT (STDMETHODCALLTYPE * GetDevicePeriod)  (ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod);
18469     HRESULT (STDMETHODCALLTYPE * Start)            (ma_IAudioClient2* pThis);
18470     HRESULT (STDMETHODCALLTYPE * Stop)             (ma_IAudioClient2* pThis);
18471     HRESULT (STDMETHODCALLTYPE * Reset)            (ma_IAudioClient2* pThis);
18472     HRESULT (STDMETHODCALLTYPE * SetEventHandle)   (ma_IAudioClient2* pThis, HANDLE eventHandle);
18473     HRESULT (STDMETHODCALLTYPE * GetService)       (ma_IAudioClient2* pThis, const IID* const riid, void** pp);
18474
18475     /* IAudioClient2 */
18476     HRESULT (STDMETHODCALLTYPE * IsOffloadCapable)   (ma_IAudioClient2* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable);
18477     HRESULT (STDMETHODCALLTYPE * SetClientProperties)(ma_IAudioClient2* pThis, const ma_AudioClientProperties* pProperties);
18478     HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient2* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration);
18479 } ma_IAudioClient2Vtbl;
18480 struct ma_IAudioClient2
18481 {
18482     ma_IAudioClient2Vtbl* lpVtbl;
18483 };
18484 static MA_INLINE HRESULT ma_IAudioClient2_QueryInterface(ma_IAudioClient2* pThis, const IID* const riid, void** ppObject)    { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
18485 static MA_INLINE ULONG   ma_IAudioClient2_AddRef(ma_IAudioClient2* pThis)                                                    { return pThis->lpVtbl->AddRef(pThis); }
18486 static MA_INLINE ULONG   ma_IAudioClient2_Release(ma_IAudioClient2* pThis)                                                   { return pThis->lpVtbl->Release(pThis); }
18487 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); }
18488 static MA_INLINE HRESULT ma_IAudioClient2_GetBufferSize(ma_IAudioClient2* pThis, ma_uint32* pNumBufferFrames)                { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); }
18489 static MA_INLINE HRESULT ma_IAudioClient2_GetStreamLatency(ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pLatency)             { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); }
18490 static MA_INLINE HRESULT ma_IAudioClient2_GetCurrentPadding(ma_IAudioClient2* pThis, ma_uint32* pNumPaddingFrames)           { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); }
18491 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); }
18492 static MA_INLINE HRESULT ma_IAudioClient2_GetMixFormat(ma_IAudioClient2* pThis, WAVEFORMATEX** ppDeviceFormat)               { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); }
18493 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); }
18494 static MA_INLINE HRESULT ma_IAudioClient2_Start(ma_IAudioClient2* pThis)                                                     { return pThis->lpVtbl->Start(pThis); }
18495 static MA_INLINE HRESULT ma_IAudioClient2_Stop(ma_IAudioClient2* pThis)                                                      { return pThis->lpVtbl->Stop(pThis); }
18496 static MA_INLINE HRESULT ma_IAudioClient2_Reset(ma_IAudioClient2* pThis)                                                     { return pThis->lpVtbl->Reset(pThis); }
18497 static MA_INLINE HRESULT ma_IAudioClient2_SetEventHandle(ma_IAudioClient2* pThis, HANDLE eventHandle)                        { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); }
18498 static MA_INLINE HRESULT ma_IAudioClient2_GetService(ma_IAudioClient2* pThis, const IID* const riid, void** pp)              { return pThis->lpVtbl->GetService(pThis, riid, pp); }
18499 static MA_INLINE HRESULT ma_IAudioClient2_IsOffloadCapable(ma_IAudioClient2* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable) { return pThis->lpVtbl->IsOffloadCapable(pThis, category, pOffloadCapable); }
18500 static MA_INLINE HRESULT ma_IAudioClient2_SetClientProperties(ma_IAudioClient2* pThis, const ma_AudioClientProperties* pProperties)           { return pThis->lpVtbl->SetClientProperties(pThis, pProperties); }
18501 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); }
18502
18503
18504 /* IAudioClient3 */
18505 typedef struct
18506 {
18507     /* IUnknown */
18508     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient3* pThis, const IID* const riid, void** ppObject);
18509     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IAudioClient3* pThis);
18510     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IAudioClient3* pThis);
18511
18512     /* IAudioClient */
18513     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);
18514     HRESULT (STDMETHODCALLTYPE * GetBufferSize)    (ma_IAudioClient3* pThis, ma_uint32* pNumBufferFrames);
18515     HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pLatency);
18516     HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient3* pThis, ma_uint32* pNumPaddingFrames);
18517     HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch);
18518     HRESULT (STDMETHODCALLTYPE * GetMixFormat)     (ma_IAudioClient3* pThis, WAVEFORMATEX** ppDeviceFormat);
18519     HRESULT (STDMETHODCALLTYPE * GetDevicePeriod)  (ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod);
18520     HRESULT (STDMETHODCALLTYPE * Start)            (ma_IAudioClient3* pThis);
18521     HRESULT (STDMETHODCALLTYPE * Stop)             (ma_IAudioClient3* pThis);
18522     HRESULT (STDMETHODCALLTYPE * Reset)            (ma_IAudioClient3* pThis);
18523     HRESULT (STDMETHODCALLTYPE * SetEventHandle)   (ma_IAudioClient3* pThis, HANDLE eventHandle);
18524     HRESULT (STDMETHODCALLTYPE * GetService)       (ma_IAudioClient3* pThis, const IID* const riid, void** pp);
18525
18526     /* IAudioClient2 */
18527     HRESULT (STDMETHODCALLTYPE * IsOffloadCapable)   (ma_IAudioClient3* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable);
18528     HRESULT (STDMETHODCALLTYPE * SetClientProperties)(ma_IAudioClient3* pThis, const ma_AudioClientProperties* pProperties);
18529     HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration);
18530
18531     /* IAudioClient3 */
18532     HRESULT (STDMETHODCALLTYPE * GetSharedModeEnginePeriod)       (ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, ma_uint32* pDefaultPeriodInFrames, ma_uint32* pFundamentalPeriodInFrames, ma_uint32* pMinPeriodInFrames, ma_uint32* pMaxPeriodInFrames);
18533     HRESULT (STDMETHODCALLTYPE * GetCurrentSharedModeEnginePeriod)(ma_IAudioClient3* pThis, WAVEFORMATEX** ppFormat, ma_uint32* pCurrentPeriodInFrames);
18534     HRESULT (STDMETHODCALLTYPE * InitializeSharedAudioStream)     (ma_IAudioClient3* pThis, DWORD streamFlags, ma_uint32 periodInFrames, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid);
18535 } ma_IAudioClient3Vtbl;
18536 struct ma_IAudioClient3
18537 {
18538     ma_IAudioClient3Vtbl* lpVtbl;
18539 };
18540 static MA_INLINE HRESULT ma_IAudioClient3_QueryInterface(ma_IAudioClient3* pThis, const IID* const riid, void** ppObject)    { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
18541 static MA_INLINE ULONG   ma_IAudioClient3_AddRef(ma_IAudioClient3* pThis)                                                    { return pThis->lpVtbl->AddRef(pThis); }
18542 static MA_INLINE ULONG   ma_IAudioClient3_Release(ma_IAudioClient3* pThis)                                                   { return pThis->lpVtbl->Release(pThis); }
18543 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); }
18544 static MA_INLINE HRESULT ma_IAudioClient3_GetBufferSize(ma_IAudioClient3* pThis, ma_uint32* pNumBufferFrames)                { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); }
18545 static MA_INLINE HRESULT ma_IAudioClient3_GetStreamLatency(ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pLatency)             { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); }
18546 static MA_INLINE HRESULT ma_IAudioClient3_GetCurrentPadding(ma_IAudioClient3* pThis, ma_uint32* pNumPaddingFrames)           { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); }
18547 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); }
18548 static MA_INLINE HRESULT ma_IAudioClient3_GetMixFormat(ma_IAudioClient3* pThis, WAVEFORMATEX** ppDeviceFormat)               { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); }
18549 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); }
18550 static MA_INLINE HRESULT ma_IAudioClient3_Start(ma_IAudioClient3* pThis)                                                     { return pThis->lpVtbl->Start(pThis); }
18551 static MA_INLINE HRESULT ma_IAudioClient3_Stop(ma_IAudioClient3* pThis)                                                      { return pThis->lpVtbl->Stop(pThis); }
18552 static MA_INLINE HRESULT ma_IAudioClient3_Reset(ma_IAudioClient3* pThis)                                                     { return pThis->lpVtbl->Reset(pThis); }
18553 static MA_INLINE HRESULT ma_IAudioClient3_SetEventHandle(ma_IAudioClient3* pThis, HANDLE eventHandle)                        { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); }
18554 static MA_INLINE HRESULT ma_IAudioClient3_GetService(ma_IAudioClient3* pThis, const IID* const riid, void** pp)              { return pThis->lpVtbl->GetService(pThis, riid, pp); }
18555 static MA_INLINE HRESULT ma_IAudioClient3_IsOffloadCapable(ma_IAudioClient3* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable) { return pThis->lpVtbl->IsOffloadCapable(pThis, category, pOffloadCapable); }
18556 static MA_INLINE HRESULT ma_IAudioClient3_SetClientProperties(ma_IAudioClient3* pThis, const ma_AudioClientProperties* pProperties)           { return pThis->lpVtbl->SetClientProperties(pThis, pProperties); }
18557 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); }
18558 static MA_INLINE HRESULT ma_IAudioClient3_GetSharedModeEnginePeriod(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, ma_uint32* pDefaultPeriodInFrames, ma_uint32* pFundamentalPeriodInFrames, ma_uint32* pMinPeriodInFrames, ma_uint32* pMaxPeriodInFrames) { return pThis->lpVtbl->GetSharedModeEnginePeriod(pThis, pFormat, pDefaultPeriodInFrames, pFundamentalPeriodInFrames, pMinPeriodInFrames, pMaxPeriodInFrames); }
18559 static MA_INLINE HRESULT ma_IAudioClient3_GetCurrentSharedModeEnginePeriod(ma_IAudioClient3* pThis, WAVEFORMATEX** ppFormat, ma_uint32* pCurrentPeriodInFrames) { return pThis->lpVtbl->GetCurrentSharedModeEnginePeriod(pThis, ppFormat, pCurrentPeriodInFrames); }
18560 static MA_INLINE HRESULT ma_IAudioClient3_InitializeSharedAudioStream(ma_IAudioClient3* pThis, DWORD streamFlags, ma_uint32 periodInFrames, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGUID) { return pThis->lpVtbl->InitializeSharedAudioStream(pThis, streamFlags, periodInFrames, pFormat, pAudioSessionGUID); }
18561
18562
18563 /* IAudioRenderClient */
18564 typedef struct
18565 {
18566     /* IUnknown */
18567     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioRenderClient* pThis, const IID* const riid, void** ppObject);
18568     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IAudioRenderClient* pThis);
18569     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IAudioRenderClient* pThis);
18570
18571     /* IAudioRenderClient */
18572     HRESULT (STDMETHODCALLTYPE * GetBuffer)    (ma_IAudioRenderClient* pThis, ma_uint32 numFramesRequested, BYTE** ppData);
18573     HRESULT (STDMETHODCALLTYPE * ReleaseBuffer)(ma_IAudioRenderClient* pThis, ma_uint32 numFramesWritten, DWORD dwFlags);
18574 } ma_IAudioRenderClientVtbl;
18575 struct ma_IAudioRenderClient
18576 {
18577     ma_IAudioRenderClientVtbl* lpVtbl;
18578 };
18579 static MA_INLINE HRESULT ma_IAudioRenderClient_QueryInterface(ma_IAudioRenderClient* pThis, const IID* const riid, void** ppObject)   { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
18580 static MA_INLINE ULONG   ma_IAudioRenderClient_AddRef(ma_IAudioRenderClient* pThis)                                                   { return pThis->lpVtbl->AddRef(pThis); }
18581 static MA_INLINE ULONG   ma_IAudioRenderClient_Release(ma_IAudioRenderClient* pThis)                                                  { return pThis->lpVtbl->Release(pThis); }
18582 static MA_INLINE HRESULT ma_IAudioRenderClient_GetBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesRequested, BYTE** ppData)   { return pThis->lpVtbl->GetBuffer(pThis, numFramesRequested, ppData); }
18583 static MA_INLINE HRESULT ma_IAudioRenderClient_ReleaseBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesWritten, DWORD dwFlags) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesWritten, dwFlags); }
18584
18585
18586 /* IAudioCaptureClient */
18587 typedef struct
18588 {
18589     /* IUnknown */
18590     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject);
18591     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IAudioCaptureClient* pThis);
18592     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IAudioCaptureClient* pThis);
18593
18594     /* IAudioRenderClient */
18595     HRESULT (STDMETHODCALLTYPE * GetBuffer)        (ma_IAudioCaptureClient* pThis, BYTE** ppData, ma_uint32* pNumFramesToRead, DWORD* pFlags, ma_uint64* pDevicePosition, ma_uint64* pQPCPosition);
18596     HRESULT (STDMETHODCALLTYPE * ReleaseBuffer)    (ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead);
18597     HRESULT (STDMETHODCALLTYPE * GetNextPacketSize)(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket);
18598 } ma_IAudioCaptureClientVtbl;
18599 struct ma_IAudioCaptureClient
18600 {
18601     ma_IAudioCaptureClientVtbl* lpVtbl;
18602 };
18603 static MA_INLINE HRESULT ma_IAudioCaptureClient_QueryInterface(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
18604 static MA_INLINE ULONG   ma_IAudioCaptureClient_AddRef(ma_IAudioCaptureClient* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
18605 static MA_INLINE ULONG   ma_IAudioCaptureClient_Release(ma_IAudioCaptureClient* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
18606 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); }
18607 static MA_INLINE HRESULT ma_IAudioCaptureClient_ReleaseBuffer(ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead)                 { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesRead); }
18608 static MA_INLINE HRESULT ma_IAudioCaptureClient_GetNextPacketSize(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket)   { return pThis->lpVtbl->GetNextPacketSize(pThis, pNumFramesInNextPacket); }
18609
18610 #ifndef MA_WIN32_DESKTOP
18611 #include <mmdeviceapi.h>
18612 typedef struct ma_completion_handler_uwp ma_completion_handler_uwp;
18613
18614 typedef struct
18615 {
18616     /* IUnknown */
18617     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject);
18618     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_completion_handler_uwp* pThis);
18619     ULONG   (STDMETHODCALLTYPE * Release)       (ma_completion_handler_uwp* pThis);
18620
18621     /* IActivateAudioInterfaceCompletionHandler */
18622     HRESULT (STDMETHODCALLTYPE * ActivateCompleted)(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation);
18623 } ma_completion_handler_uwp_vtbl;
18624 struct ma_completion_handler_uwp
18625 {
18626     ma_completion_handler_uwp_vtbl* lpVtbl;
18627     MA_ATOMIC(4, ma_uint32) counter;
18628     HANDLE hEvent;
18629 };
18630
18631 static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_QueryInterface(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject)
18632 {
18633     /*
18634     We need to "implement" IAgileObject which is just an indicator that's used internally by WASAPI for some multithreading management. To
18635     "implement" this, we just make sure we return pThis when the IAgileObject is requested.
18636     */
18637     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)) {
18638         *ppObject = NULL;
18639         return E_NOINTERFACE;
18640     }
18641
18642     /* Getting here means the IID is IUnknown or IMMNotificationClient. */
18643     *ppObject = (void*)pThis;
18644     ((ma_completion_handler_uwp_vtbl*)pThis->lpVtbl)->AddRef(pThis);
18645     return S_OK;
18646 }
18647
18648 static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_AddRef(ma_completion_handler_uwp* pThis)
18649 {
18650     return (ULONG)c89atomic_fetch_add_32(&pThis->counter, 1) + 1;
18651 }
18652
18653 static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_Release(ma_completion_handler_uwp* pThis)
18654 {
18655     ma_uint32 newRefCount = c89atomic_fetch_sub_32(&pThis->counter, 1) - 1;
18656     if (newRefCount == 0) {
18657         return 0;   /* We don't free anything here because we never allocate the object on the heap. */
18658     }
18659
18660     return (ULONG)newRefCount;
18661 }
18662
18663 static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_ActivateCompleted(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation)
18664 {
18665     (void)pActivateOperation;
18666     SetEvent(pThis->hEvent);
18667     return S_OK;
18668 }
18669
18670
18671 static ma_completion_handler_uwp_vtbl g_maCompletionHandlerVtblInstance = {
18672     ma_completion_handler_uwp_QueryInterface,
18673     ma_completion_handler_uwp_AddRef,
18674     ma_completion_handler_uwp_Release,
18675     ma_completion_handler_uwp_ActivateCompleted
18676 };
18677
18678 static ma_result ma_completion_handler_uwp_init(ma_completion_handler_uwp* pHandler)
18679 {
18680     MA_ASSERT(pHandler != NULL);
18681     MA_ZERO_OBJECT(pHandler);
18682
18683     pHandler->lpVtbl = &g_maCompletionHandlerVtblInstance;
18684     pHandler->counter = 1;
18685     pHandler->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
18686     if (pHandler->hEvent == NULL) {
18687         return ma_result_from_GetLastError(GetLastError());
18688     }
18689
18690     return MA_SUCCESS;
18691 }
18692
18693 static void ma_completion_handler_uwp_uninit(ma_completion_handler_uwp* pHandler)
18694 {
18695     if (pHandler->hEvent != NULL) {
18696         CloseHandle(pHandler->hEvent);
18697     }
18698 }
18699
18700 static void ma_completion_handler_uwp_wait(ma_completion_handler_uwp* pHandler)
18701 {
18702     WaitForSingleObject(pHandler->hEvent, INFINITE);
18703 }
18704 #endif  /* !MA_WIN32_DESKTOP */
18705
18706 /* We need a virtual table for our notification client object that's used for detecting changes to the default device. */
18707 #ifdef MA_WIN32_DESKTOP
18708 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_QueryInterface(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject)
18709 {
18710     /*
18711     We care about two interfaces - IUnknown and IMMNotificationClient. If the requested IID is something else
18712     we just return E_NOINTERFACE. Otherwise we need to increment the reference counter and return S_OK.
18713     */
18714     if (!ma_is_guid_equal(riid, &MA_IID_IUnknown) && !ma_is_guid_equal(riid, &MA_IID_IMMNotificationClient)) {
18715         *ppObject = NULL;
18716         return E_NOINTERFACE;
18717     }
18718
18719     /* Getting here means the IID is IUnknown or IMMNotificationClient. */
18720     *ppObject = (void*)pThis;
18721     ((ma_IMMNotificationClientVtbl*)pThis->lpVtbl)->AddRef(pThis);
18722     return S_OK;
18723 }
18724
18725 static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_AddRef(ma_IMMNotificationClient* pThis)
18726 {
18727     return (ULONG)c89atomic_fetch_add_32(&pThis->counter, 1) + 1;
18728 }
18729
18730 static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_Release(ma_IMMNotificationClient* pThis)
18731 {
18732     ma_uint32 newRefCount = c89atomic_fetch_sub_32(&pThis->counter, 1) - 1;
18733     if (newRefCount == 0) {
18734         return 0;   /* We don't free anything here because we never allocate the object on the heap. */
18735     }
18736
18737     return (ULONG)newRefCount;
18738 }
18739
18740 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState)
18741 {
18742     ma_bool32 isThisDevice = MA_FALSE;
18743     ma_bool32 isCapture    = MA_FALSE;
18744     ma_bool32 isPlayback   = MA_FALSE;
18745
18746 #ifdef MA_DEBUG_OUTPUT
18747     /*ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "IMMNotificationClient_OnDeviceStateChanged(pDeviceID=%S, dwNewState=%u)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)", (unsigned int)dwNewState);*/
18748 #endif
18749
18750     /*
18751     There have been reports of a hang when a playback device is disconnected. The idea with this code is to explicitly stop the device if we detect
18752     that the device is disabled or has been unplugged.
18753     */
18754     if (pThis->pDevice->wasapi.allowCaptureAutoStreamRouting && (pThis->pDevice->type == ma_device_type_capture || pThis->pDevice->type == ma_device_type_duplex || pThis->pDevice->type == ma_device_type_loopback)) {
18755         isCapture = MA_TRUE;
18756         if (wcscmp(pThis->pDevice->capture.id.wasapi, pDeviceID) == 0) {
18757             isThisDevice = MA_TRUE;
18758         }
18759     }
18760
18761     if (pThis->pDevice->wasapi.allowPlaybackAutoStreamRouting && (pThis->pDevice->type == ma_device_type_playback || pThis->pDevice->type == ma_device_type_duplex)) {
18762         isPlayback = MA_TRUE;
18763         if (wcscmp(pThis->pDevice->playback.id.wasapi, pDeviceID) == 0) {
18764             isThisDevice = MA_TRUE;
18765         }
18766     }
18767
18768
18769     /*
18770     If the device ID matches our device we need to mark our device as detached and stop it. When a
18771     device is added in OnDeviceAdded(), we'll restart it. We only mark it as detached if the device
18772     was started at the time of being removed.
18773     */
18774     if (isThisDevice) {
18775         if ((dwNewState & MA_MM_DEVICE_STATE_ACTIVE) == 0) {
18776             /*
18777             Unplugged or otherwise unavailable. Mark as detached if we were in a playing state. We'll
18778             use this to determine whether or not we need to automatically start the device when it's
18779             plugged back in again.
18780             */
18781             if (ma_device_get_state(pThis->pDevice) == ma_device_state_started) {
18782                 if (isPlayback) {
18783                     pThis->pDevice->wasapi.isDetachedPlayback = MA_TRUE;
18784                 }
18785                 if (isCapture) {
18786                     pThis->pDevice->wasapi.isDetachedCapture = MA_TRUE;
18787                 }
18788
18789                 ma_device_stop(pThis->pDevice);
18790             }
18791         }
18792
18793         if ((dwNewState & MA_MM_DEVICE_STATE_ACTIVE) != 0) {
18794             /* The device was activated. If we were detached, we need to start it again. */
18795             ma_bool8 tryRestartingDevice = MA_FALSE;
18796
18797             if (isPlayback) {
18798                 if (pThis->pDevice->wasapi.isDetachedPlayback) {
18799                     pThis->pDevice->wasapi.isDetachedPlayback = MA_FALSE;
18800                     ma_device_reroute__wasapi(pThis->pDevice, ma_device_type_playback);
18801                     tryRestartingDevice = MA_TRUE;
18802                 }
18803             }
18804
18805             if (isCapture) {
18806                 if (pThis->pDevice->wasapi.isDetachedCapture) {
18807                     pThis->pDevice->wasapi.isDetachedCapture = MA_FALSE;
18808                     ma_device_reroute__wasapi(pThis->pDevice, (pThis->pDevice->type == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture);
18809                     tryRestartingDevice = MA_TRUE;
18810                 }
18811             }
18812
18813             if (tryRestartingDevice) {
18814                 if (pThis->pDevice->wasapi.isDetachedPlayback == MA_FALSE && pThis->pDevice->wasapi.isDetachedCapture == MA_FALSE) {
18815                     ma_device_start(pThis->pDevice);
18816                 }
18817             }
18818         }
18819     }
18820
18821     return S_OK;
18822 }
18823
18824 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceAdded(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
18825 {
18826 #ifdef MA_DEBUG_OUTPUT
18827     /*ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "IMMNotificationClient_OnDeviceAdded(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/
18828 #endif
18829
18830     /* We don't need to worry about this event for our purposes. */
18831     (void)pThis;
18832     (void)pDeviceID;
18833     return S_OK;
18834 }
18835
18836 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceRemoved(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
18837 {
18838 #ifdef MA_DEBUG_OUTPUT
18839     /*ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "IMMNotificationClient_OnDeviceRemoved(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/
18840 #endif
18841
18842     /* We don't need to worry about this event for our purposes. */
18843     (void)pThis;
18844     (void)pDeviceID;
18845     return S_OK;
18846 }
18847
18848 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, LPCWSTR pDefaultDeviceID)
18849 {
18850 #ifdef MA_DEBUG_OUTPUT
18851     /*ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "IMMNotificationClient_OnDefaultDeviceChanged(dataFlow=%d, role=%d, pDefaultDeviceID=%S)\n", dataFlow, role, (pDefaultDeviceID != NULL) ? pDefaultDeviceID : L"(NULL)");*/
18852 #endif
18853
18854     /* We only ever use the eConsole role in miniaudio. */
18855     if (role != ma_eConsole) {
18856         ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting: role != eConsole\n");
18857         return S_OK;
18858     }
18859
18860     /* We only care about devices with the same data flow and role as the current device. */
18861     if ((pThis->pDevice->type == ma_device_type_playback && dataFlow != ma_eRender) ||
18862         (pThis->pDevice->type == ma_device_type_capture  && dataFlow != ma_eCapture)) {
18863         ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because dataFlow does match device type.\n");
18864         return S_OK;
18865     }
18866
18867     /* Don't do automatic stream routing if we're not allowed. */
18868     if ((dataFlow == ma_eRender  && pThis->pDevice->wasapi.allowPlaybackAutoStreamRouting == MA_FALSE) ||
18869         (dataFlow == ma_eCapture && pThis->pDevice->wasapi.allowCaptureAutoStreamRouting  == MA_FALSE)) {
18870         ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because automatic stream routing has been disabled by the device config.\n");
18871         return S_OK;
18872     }
18873
18874     /*
18875     Not currently supporting automatic stream routing in exclusive mode. This is not working correctly on my machine due to
18876     AUDCLNT_E_DEVICE_IN_USE errors when reinitializing the device. If this is a bug in miniaudio, we can try re-enabling this once
18877     it's fixed.
18878     */
18879     if ((dataFlow == ma_eRender  && pThis->pDevice->playback.shareMode == ma_share_mode_exclusive) ||
18880         (dataFlow == ma_eCapture && pThis->pDevice->capture.shareMode  == ma_share_mode_exclusive)) {
18881         ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Stream rerouting abandoned because the device shared mode is exclusive.\n");
18882         return S_OK;
18883     }
18884
18885
18886
18887
18888     /*
18889     Second attempt at device rerouting. We're going to retrieve the device's state at the time of
18890     the route change. We're then going to stop the device, reinitialize the device, and then start
18891     it again if the state before stopping was ma_device_state_started.
18892     */
18893     {
18894         ma_uint32 previousState = ma_device_get_state(pThis->pDevice);
18895         ma_bool8 restartDevice = MA_FALSE;
18896
18897         if (previousState == ma_device_state_started) {
18898             ma_device_stop(pThis->pDevice);
18899             restartDevice = MA_TRUE;
18900         }
18901
18902         if (pDefaultDeviceID != NULL) { /* <-- The input device ID will be null if there's no other device available. */
18903             if (dataFlow == ma_eRender) {
18904                 ma_device_reroute__wasapi(pThis->pDevice, ma_device_type_playback);
18905
18906                 if (pThis->pDevice->wasapi.isDetachedPlayback) {
18907                     pThis->pDevice->wasapi.isDetachedPlayback = MA_FALSE;
18908
18909                     if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedCapture) {
18910                         restartDevice = MA_FALSE;   /* It's a duplex device and the capture side is detached. We cannot be restarting the device just yet. */
18911                     } else {
18912                         restartDevice = MA_TRUE;    /* It's not a duplex device, or the capture side is also attached so we can go ahead and restart the device. */
18913                     }
18914                 }
18915             } else {
18916                 ma_device_reroute__wasapi(pThis->pDevice, (pThis->pDevice->type == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture);
18917
18918                 if (pThis->pDevice->wasapi.isDetachedCapture) {
18919                     pThis->pDevice->wasapi.isDetachedCapture = MA_FALSE;
18920
18921                     if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedPlayback) {
18922                         restartDevice = MA_FALSE;   /* It's a duplex device and the playback side is detached. We cannot be restarting the device just yet. */
18923                     } else {
18924                         restartDevice = MA_TRUE;    /* It's not a duplex device, or the playback side is also attached so we can go ahead and restart the device. */
18925                     }
18926                 }
18927             }
18928
18929             if (restartDevice) {
18930                 ma_device_start(pThis->pDevice);
18931             }
18932         }
18933     }
18934
18935     return S_OK;
18936 }
18937
18938 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnPropertyValueChanged(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key)
18939 {
18940 #ifdef MA_DEBUG_OUTPUT
18941     /*ma_log_postf(ma_device_get_log(pThis->pDevice), MA_LOG_LEVEL_DEBUG, "IMMNotificationClient_OnPropertyValueChanged(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/
18942 #endif
18943
18944     (void)pThis;
18945     (void)pDeviceID;
18946     (void)key;
18947     return S_OK;
18948 }
18949
18950 static ma_IMMNotificationClientVtbl g_maNotificationCientVtbl = {
18951     ma_IMMNotificationClient_QueryInterface,
18952     ma_IMMNotificationClient_AddRef,
18953     ma_IMMNotificationClient_Release,
18954     ma_IMMNotificationClient_OnDeviceStateChanged,
18955     ma_IMMNotificationClient_OnDeviceAdded,
18956     ma_IMMNotificationClient_OnDeviceRemoved,
18957     ma_IMMNotificationClient_OnDefaultDeviceChanged,
18958     ma_IMMNotificationClient_OnPropertyValueChanged
18959 };
18960 #endif  /* MA_WIN32_DESKTOP */
18961
18962 #ifdef MA_WIN32_DESKTOP
18963 typedef ma_IMMDevice ma_WASAPIDeviceInterface;
18964 #else
18965 typedef ma_IUnknown ma_WASAPIDeviceInterface;
18966 #endif
18967
18968
18969 #define MA_CONTEXT_COMMAND_QUIT__WASAPI                 1
18970 #define MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI  2
18971 #define MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI 3
18972
18973 static ma_context_command__wasapi ma_context_init_command__wasapi(int code)
18974 {
18975     ma_context_command__wasapi cmd;
18976
18977     MA_ZERO_OBJECT(&cmd);
18978     cmd.code = code;
18979
18980     return cmd;
18981 }
18982
18983 static ma_result ma_context_post_command__wasapi(ma_context* pContext, const ma_context_command__wasapi* pCmd)
18984 {
18985     /* For now we are doing everything synchronously, but I might relax this later if the need arises. */
18986     ma_result result;
18987     ma_bool32 isUsingLocalEvent = MA_FALSE;
18988     ma_event localEvent;
18989
18990     MA_ASSERT(pContext != NULL);
18991     MA_ASSERT(pCmd     != NULL);
18992
18993     if (pCmd->pEvent == NULL) {
18994         isUsingLocalEvent = MA_TRUE;
18995
18996         result = ma_event_init(&localEvent);
18997         if (result != MA_SUCCESS) {
18998             return result;  /* Failed to create the event for this command. */
18999         }
19000     }
19001
19002     /* Here is where we add the command to the list. If there's not enough room we'll spin until there is. */
19003     ma_mutex_lock(&pContext->wasapi.commandLock);
19004     {
19005         ma_uint32 index;
19006
19007         /* Spin until we've got some space available. */
19008         while (pContext->wasapi.commandCount == ma_countof(pContext->wasapi.commands)) {
19009             ma_yield();
19010         }
19011
19012         /* Space is now available. Can safely add to the list. */
19013         index = (pContext->wasapi.commandIndex + pContext->wasapi.commandCount) % ma_countof(pContext->wasapi.commands);
19014         pContext->wasapi.commands[index]        = *pCmd;
19015         pContext->wasapi.commands[index].pEvent = &localEvent;
19016         pContext->wasapi.commandCount += 1;
19017
19018         /* Now that the command has been added, release the semaphore so ma_context_next_command__wasapi() can return. */
19019         ma_semaphore_release(&pContext->wasapi.commandSem);
19020     }
19021     ma_mutex_unlock(&pContext->wasapi.commandLock);
19022
19023     if (isUsingLocalEvent) {
19024         ma_event_wait(&localEvent);
19025         ma_event_uninit(&localEvent);
19026     }
19027
19028     return MA_SUCCESS;
19029 }
19030
19031 static ma_result ma_context_next_command__wasapi(ma_context* pContext, ma_context_command__wasapi* pCmd)
19032 {
19033     ma_result result = MA_SUCCESS;
19034
19035     MA_ASSERT(pContext != NULL);
19036     MA_ASSERT(pCmd     != NULL);
19037
19038     result = ma_semaphore_wait(&pContext->wasapi.commandSem);
19039     if (result == MA_SUCCESS) {
19040         ma_mutex_lock(&pContext->wasapi.commandLock);
19041         {
19042             *pCmd = pContext->wasapi.commands[pContext->wasapi.commandIndex];
19043             pContext->wasapi.commandIndex  = (pContext->wasapi.commandIndex + 1) % ma_countof(pContext->wasapi.commands);
19044             pContext->wasapi.commandCount -= 1;
19045         }
19046         ma_mutex_unlock(&pContext->wasapi.commandLock);
19047     }
19048
19049     return result;
19050 }
19051
19052 static ma_thread_result MA_THREADCALL ma_context_command_thread__wasapi(void* pUserData)
19053 {
19054     ma_result result;
19055     ma_context* pContext = (ma_context*)pUserData;
19056     MA_ASSERT(pContext != NULL);
19057
19058     for (;;) {
19059         ma_context_command__wasapi cmd;
19060         result = ma_context_next_command__wasapi(pContext, &cmd);
19061         if (result != MA_SUCCESS) {
19062             break;
19063         }
19064
19065         switch (cmd.code)
19066         {
19067             case MA_CONTEXT_COMMAND_QUIT__WASAPI:
19068             {
19069                 /* Do nothing. Handled after the switch. */
19070             } break;
19071
19072             case MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI:
19073             {
19074                 if (cmd.data.createAudioClient.deviceType == ma_device_type_playback) {
19075                     *cmd.data.createAudioClient.pResult = ma_result_from_HRESULT(ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioRenderClient, cmd.data.createAudioClient.ppAudioClientService));
19076                 } else {
19077                     *cmd.data.createAudioClient.pResult = ma_result_from_HRESULT(ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioCaptureClient, cmd.data.createAudioClient.ppAudioClientService));
19078                 }
19079             } break;
19080
19081             case MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI:
19082             {
19083                 if (cmd.data.releaseAudioClient.deviceType == ma_device_type_playback) {
19084                     if (cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientPlayback != NULL) {
19085                         ma_IAudioClient_Release((ma_IAudioClient*)cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientPlayback);
19086                         cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientPlayback = NULL;
19087                     }
19088                 }
19089
19090                 if (cmd.data.releaseAudioClient.deviceType == ma_device_type_capture) {
19091                     if (cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientCapture != NULL) {
19092                         ma_IAudioClient_Release((ma_IAudioClient*)cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientCapture);
19093                         cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientCapture = NULL;
19094                     }
19095                 }
19096             } break;
19097
19098             default:
19099             {
19100                 /* Unknown command. Ignore it, but trigger an assert in debug mode so we're aware of it. */
19101                 MA_ASSERT(MA_FALSE);
19102             } break;
19103         }
19104
19105         if (cmd.pEvent != NULL) {
19106             ma_event_signal(cmd.pEvent);
19107         }
19108
19109         if (cmd.code == MA_CONTEXT_COMMAND_QUIT__WASAPI) {
19110             break;  /* Received a quit message. Get out of here. */
19111         }
19112     }
19113
19114     return (ma_thread_result)0;
19115 }
19116
19117 static ma_result ma_device_create_IAudioClient_service__wasapi(ma_context* pContext, ma_device_type deviceType, ma_IAudioClient* pAudioClient, void** ppAudioClientService)
19118 {
19119     ma_result result;
19120     ma_result cmdResult;
19121     ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI);
19122     cmd.data.createAudioClient.deviceType           = deviceType;
19123     cmd.data.createAudioClient.pAudioClient         = (void*)pAudioClient;
19124     cmd.data.createAudioClient.ppAudioClientService = ppAudioClientService;
19125     cmd.data.createAudioClient.pResult              = &cmdResult;   /* Declared locally, but won't be dereferenced after this function returns since execution of the command will wait here. */
19126
19127     result = ma_context_post_command__wasapi(pContext, &cmd);  /* This will not return until the command has actually been run. */
19128     if (result != MA_SUCCESS) {
19129         return result;
19130     }
19131
19132     return *cmd.data.createAudioClient.pResult;
19133 }
19134
19135 #if 0   /* Not used at the moment, but leaving here for future use. */
19136 static ma_result ma_device_release_IAudioClient_service__wasapi(ma_device* pDevice, ma_device_type deviceType)
19137 {
19138     ma_result result;
19139     ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI);
19140     cmd.data.releaseAudioClient.pDevice    = pDevice;
19141     cmd.data.releaseAudioClient.deviceType = deviceType;
19142
19143     result = ma_context_post_command__wasapi(pDevice->pContext, &cmd);  /* This will not return until the command has actually been run. */
19144     if (result != MA_SUCCESS) {
19145         return result;
19146     }
19147
19148     return MA_SUCCESS;
19149 }
19150 #endif
19151
19152
19153 static void ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(const WAVEFORMATEX* pWF, ma_share_mode shareMode, ma_device_info* pInfo)
19154 {
19155     MA_ASSERT(pWF != NULL);
19156     MA_ASSERT(pInfo != NULL);
19157
19158     if (pInfo->nativeDataFormatCount >= ma_countof(pInfo->nativeDataFormats)) {
19159         return; /* Too many data formats. Need to ignore this one. Don't think this should ever happen with WASAPI. */
19160     }
19161
19162     pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].format     = ma_format_from_WAVEFORMATEX(pWF);
19163     pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].channels   = pWF->nChannels;
19164     pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].sampleRate = pWF->nSamplesPerSec;
19165     pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].flags      = (shareMode == ma_share_mode_exclusive) ? MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE : 0;
19166     pInfo->nativeDataFormatCount += 1;
19167 }
19168
19169 static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context* pContext, /*ma_IMMDevice**/void* pMMDevice, ma_IAudioClient* pAudioClient, ma_device_info* pInfo)
19170 {
19171     HRESULT hr;
19172     WAVEFORMATEX* pWF = NULL;
19173
19174     MA_ASSERT(pAudioClient != NULL);
19175     MA_ASSERT(pInfo != NULL);
19176
19177     /* Shared Mode. We use GetMixFormat() here. */
19178     hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pAudioClient, (WAVEFORMATEX**)&pWF);
19179     if (SUCCEEDED(hr)) {
19180         ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(pWF, ma_share_mode_shared, pInfo);
19181     } else {
19182         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve mix format for device info retrieval.");
19183         return ma_result_from_HRESULT(hr);
19184     }
19185
19186     /*
19187     Exlcusive Mode. We repeatedly call IsFormatSupported() here. This is not currently supported on
19188     UWP. Failure to retrieve the exclusive mode format is not considered an error, so from here on
19189     out, MA_SUCCESS is guaranteed to be returned.
19190     */
19191     #ifdef MA_WIN32_DESKTOP
19192     {
19193         ma_IPropertyStore *pProperties;
19194
19195         /*
19196         The first thing to do is get the format from PKEY_AudioEngine_DeviceFormat. This should give us a channel count we assume is
19197         correct which will simplify our searching.
19198         */
19199         hr = ma_IMMDevice_OpenPropertyStore((ma_IMMDevice*)pMMDevice, STGM_READ, &pProperties);
19200         if (SUCCEEDED(hr)) {
19201             PROPVARIANT var;
19202             ma_PropVariantInit(&var);
19203
19204             hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_AudioEngine_DeviceFormat, &var);
19205             if (SUCCEEDED(hr)) {
19206                 pWF = (WAVEFORMATEX*)var.blob.pBlobData;
19207
19208                 /*
19209                 In my testing, the format returned by PKEY_AudioEngine_DeviceFormat is suitable for exclusive mode so we check this format
19210                 first. If this fails, fall back to a search.
19211                 */
19212                 hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pWF, NULL);
19213                 if (SUCCEEDED(hr)) {
19214                     /* The format returned by PKEY_AudioEngine_DeviceFormat is supported. */
19215                     ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(pWF, ma_share_mode_exclusive, pInfo);
19216                 } else {
19217                     /*
19218                     The format returned by PKEY_AudioEngine_DeviceFormat is not supported, so fall back to a search. We assume the channel
19219                     count returned by MA_PKEY_AudioEngine_DeviceFormat is valid and correct. For simplicity we're only returning one format.
19220                     */
19221                     ma_uint32 channels = pWF->nChannels;
19222                     ma_channel defaultChannelMap[MA_MAX_CHANNELS];
19223                     WAVEFORMATEXTENSIBLE wf;
19224                     ma_bool32 found;
19225                     ma_uint32 iFormat;
19226
19227                     /* Make sure we don't overflow the channel map. */
19228                     if (channels > MA_MAX_CHANNELS) {
19229                         channels = MA_MAX_CHANNELS;
19230                     }
19231
19232                     ma_channel_map_init_standard(ma_standard_channel_map_microsoft, defaultChannelMap, ma_countof(defaultChannelMap), channels);
19233
19234                     MA_ZERO_OBJECT(&wf);
19235                     wf.Format.cbSize     = sizeof(wf);
19236                     wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
19237                     wf.Format.nChannels  = (WORD)channels;
19238                     wf.dwChannelMask     = ma_channel_map_to_channel_mask__win32(defaultChannelMap, channels);
19239
19240                     found = MA_FALSE;
19241                     for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); ++iFormat) {
19242                         ma_format format = g_maFormatPriorities[iFormat];
19243                         ma_uint32 iSampleRate;
19244
19245                         wf.Format.wBitsPerSample       = (WORD)(ma_get_bytes_per_sample(format)*8);
19246                         wf.Format.nBlockAlign          = (WORD)(wf.Format.nChannels * wf.Format.wBitsPerSample / 8);
19247                         wf.Format.nAvgBytesPerSec      = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
19248                         wf.Samples.wValidBitsPerSample = /*(format == ma_format_s24_32) ? 24 :*/ wf.Format.wBitsPerSample;
19249                         if (format == ma_format_f32) {
19250                             wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
19251                         } else {
19252                             wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
19253                         }
19254
19255                         for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); ++iSampleRate) {
19256                             wf.Format.nSamplesPerSec = g_maStandardSampleRatePriorities[iSampleRate];
19257
19258                             hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wf, NULL);
19259                             if (SUCCEEDED(hr)) {
19260                                 ma_add_native_data_format_to_device_info_from_WAVEFORMATEX((WAVEFORMATEX*)&wf, ma_share_mode_exclusive, pInfo);
19261                                 found = MA_TRUE;
19262                                 break;
19263                             }
19264                         }
19265
19266                         if (found) {
19267                             break;
19268                         }
19269                     }
19270
19271                     ma_PropVariantClear(pContext, &var);
19272
19273                     if (!found) {
19274                         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to find suitable device format for device info retrieval.");
19275                     }
19276                 }
19277             } else {
19278                 ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to retrieve device format for device info retrieval.");
19279             }
19280
19281             ma_IPropertyStore_Release(pProperties);
19282         } else {
19283             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to open property store for device info retrieval.");
19284         }
19285     }
19286     #endif
19287
19288     return MA_SUCCESS;
19289 }
19290
19291 #ifdef MA_WIN32_DESKTOP
19292 static ma_EDataFlow ma_device_type_to_EDataFlow(ma_device_type deviceType)
19293 {
19294     if (deviceType == ma_device_type_playback) {
19295         return ma_eRender;
19296     } else if (deviceType == ma_device_type_capture) {
19297         return ma_eCapture;
19298     } else {
19299         MA_ASSERT(MA_FALSE);
19300         return ma_eRender; /* Should never hit this. */
19301     }
19302 }
19303
19304 static ma_result ma_context_create_IMMDeviceEnumerator__wasapi(ma_context* pContext, ma_IMMDeviceEnumerator** ppDeviceEnumerator)
19305 {
19306     HRESULT hr;
19307     ma_IMMDeviceEnumerator* pDeviceEnumerator;
19308
19309     MA_ASSERT(pContext           != NULL);
19310     MA_ASSERT(ppDeviceEnumerator != NULL);
19311
19312     *ppDeviceEnumerator = NULL; /* Safety. */
19313
19314     hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
19315     if (FAILED(hr)) {
19316         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.");
19317         return ma_result_from_HRESULT(hr);
19318     }
19319
19320     *ppDeviceEnumerator = pDeviceEnumerator;
19321
19322     return MA_SUCCESS;
19323 }
19324
19325 static LPWSTR ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(ma_context* pContext, ma_IMMDeviceEnumerator* pDeviceEnumerator, ma_device_type deviceType)
19326 {
19327     HRESULT hr;
19328     ma_IMMDevice* pMMDefaultDevice = NULL;
19329     LPWSTR pDefaultDeviceID = NULL;
19330     ma_EDataFlow dataFlow;
19331     ma_ERole role;
19332
19333     MA_ASSERT(pContext          != NULL);
19334     MA_ASSERT(pDeviceEnumerator != NULL);
19335
19336     (void)pContext;
19337
19338     /* Grab the EDataFlow type from the device type. */
19339     dataFlow = ma_device_type_to_EDataFlow(deviceType);
19340
19341     /* The role is always eConsole, but we may make this configurable later. */
19342     role = ma_eConsole;
19343
19344     hr = ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator, dataFlow, role, &pMMDefaultDevice);
19345     if (FAILED(hr)) {
19346         return NULL;
19347     }
19348
19349     hr = ma_IMMDevice_GetId(pMMDefaultDevice, &pDefaultDeviceID);
19350
19351     ma_IMMDevice_Release(pMMDefaultDevice);
19352     pMMDefaultDevice = NULL;
19353
19354     if (FAILED(hr)) {
19355         return NULL;
19356     }
19357
19358     return pDefaultDeviceID;
19359 }
19360
19361 static LPWSTR ma_context_get_default_device_id__wasapi(ma_context* pContext, ma_device_type deviceType)    /* Free the returned pointer with ma_CoTaskMemFree() */
19362 {
19363     ma_result result;
19364     ma_IMMDeviceEnumerator* pDeviceEnumerator;
19365     LPWSTR pDefaultDeviceID = NULL;
19366
19367     MA_ASSERT(pContext != NULL);
19368
19369     result = ma_context_create_IMMDeviceEnumerator__wasapi(pContext, &pDeviceEnumerator);
19370     if (result != MA_SUCCESS) {
19371         return NULL;
19372     }
19373
19374     pDefaultDeviceID = ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(pContext, pDeviceEnumerator, deviceType);
19375
19376     ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
19377     return pDefaultDeviceID;
19378 }
19379
19380 static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IMMDevice** ppMMDevice)
19381 {
19382     ma_IMMDeviceEnumerator* pDeviceEnumerator;
19383     HRESULT hr;
19384
19385     MA_ASSERT(pContext != NULL);
19386     MA_ASSERT(ppMMDevice != NULL);
19387
19388     hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
19389     if (FAILED(hr)) {
19390         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.");
19391         return ma_result_from_HRESULT(hr);
19392     }
19393
19394     if (pDeviceID == NULL) {
19395         hr = ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator, (deviceType == ma_device_type_capture) ? ma_eCapture : ma_eRender, ma_eConsole, ppMMDevice);
19396     } else {
19397         hr = ma_IMMDeviceEnumerator_GetDevice(pDeviceEnumerator, pDeviceID->wasapi, ppMMDevice);
19398     }
19399
19400     ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
19401     if (FAILED(hr)) {
19402         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve IMMDevice.");
19403         return ma_result_from_HRESULT(hr);
19404     }
19405
19406     return MA_SUCCESS;
19407 }
19408
19409 static ma_result ma_context_get_device_id_from_MMDevice__wasapi(ma_context* pContext, ma_IMMDevice* pMMDevice, ma_device_id* pDeviceID)
19410 {
19411     LPWSTR pDeviceIDString;
19412     HRESULT hr;
19413
19414     MA_ASSERT(pDeviceID != NULL);
19415
19416     hr = ma_IMMDevice_GetId(pMMDevice, &pDeviceIDString);
19417     if (SUCCEEDED(hr)) {
19418         size_t idlen = wcslen(pDeviceIDString);
19419         if (idlen+1 > ma_countof(pDeviceID->wasapi)) {
19420             ma_CoTaskMemFree(pContext, pDeviceIDString);
19421             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. */
19422             return MA_ERROR;
19423         }
19424
19425         MA_COPY_MEMORY(pDeviceID->wasapi, pDeviceIDString, idlen * sizeof(wchar_t));
19426         pDeviceID->wasapi[idlen] = '\0';
19427
19428         ma_CoTaskMemFree(pContext, pDeviceIDString);
19429
19430         return MA_SUCCESS;
19431     }
19432
19433     return MA_ERROR;
19434 }
19435
19436 static ma_result ma_context_get_device_info_from_MMDevice__wasapi(ma_context* pContext, ma_IMMDevice* pMMDevice, LPWSTR pDefaultDeviceID, ma_bool32 onlySimpleInfo, ma_device_info* pInfo)
19437 {
19438     ma_result result;
19439     HRESULT hr;
19440
19441     MA_ASSERT(pContext != NULL);
19442     MA_ASSERT(pMMDevice != NULL);
19443     MA_ASSERT(pInfo != NULL);
19444
19445     /* ID. */
19446     result = ma_context_get_device_id_from_MMDevice__wasapi(pContext, pMMDevice, &pInfo->id);
19447     if (result == MA_SUCCESS) {
19448         if (pDefaultDeviceID != NULL) {
19449             if (wcscmp(pInfo->id.wasapi, pDefaultDeviceID) == 0) {
19450                 pInfo->isDefault = MA_TRUE;
19451             }
19452         }
19453     }
19454
19455     /* Description / Friendly Name */
19456     {
19457         ma_IPropertyStore *pProperties;
19458         hr = ma_IMMDevice_OpenPropertyStore(pMMDevice, STGM_READ, &pProperties);
19459         if (SUCCEEDED(hr)) {
19460             PROPVARIANT var;
19461
19462             ma_PropVariantInit(&var);
19463             hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &var);
19464             if (SUCCEEDED(hr)) {
19465                 WideCharToMultiByte(CP_UTF8, 0, var.pwszVal, -1, pInfo->name, sizeof(pInfo->name), 0, FALSE);
19466                 ma_PropVariantClear(pContext, &var);
19467             }
19468
19469             ma_IPropertyStore_Release(pProperties);
19470         }
19471     }
19472
19473     /* Format */
19474     if (!onlySimpleInfo) {
19475         ma_IAudioClient* pAudioClient;
19476         hr = ma_IMMDevice_Activate(pMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);
19477         if (SUCCEEDED(hr)) {
19478             result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, pMMDevice, pAudioClient, pInfo);
19479
19480             ma_IAudioClient_Release(pAudioClient);
19481             return result;
19482         } else {
19483             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate audio client for device info retrieval.");
19484             return ma_result_from_HRESULT(hr);
19485         }
19486     }
19487
19488     return MA_SUCCESS;
19489 }
19490
19491 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)
19492 {
19493     ma_result result = MA_SUCCESS;
19494     UINT deviceCount;
19495     HRESULT hr;
19496     ma_uint32 iDevice;
19497     LPWSTR pDefaultDeviceID = NULL;
19498     ma_IMMDeviceCollection* pDeviceCollection = NULL;
19499
19500     MA_ASSERT(pContext != NULL);
19501     MA_ASSERT(callback != NULL);
19502
19503     /* Grab the default device. We use this to know whether or not flag the returned device info as being the default. */
19504     pDefaultDeviceID = ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(pContext, pDeviceEnumerator, deviceType);
19505
19506     /* We need to enumerate the devices which returns a device collection. */
19507     hr = ma_IMMDeviceEnumerator_EnumAudioEndpoints(pDeviceEnumerator, ma_device_type_to_EDataFlow(deviceType), MA_MM_DEVICE_STATE_ACTIVE, &pDeviceCollection);
19508     if (SUCCEEDED(hr)) {
19509         hr = ma_IMMDeviceCollection_GetCount(pDeviceCollection, &deviceCount);
19510         if (FAILED(hr)) {
19511             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to get device count.");
19512             result = ma_result_from_HRESULT(hr);
19513             goto done;
19514         }
19515
19516         for (iDevice = 0; iDevice < deviceCount; ++iDevice) {
19517             ma_device_info deviceInfo;
19518             ma_IMMDevice* pMMDevice;
19519
19520             MA_ZERO_OBJECT(&deviceInfo);
19521
19522             hr = ma_IMMDeviceCollection_Item(pDeviceCollection, iDevice, &pMMDevice);
19523             if (SUCCEEDED(hr)) {
19524                 result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, pDefaultDeviceID, MA_TRUE, &deviceInfo);   /* MA_TRUE = onlySimpleInfo. */
19525
19526                 ma_IMMDevice_Release(pMMDevice);
19527                 if (result == MA_SUCCESS) {
19528                     ma_bool32 cbResult = callback(pContext, deviceType, &deviceInfo, pUserData);
19529                     if (cbResult == MA_FALSE) {
19530                         break;
19531                     }
19532                 }
19533             }
19534         }
19535     }
19536
19537 done:
19538     if (pDefaultDeviceID != NULL) {
19539         ma_CoTaskMemFree(pContext, pDefaultDeviceID);
19540         pDefaultDeviceID = NULL;
19541     }
19542
19543     if (pDeviceCollection != NULL) {
19544         ma_IMMDeviceCollection_Release(pDeviceCollection);
19545         pDeviceCollection = NULL;
19546     }
19547
19548     return result;
19549 }
19550
19551 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)
19552 {
19553     ma_result result;
19554     HRESULT hr;
19555
19556     MA_ASSERT(pContext != NULL);
19557     MA_ASSERT(ppAudioClient != NULL);
19558     MA_ASSERT(ppMMDevice != NULL);
19559
19560     result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, ppMMDevice);
19561     if (result != MA_SUCCESS) {
19562         return result;
19563     }
19564
19565     hr = ma_IMMDevice_Activate(*ppMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)ppAudioClient);
19566     if (FAILED(hr)) {
19567         return ma_result_from_HRESULT(hr);
19568     }
19569
19570     return MA_SUCCESS;
19571 }
19572 #else
19573 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)
19574 {
19575     ma_IActivateAudioInterfaceAsyncOperation *pAsyncOp = NULL;
19576     ma_completion_handler_uwp completionHandler;
19577     IID iid;
19578     LPOLESTR iidStr;
19579     HRESULT hr;
19580     ma_result result;
19581     HRESULT activateResult;
19582     ma_IUnknown* pActivatedInterface;
19583
19584     MA_ASSERT(pContext != NULL);
19585     MA_ASSERT(ppAudioClient != NULL);
19586
19587     if (pDeviceID != NULL) {
19588         MA_COPY_MEMORY(&iid, pDeviceID->wasapi, sizeof(iid));
19589     } else {
19590         if (deviceType == ma_device_type_playback) {
19591             iid = MA_IID_DEVINTERFACE_AUDIO_RENDER;
19592         } else {
19593             iid = MA_IID_DEVINTERFACE_AUDIO_CAPTURE;
19594         }
19595     }
19596
19597 #if defined(__cplusplus)
19598     hr = StringFromIID(iid, &iidStr);
19599 #else
19600     hr = StringFromIID(&iid, &iidStr);
19601 #endif
19602     if (FAILED(hr)) {
19603         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.");
19604         return ma_result_from_HRESULT(hr);
19605     }
19606
19607     result = ma_completion_handler_uwp_init(&completionHandler);
19608     if (result != MA_SUCCESS) {
19609         ma_CoTaskMemFree(pContext, iidStr);
19610         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().");
19611         return result;
19612     }
19613
19614 #if defined(__cplusplus)
19615     hr = ActivateAudioInterfaceAsync(iidStr, MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
19616 #else
19617     hr = ActivateAudioInterfaceAsync(iidStr, &MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
19618 #endif
19619     if (FAILED(hr)) {
19620         ma_completion_handler_uwp_uninit(&completionHandler);
19621         ma_CoTaskMemFree(pContext, iidStr);
19622         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed.");
19623         return ma_result_from_HRESULT(hr);
19624     }
19625
19626     ma_CoTaskMemFree(pContext, iidStr);
19627
19628     /* Wait for the async operation for finish. */
19629     ma_completion_handler_uwp_wait(&completionHandler);
19630     ma_completion_handler_uwp_uninit(&completionHandler);
19631
19632     hr = ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(pAsyncOp, &activateResult, &pActivatedInterface);
19633     ma_IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp);
19634
19635     if (FAILED(hr) || FAILED(activateResult)) {
19636         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device.");
19637         return FAILED(hr) ? ma_result_from_HRESULT(hr) : ma_result_from_HRESULT(activateResult);
19638     }
19639
19640     /* Here is where we grab the IAudioClient interface. */
19641     hr = ma_IUnknown_QueryInterface(pActivatedInterface, &MA_IID_IAudioClient, (void**)ppAudioClient);
19642     if (FAILED(hr)) {
19643         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface.");
19644         return ma_result_from_HRESULT(hr);
19645     }
19646
19647     if (ppActivatedInterface) {
19648         *ppActivatedInterface = pActivatedInterface;
19649     } else {
19650         ma_IUnknown_Release(pActivatedInterface);
19651     }
19652
19653     return MA_SUCCESS;
19654 }
19655 #endif
19656
19657 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)
19658 {
19659 #ifdef MA_WIN32_DESKTOP
19660     return ma_context_get_IAudioClient_Desktop__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface);
19661 #else
19662     return ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface);
19663 #endif
19664 }
19665
19666
19667 static ma_result ma_context_enumerate_devices__wasapi(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
19668 {
19669     /* Different enumeration for desktop and UWP. */
19670 #ifdef MA_WIN32_DESKTOP
19671     /* Desktop */
19672     HRESULT hr;
19673     ma_IMMDeviceEnumerator* pDeviceEnumerator;
19674
19675     hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
19676     if (FAILED(hr)) {
19677         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.");
19678         return ma_result_from_HRESULT(hr);
19679     }
19680
19681     ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_playback, callback, pUserData);
19682     ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_capture,  callback, pUserData);
19683
19684     ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
19685 #else
19686     /*
19687     UWP
19688
19689     The MMDevice API is only supported on desktop applications. For now, while I'm still figuring out how to properly enumerate
19690     over devices without using MMDevice, I'm restricting devices to defaults.
19691
19692     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/
19693     */
19694     if (callback) {
19695         ma_bool32 cbResult = MA_TRUE;
19696
19697         /* Playback. */
19698         if (cbResult) {
19699             ma_device_info deviceInfo;
19700             MA_ZERO_OBJECT(&deviceInfo);
19701             ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
19702             deviceInfo.isDefault = MA_TRUE;
19703             cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
19704         }
19705
19706         /* Capture. */
19707         if (cbResult) {
19708             ma_device_info deviceInfo;
19709             MA_ZERO_OBJECT(&deviceInfo);
19710             ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
19711             deviceInfo.isDefault = MA_TRUE;
19712             cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
19713         }
19714     }
19715 #endif
19716
19717     return MA_SUCCESS;
19718 }
19719
19720 static ma_result ma_context_get_device_info__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
19721 {
19722 #ifdef MA_WIN32_DESKTOP
19723     ma_result result;
19724     ma_IMMDevice* pMMDevice = NULL;
19725     LPWSTR pDefaultDeviceID = NULL;
19726
19727     result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, &pMMDevice);
19728     if (result != MA_SUCCESS) {
19729         return result;
19730     }
19731
19732     /* We need the default device ID so we can set the isDefault flag in the device info. */
19733     pDefaultDeviceID = ma_context_get_default_device_id__wasapi(pContext, deviceType);
19734
19735     result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, pDefaultDeviceID, MA_FALSE, pDeviceInfo);   /* MA_FALSE = !onlySimpleInfo. */
19736
19737     if (pDefaultDeviceID != NULL) {
19738         ma_CoTaskMemFree(pContext, pDefaultDeviceID);
19739         pDefaultDeviceID = NULL;
19740     }
19741
19742     ma_IMMDevice_Release(pMMDevice);
19743
19744     return result;
19745 #else
19746     ma_IAudioClient* pAudioClient;
19747     ma_result result;
19748
19749     /* UWP currently only uses default devices. */
19750     if (deviceType == ma_device_type_playback) {
19751         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
19752     } else {
19753         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
19754     }
19755
19756     result = ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, &pAudioClient, NULL);
19757     if (result != MA_SUCCESS) {
19758         return result;
19759     }
19760
19761     result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, NULL, pAudioClient, pDeviceInfo);
19762
19763     pDeviceInfo->isDefault = MA_TRUE;  /* UWP only supports default devices. */
19764
19765     ma_IAudioClient_Release(pAudioClient);
19766     return result;
19767 #endif
19768 }
19769
19770 static ma_result ma_device_uninit__wasapi(ma_device* pDevice)
19771 {
19772     MA_ASSERT(pDevice != NULL);
19773
19774 #ifdef MA_WIN32_DESKTOP
19775     if (pDevice->wasapi.pDeviceEnumerator) {
19776         ((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator)->lpVtbl->UnregisterEndpointNotificationCallback((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator, &pDevice->wasapi.notificationClient);
19777         ma_IMMDeviceEnumerator_Release((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator);
19778     }
19779 #endif
19780
19781     if (pDevice->wasapi.pRenderClient) {
19782         ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient);
19783     }
19784     if (pDevice->wasapi.pCaptureClient) {
19785         ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
19786     }
19787
19788     if (pDevice->wasapi.pAudioClientPlayback) {
19789         ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
19790     }
19791     if (pDevice->wasapi.pAudioClientCapture) {
19792         ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
19793     }
19794
19795     if (pDevice->wasapi.hEventPlayback) {
19796         CloseHandle(pDevice->wasapi.hEventPlayback);
19797     }
19798     if (pDevice->wasapi.hEventCapture) {
19799         CloseHandle(pDevice->wasapi.hEventCapture);
19800     }
19801
19802     return MA_SUCCESS;
19803 }
19804
19805
19806 typedef struct
19807 {
19808     /* Input. */
19809     ma_format formatIn;
19810     ma_uint32 channelsIn;
19811     ma_uint32 sampleRateIn;
19812     ma_channel channelMapIn[MA_MAX_CHANNELS];
19813     ma_uint32 periodSizeInFramesIn;
19814     ma_uint32 periodSizeInMillisecondsIn;
19815     ma_uint32 periodsIn;
19816     ma_share_mode shareMode;
19817     ma_performance_profile performanceProfile;
19818     ma_bool32 noAutoConvertSRC;
19819     ma_bool32 noDefaultQualitySRC;
19820     ma_bool32 noHardwareOffloading;
19821
19822     /* Output. */
19823     ma_IAudioClient* pAudioClient;
19824     ma_IAudioRenderClient* pRenderClient;
19825     ma_IAudioCaptureClient* pCaptureClient;
19826     ma_format formatOut;
19827     ma_uint32 channelsOut;
19828     ma_uint32 sampleRateOut;
19829     ma_channel channelMapOut[MA_MAX_CHANNELS];
19830     ma_uint32 periodSizeInFramesOut;
19831     ma_uint32 periodsOut;
19832     ma_bool32 usingAudioClient3;
19833     char deviceName[256];
19834     ma_device_id id;
19835 } ma_device_init_internal_data__wasapi;
19836
19837 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)
19838 {
19839     HRESULT hr;
19840     ma_result result = MA_SUCCESS;
19841     const char* errorMsg = "";
19842     MA_AUDCLNT_SHAREMODE shareMode = MA_AUDCLNT_SHAREMODE_SHARED;
19843     DWORD streamFlags = 0;
19844     MA_REFERENCE_TIME periodDurationInMicroseconds;
19845     ma_bool32 wasInitializedUsingIAudioClient3 = MA_FALSE;
19846     WAVEFORMATEXTENSIBLE wf;
19847     ma_WASAPIDeviceInterface* pDeviceInterface = NULL;
19848     ma_IAudioClient2* pAudioClient2;
19849     ma_uint32 nativeSampleRate;
19850
19851     MA_ASSERT(pContext != NULL);
19852     MA_ASSERT(pData != NULL);
19853
19854     /* This function is only used to initialize one device type: either playback, capture or loopback. Never full-duplex. */
19855     if (deviceType == ma_device_type_duplex) {
19856         return MA_INVALID_ARGS;
19857     }
19858
19859     pData->pAudioClient = NULL;
19860     pData->pRenderClient = NULL;
19861     pData->pCaptureClient = NULL;
19862
19863     streamFlags = MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
19864     if (!pData->noAutoConvertSRC && pData->sampleRateIn != 0 && pData->shareMode != ma_share_mode_exclusive) {    /* <-- Exclusive streams must use the native sample rate. */
19865         streamFlags |= MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM;
19866     }
19867     if (!pData->noDefaultQualitySRC && pData->sampleRateIn != 0 && (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) != 0) {
19868         streamFlags |= MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
19869     }
19870     if (deviceType == ma_device_type_loopback) {
19871         streamFlags |= MA_AUDCLNT_STREAMFLAGS_LOOPBACK;
19872     }
19873
19874     result = ma_context_get_IAudioClient__wasapi(pContext, deviceType, pDeviceID, &pData->pAudioClient, &pDeviceInterface);
19875     if (result != MA_SUCCESS) {
19876         goto done;
19877     }
19878
19879     MA_ZERO_OBJECT(&wf);
19880
19881     /* Try enabling hardware offloading. */
19882     if (!pData->noHardwareOffloading) {
19883         hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient2, (void**)&pAudioClient2);
19884         if (SUCCEEDED(hr)) {
19885             BOOL isHardwareOffloadingSupported = 0;
19886             hr = ma_IAudioClient2_IsOffloadCapable(pAudioClient2, MA_AudioCategory_Other, &isHardwareOffloadingSupported);
19887             if (SUCCEEDED(hr) && isHardwareOffloadingSupported) {
19888                 ma_AudioClientProperties clientProperties;
19889                 MA_ZERO_OBJECT(&clientProperties);
19890                 clientProperties.cbSize = sizeof(clientProperties);
19891                 clientProperties.bIsOffload = 1;
19892                 clientProperties.eCategory = MA_AudioCategory_Other;
19893                 ma_IAudioClient2_SetClientProperties(pAudioClient2, &clientProperties);
19894             }
19895
19896             pAudioClient2->lpVtbl->Release(pAudioClient2);
19897         }
19898     }
19899
19900     /* 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. */
19901     result = MA_FORMAT_NOT_SUPPORTED;
19902     if (pData->shareMode == ma_share_mode_exclusive) {
19903     #ifdef MA_WIN32_DESKTOP
19904         /* In exclusive mode on desktop we always use the backend's native format. */
19905         ma_IPropertyStore* pStore = NULL;
19906         hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pStore);
19907         if (SUCCEEDED(hr)) {
19908             PROPVARIANT prop;
19909             ma_PropVariantInit(&prop);
19910             hr = ma_IPropertyStore_GetValue(pStore, &MA_PKEY_AudioEngine_DeviceFormat, &prop);
19911             if (SUCCEEDED(hr)) {
19912                 WAVEFORMATEX* pActualFormat = (WAVEFORMATEX*)prop.blob.pBlobData;
19913                 hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pData->pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pActualFormat, NULL);
19914                 if (SUCCEEDED(hr)) {
19915                     MA_COPY_MEMORY(&wf, pActualFormat, sizeof(WAVEFORMATEXTENSIBLE));
19916                 }
19917
19918                 ma_PropVariantClear(pContext, &prop);
19919             }
19920
19921             ma_IPropertyStore_Release(pStore);
19922         }
19923     #else
19924         /*
19925         I do not know how to query the device's native format on UWP so for now I'm just disabling support for
19926         exclusive mode. The alternative is to enumerate over different formats and check IsFormatSupported()
19927         until you find one that works.
19928
19929         TODO: Add support for exclusive mode to UWP.
19930         */
19931         hr = S_FALSE;
19932     #endif
19933
19934         if (hr == S_OK) {
19935             shareMode = MA_AUDCLNT_SHAREMODE_EXCLUSIVE;
19936             result = MA_SUCCESS;
19937         } else {
19938             result = MA_SHARE_MODE_NOT_SUPPORTED;
19939         }
19940     } else {
19941         /* In shared mode we are always using the format reported by the operating system. */
19942         WAVEFORMATEXTENSIBLE* pNativeFormat = NULL;
19943         hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pData->pAudioClient, (WAVEFORMATEX**)&pNativeFormat);
19944         if (hr != S_OK) {
19945             result = MA_FORMAT_NOT_SUPPORTED;
19946         } else {
19947             MA_COPY_MEMORY(&wf, pNativeFormat, sizeof(wf));
19948             result = MA_SUCCESS;
19949         }
19950
19951         ma_CoTaskMemFree(pContext, pNativeFormat);
19952
19953         shareMode = MA_AUDCLNT_SHAREMODE_SHARED;
19954     }
19955
19956     /* Return an error if we still haven't found a format. */
19957     if (result != MA_SUCCESS) {
19958         errorMsg = "[WASAPI] Failed to find best device mix format.";
19959         goto done;
19960     }
19961
19962     /*
19963     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
19964     WASAPI to perform the sample rate conversion.
19965     */
19966     nativeSampleRate = wf.Format.nSamplesPerSec;
19967     if (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) {
19968         wf.Format.nSamplesPerSec = (pData->sampleRateIn != 0) ? pData->sampleRateIn : MA_DEFAULT_SAMPLE_RATE;
19969         wf.Format.nAvgBytesPerSec = wf.Format.nSamplesPerSec * wf.Format.nBlockAlign;
19970     }
19971
19972     pData->formatOut = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)&wf);
19973     if (pData->formatOut == ma_format_unknown) {
19974         /*
19975         The format isn't supported. This is almost certainly because the exclusive mode format isn't supported by miniaudio. We need to return MA_SHARE_MODE_NOT_SUPPORTED
19976         in this case so that the caller can detect it and fall back to shared mode if desired. We should never get here if shared mode was requested, but just for
19977         completeness we'll check for it and return MA_FORMAT_NOT_SUPPORTED.
19978         */
19979         if (shareMode == MA_AUDCLNT_SHAREMODE_EXCLUSIVE) {
19980             result = MA_SHARE_MODE_NOT_SUPPORTED;
19981         } else {
19982             result = MA_FORMAT_NOT_SUPPORTED;
19983         }
19984
19985         errorMsg = "[WASAPI] Native format not supported.";
19986         goto done;
19987     }
19988
19989     pData->channelsOut = wf.Format.nChannels;
19990     pData->sampleRateOut = wf.Format.nSamplesPerSec;
19991
19992     /* Get the internal channel map based on the channel mask. */
19993     ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pData->channelsOut, pData->channelMapOut);
19994
19995     /* Period size. */
19996     pData->periodsOut = (pData->periodsIn != 0) ? pData->periodsIn : MA_DEFAULT_PERIODS;
19997     pData->periodSizeInFramesOut = pData->periodSizeInFramesIn;
19998     if (pData->periodSizeInFramesOut == 0) {
19999         if (pData->periodSizeInMillisecondsIn == 0) {
20000             if (pData->performanceProfile == ma_performance_profile_low_latency) {
20001                 pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, wf.Format.nSamplesPerSec);
20002             } else {
20003                 pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, wf.Format.nSamplesPerSec);
20004             }
20005         } else {
20006             pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, wf.Format.nSamplesPerSec);
20007         }
20008     }
20009
20010     periodDurationInMicroseconds = ((ma_uint64)pData->periodSizeInFramesOut * 1000 * 1000) / wf.Format.nSamplesPerSec;
20011
20012
20013     /* Slightly different initialization for shared and exclusive modes. We try exclusive mode first, and if it fails, fall back to shared mode. */
20014     if (shareMode == MA_AUDCLNT_SHAREMODE_EXCLUSIVE) {
20015         MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * 10;
20016
20017         /*
20018         If the periodicy is too small, Initialize() will fail with AUDCLNT_E_INVALID_DEVICE_PERIOD. In this case we should just keep increasing
20019         it and trying it again.
20020         */
20021         hr = E_FAIL;
20022         for (;;) {
20023             hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL);
20024             if (hr == MA_AUDCLNT_E_INVALID_DEVICE_PERIOD) {
20025                 if (bufferDuration > 500*10000) {
20026                     break;
20027                 } else {
20028                     if (bufferDuration == 0) {  /* <-- Just a sanity check to prevent an infinit loop. Should never happen, but it makes me feel better. */
20029                         break;
20030                     }
20031
20032                     bufferDuration = bufferDuration * 2;
20033                     continue;
20034                 }
20035             } else {
20036                 break;
20037             }
20038         }
20039
20040         if (hr == MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) {
20041             ma_uint32 bufferSizeInFrames;
20042             hr = ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient, &bufferSizeInFrames);
20043             if (SUCCEEDED(hr)) {
20044                 bufferDuration = (MA_REFERENCE_TIME)((10000.0 * 1000 / wf.Format.nSamplesPerSec * bufferSizeInFrames) + 0.5);
20045
20046                 /* Unfortunately we need to release and re-acquire the audio client according to MSDN. Seems silly - why not just call IAudioClient_Initialize() again?! */
20047                 ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient);
20048
20049             #ifdef MA_WIN32_DESKTOP
20050                 hr = ma_IMMDevice_Activate(pDeviceInterface, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pData->pAudioClient);
20051             #else
20052                 hr = ma_IUnknown_QueryInterface(pDeviceInterface, &MA_IID_IAudioClient, (void**)&pData->pAudioClient);
20053             #endif
20054
20055                 if (SUCCEEDED(hr)) {
20056                     hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL);
20057                 }
20058             }
20059         }
20060
20061         if (FAILED(hr)) {
20062             /* 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. */
20063             if (hr == E_ACCESSDENIED) {
20064                 errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Access denied.", result = MA_ACCESS_DENIED;
20065             } else if (hr == MA_AUDCLNT_E_DEVICE_IN_USE) {
20066                 errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Device in use.", result = MA_BUSY;
20067             } else {
20068                 errorMsg = "[WASAPI] Failed to initialize device in exclusive mode."; result = ma_result_from_HRESULT(hr);
20069             }
20070             goto done;
20071         }
20072     }
20073
20074     if (shareMode == MA_AUDCLNT_SHAREMODE_SHARED) {
20075         /*
20076         Low latency shared mode via IAudioClient3.
20077
20078         NOTE
20079         ====
20080         Contrary to the documentation on MSDN (https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nf-audioclient-iaudioclient3-initializesharedaudiostream), the
20081         use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM and AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY with IAudioClient3_InitializeSharedAudioStream() absolutely does not work. Using
20082         any of these flags will result in HRESULT code 0x88890021. The other problem is that calling IAudioClient3_GetSharedModeEnginePeriod() with a sample rate different to
20083         that returned by IAudioClient_GetMixFormat() also results in an error. I'm therefore disabling low-latency shared mode with AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM.
20084         */
20085         #ifndef MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE
20086         {
20087             if ((streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) == 0 || nativeSampleRate == wf.Format.nSamplesPerSec) {
20088                 ma_IAudioClient3* pAudioClient3 = NULL;
20089                 hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient3, (void**)&pAudioClient3);
20090                 if (SUCCEEDED(hr)) {
20091                     ma_uint32 defaultPeriodInFrames;
20092                     ma_uint32 fundamentalPeriodInFrames;
20093                     ma_uint32 minPeriodInFrames;
20094                     ma_uint32 maxPeriodInFrames;
20095                     hr = ma_IAudioClient3_GetSharedModeEnginePeriod(pAudioClient3, (WAVEFORMATEX*)&wf, &defaultPeriodInFrames, &fundamentalPeriodInFrames, &minPeriodInFrames, &maxPeriodInFrames);
20096                     if (SUCCEEDED(hr)) {
20097                         ma_uint32 desiredPeriodInFrames = pData->periodSizeInFramesOut;
20098                         ma_uint32 actualPeriodInFrames  = desiredPeriodInFrames;
20099
20100                         /* Make sure the period size is a multiple of fundamentalPeriodInFrames. */
20101                         actualPeriodInFrames = actualPeriodInFrames / fundamentalPeriodInFrames;
20102                         actualPeriodInFrames = actualPeriodInFrames * fundamentalPeriodInFrames;
20103
20104                         /* The period needs to be clamped between minPeriodInFrames and maxPeriodInFrames. */
20105                         actualPeriodInFrames = ma_clamp(actualPeriodInFrames, minPeriodInFrames, maxPeriodInFrames);
20106
20107                         #if defined(MA_DEBUG_OUTPUT)
20108                         {
20109                             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=%d)\n", actualPeriodInFrames);
20110                             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "    defaultPeriodInFrames=%d\n", defaultPeriodInFrames);
20111                             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "    fundamentalPeriodInFrames=%d\n", fundamentalPeriodInFrames);
20112                             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "    minPeriodInFrames=%d\n", minPeriodInFrames);
20113                             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "    maxPeriodInFrames=%d\n", maxPeriodInFrames);
20114                         }
20115                         #endif
20116
20117                         /* If the client requested a largish buffer than we don't actually want to use low latency shared mode because it forces small buffers. */
20118                         if (actualPeriodInFrames >= desiredPeriodInFrames) {
20119                             /*
20120                             MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY must not be in the stream flags. If either of these are specified,
20121                             IAudioClient3_InitializeSharedAudioStream() will fail.
20122                             */
20123                             hr = ma_IAudioClient3_InitializeSharedAudioStream(pAudioClient3, streamFlags & ~(MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY), actualPeriodInFrames, (WAVEFORMATEX*)&wf, NULL);
20124                             if (SUCCEEDED(hr)) {
20125                                 wasInitializedUsingIAudioClient3 = MA_TRUE;
20126                                 pData->periodSizeInFramesOut = actualPeriodInFrames;
20127                                 #if defined(MA_DEBUG_OUTPUT)
20128                                 {
20129                                     ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Using IAudioClient3\n");
20130                                     ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "    periodSizeInFramesOut=%d\n", pData->periodSizeInFramesOut);
20131                                 }
20132                                 #endif
20133                             } else {
20134                                 ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] IAudioClient3_InitializeSharedAudioStream failed. Falling back to IAudioClient.\n");
20135                             }
20136                         } else {
20137                             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Not using IAudioClient3 because the desired period size is larger than the maximum supported by IAudioClient3.\n");
20138                         }
20139                     } else {
20140                         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] IAudioClient3_GetSharedModeEnginePeriod failed. Falling back to IAudioClient.\n");
20141                     }
20142
20143                     ma_IAudioClient3_Release(pAudioClient3);
20144                     pAudioClient3 = NULL;
20145                 }
20146             }
20147         }
20148         #else
20149         {
20150             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[WASAPI] Not using IAudioClient3 because MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE is enabled.\n");
20151         }
20152         #endif
20153
20154         /* If we don't have an IAudioClient3 then we need to use the normal initialization routine. */
20155         if (!wasInitializedUsingIAudioClient3) {
20156             MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * pData->periodsOut * 10;   /* <-- Multiply by 10 for microseconds to 100-nanoseconds. */
20157             hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, 0, (WAVEFORMATEX*)&wf, NULL);
20158             if (FAILED(hr)) {
20159                 if (hr == E_ACCESSDENIED) {
20160                     errorMsg = "[WASAPI] Failed to initialize device. Access denied.", result = MA_ACCESS_DENIED;
20161                 } else if (hr == MA_AUDCLNT_E_DEVICE_IN_USE) {
20162                     errorMsg = "[WASAPI] Failed to initialize device. Device in use.", result = MA_BUSY;
20163                 } else {
20164                     errorMsg = "[WASAPI] Failed to initialize device.", result = ma_result_from_HRESULT(hr);
20165                 }
20166
20167                 goto done;
20168             }
20169         }
20170     }
20171
20172     if (!wasInitializedUsingIAudioClient3) {
20173         ma_uint32 bufferSizeInFrames;
20174         hr = ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient, &bufferSizeInFrames);
20175         if (FAILED(hr)) {
20176             errorMsg = "[WASAPI] Failed to get audio client's actual buffer size.", result = ma_result_from_HRESULT(hr);
20177             goto done;
20178         }
20179
20180         pData->periodSizeInFramesOut = bufferSizeInFrames / pData->periodsOut;
20181     }
20182
20183     pData->usingAudioClient3 = wasInitializedUsingIAudioClient3;
20184
20185
20186     if (deviceType == ma_device_type_playback) {
20187         result = ma_device_create_IAudioClient_service__wasapi(pContext, deviceType, (ma_IAudioClient*)pData->pAudioClient, (void**)&pData->pRenderClient);
20188     } else {
20189         result = ma_device_create_IAudioClient_service__wasapi(pContext, deviceType, (ma_IAudioClient*)pData->pAudioClient, (void**)&pData->pCaptureClient);
20190     }
20191
20192     /*if (FAILED(hr)) {*/
20193     if (result != MA_SUCCESS) {
20194         errorMsg = "[WASAPI] Failed to get audio client service.";
20195         goto done;
20196     }
20197
20198
20199     /* Grab the name of the device. */
20200     #ifdef MA_WIN32_DESKTOP
20201     {
20202         ma_IPropertyStore *pProperties;
20203         hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pProperties);
20204         if (SUCCEEDED(hr)) {
20205             PROPVARIANT varName;
20206             ma_PropVariantInit(&varName);
20207             hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &varName);
20208             if (SUCCEEDED(hr)) {
20209                 WideCharToMultiByte(CP_UTF8, 0, varName.pwszVal, -1, pData->deviceName, sizeof(pData->deviceName), 0, FALSE);
20210                 ma_PropVariantClear(pContext, &varName);
20211             }
20212
20213             ma_IPropertyStore_Release(pProperties);
20214         }
20215     }
20216     #endif
20217
20218     /*
20219     For the WASAPI backend we need to know the actual IDs of the device in order to do automatic
20220     stream routing so that IDs can be compared and we can determine which device has been detached
20221     and whether or not it matches with our ma_device.
20222     */
20223     #ifdef MA_WIN32_DESKTOP
20224     {
20225         /* Desktop */
20226         ma_context_get_device_id_from_MMDevice__wasapi(pContext, pDeviceInterface, &pData->id);
20227     }
20228     #else
20229     {
20230         /* UWP */
20231         /* TODO: Implement me. Need to figure out how to get the ID of the default device. */
20232     }
20233     #endif
20234
20235 done:
20236     /* Clean up. */
20237 #ifdef MA_WIN32_DESKTOP
20238     if (pDeviceInterface != NULL) {
20239         ma_IMMDevice_Release(pDeviceInterface);
20240     }
20241 #else
20242     if (pDeviceInterface != NULL) {
20243         ma_IUnknown_Release(pDeviceInterface);
20244     }
20245 #endif
20246
20247     if (result != MA_SUCCESS) {
20248         if (pData->pRenderClient) {
20249             ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pData->pRenderClient);
20250             pData->pRenderClient = NULL;
20251         }
20252         if (pData->pCaptureClient) {
20253             ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pData->pCaptureClient);
20254             pData->pCaptureClient = NULL;
20255         }
20256         if (pData->pAudioClient) {
20257             ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient);
20258             pData->pAudioClient = NULL;
20259         }
20260
20261         if (errorMsg != NULL && errorMsg[0] != '\0') {
20262             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "%s", errorMsg);
20263         }
20264
20265         return result;
20266     } else {
20267         return MA_SUCCESS;
20268     }
20269 }
20270
20271 static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type deviceType)
20272 {
20273     ma_device_init_internal_data__wasapi data;
20274     ma_result result;
20275
20276     MA_ASSERT(pDevice != NULL);
20277
20278     /* We only re-initialize the playback or capture device. Never a full-duplex device. */
20279     if (deviceType == ma_device_type_duplex) {
20280         return MA_INVALID_ARGS;
20281     }
20282
20283
20284     /*
20285     Before reinitializing the device we need to free the previous audio clients.
20286
20287     There's a known memory leak here. We will be calling this from the routing change callback that
20288     is fired by WASAPI. If we attempt to release the IAudioClient we will deadlock. In my opinion
20289     this is a bug. I'm not sure what I need to do to handle this cleanly, but I think we'll probably
20290     need some system where we post an event, but delay the execution of it until the callback has
20291     returned. I'm not sure how to do this reliably, however. I have set up some infrastructure for
20292     a command thread which might be useful for this.
20293     */
20294     if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
20295         if (pDevice->wasapi.pCaptureClient) {
20296             ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
20297             pDevice->wasapi.pCaptureClient = NULL;
20298         }
20299
20300         if (pDevice->wasapi.pAudioClientCapture) {
20301             /*ma_device_release_IAudioClient_service__wasapi(pDevice, ma_device_type_capture);*/
20302             pDevice->wasapi.pAudioClientCapture = NULL;
20303         }
20304     }
20305
20306     if (deviceType == ma_device_type_playback) {
20307         if (pDevice->wasapi.pRenderClient) {
20308             ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient);
20309             pDevice->wasapi.pRenderClient = NULL;
20310         }
20311
20312         if (pDevice->wasapi.pAudioClientPlayback) {
20313             /*ma_device_release_IAudioClient_service__wasapi(pDevice, ma_device_type_playback);*/
20314             pDevice->wasapi.pAudioClientPlayback = NULL;
20315         }
20316     }
20317
20318
20319     if (deviceType == ma_device_type_playback) {
20320         data.formatIn               = pDevice->playback.format;
20321         data.channelsIn             = pDevice->playback.channels;
20322         MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
20323         data.shareMode              = pDevice->playback.shareMode;
20324     } else {
20325         data.formatIn               = pDevice->capture.format;
20326         data.channelsIn             = pDevice->capture.channels;
20327         MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
20328         data.shareMode              = pDevice->capture.shareMode;
20329     }
20330
20331     data.sampleRateIn               = pDevice->sampleRate;
20332     data.periodSizeInFramesIn       = pDevice->wasapi.originalPeriodSizeInFrames;
20333     data.periodSizeInMillisecondsIn = pDevice->wasapi.originalPeriodSizeInMilliseconds;
20334     data.periodsIn                  = pDevice->wasapi.originalPeriods;
20335     data.performanceProfile         = pDevice->wasapi.originalPerformanceProfile;
20336     data.noAutoConvertSRC           = pDevice->wasapi.noAutoConvertSRC;
20337     data.noDefaultQualitySRC        = pDevice->wasapi.noDefaultQualitySRC;
20338     data.noHardwareOffloading       = pDevice->wasapi.noHardwareOffloading;
20339     result = ma_device_init_internal__wasapi(pDevice->pContext, deviceType, NULL, &data);
20340     if (result != MA_SUCCESS) {
20341         return result;
20342     }
20343
20344     /* At this point we have some new objects ready to go. We need to uninitialize the previous ones and then set the new ones. */
20345     if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
20346         pDevice->wasapi.pAudioClientCapture         = data.pAudioClient;
20347         pDevice->wasapi.pCaptureClient              = data.pCaptureClient;
20348
20349         pDevice->capture.internalFormat             = data.formatOut;
20350         pDevice->capture.internalChannels           = data.channelsOut;
20351         pDevice->capture.internalSampleRate         = data.sampleRateOut;
20352         MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
20353         pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
20354         pDevice->capture.internalPeriods            = data.periodsOut;
20355         ma_strcpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), data.deviceName);
20356
20357         ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture,  pDevice->wasapi.hEventCapture);
20358
20359         pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut;
20360         ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture);
20361
20362         /* We must always have a valid ID. */
20363         ma_wcscpy_s(pDevice->capture.id.wasapi, sizeof(pDevice->capture.id.wasapi), data.id.wasapi);
20364     }
20365
20366     if (deviceType == ma_device_type_playback) {
20367         pDevice->wasapi.pAudioClientPlayback         = data.pAudioClient;
20368         pDevice->wasapi.pRenderClient                = data.pRenderClient;
20369
20370         pDevice->playback.internalFormat             = data.formatOut;
20371         pDevice->playback.internalChannels           = data.channelsOut;
20372         pDevice->playback.internalSampleRate         = data.sampleRateOut;
20373         MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
20374         pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
20375         pDevice->playback.internalPeriods            = data.periodsOut;
20376         ma_strcpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), data.deviceName);
20377
20378         ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback);
20379
20380         pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut;
20381         ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback);
20382
20383         /* We must always have a valid ID. */
20384         ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi);
20385     }
20386
20387     return MA_SUCCESS;
20388 }
20389
20390 static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
20391 {
20392     ma_result result = MA_SUCCESS;
20393
20394 #ifdef MA_WIN32_DESKTOP
20395     HRESULT hr;
20396     ma_IMMDeviceEnumerator* pDeviceEnumerator;
20397 #endif
20398
20399     MA_ASSERT(pDevice != NULL);
20400
20401     MA_ZERO_OBJECT(&pDevice->wasapi);
20402     pDevice->wasapi.noAutoConvertSRC     = pConfig->wasapi.noAutoConvertSRC;
20403     pDevice->wasapi.noDefaultQualitySRC  = pConfig->wasapi.noDefaultQualitySRC;
20404     pDevice->wasapi.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading;
20405
20406     /* Exclusive mode is not allowed with loopback. */
20407     if (pConfig->deviceType == ma_device_type_loopback && pConfig->playback.shareMode == ma_share_mode_exclusive) {
20408         return MA_INVALID_DEVICE_CONFIG;
20409     }
20410
20411     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
20412         ma_device_init_internal_data__wasapi data;
20413         data.formatIn                   = pDescriptorCapture->format;
20414         data.channelsIn                 = pDescriptorCapture->channels;
20415         data.sampleRateIn               = pDescriptorCapture->sampleRate;
20416         MA_COPY_MEMORY(data.channelMapIn, pDescriptorCapture->channelMap, sizeof(pDescriptorCapture->channelMap));
20417         data.periodSizeInFramesIn       = pDescriptorCapture->periodSizeInFrames;
20418         data.periodSizeInMillisecondsIn = pDescriptorCapture->periodSizeInMilliseconds;
20419         data.periodsIn                  = pDescriptorCapture->periodCount;
20420         data.shareMode                  = pDescriptorCapture->shareMode;
20421         data.performanceProfile         = pConfig->performanceProfile;
20422         data.noAutoConvertSRC           = pConfig->wasapi.noAutoConvertSRC;
20423         data.noDefaultQualitySRC        = pConfig->wasapi.noDefaultQualitySRC;
20424         data.noHardwareOffloading       = pConfig->wasapi.noHardwareOffloading;
20425
20426         result = ma_device_init_internal__wasapi(pDevice->pContext, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture, pDescriptorCapture->pDeviceID, &data);
20427         if (result != MA_SUCCESS) {
20428             return result;
20429         }
20430
20431         pDevice->wasapi.pAudioClientCapture              = data.pAudioClient;
20432         pDevice->wasapi.pCaptureClient                   = data.pCaptureClient;
20433         pDevice->wasapi.originalPeriodSizeInMilliseconds = pDescriptorCapture->periodSizeInMilliseconds;
20434         pDevice->wasapi.originalPeriodSizeInFrames       = pDescriptorCapture->periodSizeInFrames;
20435         pDevice->wasapi.originalPeriods                  = pDescriptorCapture->periodCount;
20436         pDevice->wasapi.originalPerformanceProfile       = pConfig->performanceProfile;
20437
20438         /*
20439         The event for capture needs to be manual reset for the same reason as playback. We keep the initial state set to unsignaled,
20440         however, because we want to block until we actually have something for the first call to ma_device_read().
20441         */
20442         pDevice->wasapi.hEventCapture = CreateEventW(NULL, FALSE, FALSE, NULL);  /* Auto reset, unsignaled by default. */
20443         if (pDevice->wasapi.hEventCapture == NULL) {
20444             result = ma_result_from_GetLastError(GetLastError());
20445
20446             if (pDevice->wasapi.pCaptureClient != NULL) {
20447                 ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
20448                 pDevice->wasapi.pCaptureClient = NULL;
20449             }
20450             if (pDevice->wasapi.pAudioClientCapture != NULL) {
20451                 ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
20452                 pDevice->wasapi.pAudioClientCapture = NULL;
20453             }
20454
20455             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for capture.");
20456             return result;
20457         }
20458         ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture);
20459
20460         pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut;
20461         ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture);
20462
20463         /* We must always have a valid ID. */
20464         ma_wcscpy_s(pDevice->capture.id.wasapi, sizeof(pDevice->capture.id.wasapi), data.id.wasapi);
20465
20466         /* The descriptor needs to be updated with actual values. */
20467         pDescriptorCapture->format             = data.formatOut;
20468         pDescriptorCapture->channels           = data.channelsOut;
20469         pDescriptorCapture->sampleRate         = data.sampleRateOut;
20470         MA_COPY_MEMORY(pDescriptorCapture->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
20471         pDescriptorCapture->periodSizeInFrames = data.periodSizeInFramesOut;
20472         pDescriptorCapture->periodCount        = data.periodsOut;
20473     }
20474
20475     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
20476         ma_device_init_internal_data__wasapi data;
20477         data.formatIn                   = pDescriptorPlayback->format;
20478         data.channelsIn                 = pDescriptorPlayback->channels;
20479         data.sampleRateIn               = pDescriptorPlayback->sampleRate;
20480         MA_COPY_MEMORY(data.channelMapIn, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap));
20481         data.periodSizeInFramesIn       = pDescriptorPlayback->periodSizeInFrames;
20482         data.periodSizeInMillisecondsIn = pDescriptorPlayback->periodSizeInMilliseconds;
20483         data.periodsIn                  = pDescriptorPlayback->periodCount;
20484         data.shareMode                  = pDescriptorPlayback->shareMode;
20485         data.performanceProfile         = pConfig->performanceProfile;
20486         data.noAutoConvertSRC           = pConfig->wasapi.noAutoConvertSRC;
20487         data.noDefaultQualitySRC        = pConfig->wasapi.noDefaultQualitySRC;
20488         data.noHardwareOffloading       = pConfig->wasapi.noHardwareOffloading;
20489
20490         result = ma_device_init_internal__wasapi(pDevice->pContext, ma_device_type_playback, pDescriptorPlayback->pDeviceID, &data);
20491         if (result != MA_SUCCESS) {
20492             if (pConfig->deviceType == ma_device_type_duplex) {
20493                 if (pDevice->wasapi.pCaptureClient != NULL) {
20494                     ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
20495                     pDevice->wasapi.pCaptureClient = NULL;
20496                 }
20497                 if (pDevice->wasapi.pAudioClientCapture != NULL) {
20498                     ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
20499                     pDevice->wasapi.pAudioClientCapture = NULL;
20500                 }
20501
20502                 CloseHandle(pDevice->wasapi.hEventCapture);
20503                 pDevice->wasapi.hEventCapture = NULL;
20504             }
20505             return result;
20506         }
20507
20508         pDevice->wasapi.pAudioClientPlayback             = data.pAudioClient;
20509         pDevice->wasapi.pRenderClient                    = data.pRenderClient;
20510         pDevice->wasapi.originalPeriodSizeInMilliseconds = pDescriptorPlayback->periodSizeInMilliseconds;
20511         pDevice->wasapi.originalPeriodSizeInFrames       = pDescriptorPlayback->periodSizeInFrames;
20512         pDevice->wasapi.originalPeriods                  = pDescriptorPlayback->periodCount;
20513         pDevice->wasapi.originalPerformanceProfile       = pConfig->performanceProfile;
20514
20515         /*
20516         The event for playback is needs to be manual reset because we want to explicitly control the fact that it becomes signalled
20517         only after the whole available space has been filled, never before.
20518
20519         The playback event also needs to be initially set to a signaled state so that the first call to ma_device_write() is able
20520         to get passed WaitForMultipleObjects().
20521         */
20522         pDevice->wasapi.hEventPlayback = CreateEventW(NULL, FALSE, TRUE, NULL);  /* Auto reset, signaled by default. */
20523         if (pDevice->wasapi.hEventPlayback == NULL) {
20524             result = ma_result_from_GetLastError(GetLastError());
20525
20526             if (pConfig->deviceType == ma_device_type_duplex) {
20527                 if (pDevice->wasapi.pCaptureClient != NULL) {
20528                     ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
20529                     pDevice->wasapi.pCaptureClient = NULL;
20530                 }
20531                 if (pDevice->wasapi.pAudioClientCapture != NULL) {
20532                     ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
20533                     pDevice->wasapi.pAudioClientCapture = NULL;
20534                 }
20535
20536                 CloseHandle(pDevice->wasapi.hEventCapture);
20537                 pDevice->wasapi.hEventCapture = NULL;
20538             }
20539
20540             if (pDevice->wasapi.pRenderClient != NULL) {
20541                 ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient);
20542                 pDevice->wasapi.pRenderClient = NULL;
20543             }
20544             if (pDevice->wasapi.pAudioClientPlayback != NULL) {
20545                 ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
20546                 pDevice->wasapi.pAudioClientPlayback = NULL;
20547             }
20548
20549             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for playback.");
20550             return result;
20551         }
20552         ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback);
20553
20554         pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut;
20555         ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback);
20556
20557         /* We must always have a valid ID. */
20558         ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi);
20559
20560         /* The descriptor needs to be updated with actual values. */
20561         pDescriptorPlayback->format             = data.formatOut;
20562         pDescriptorPlayback->channels           = data.channelsOut;
20563         pDescriptorPlayback->sampleRate         = data.sampleRateOut;
20564         MA_COPY_MEMORY(pDescriptorPlayback->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
20565         pDescriptorPlayback->periodSizeInFrames = data.periodSizeInFramesOut;
20566         pDescriptorPlayback->periodCount        = data.periodsOut;
20567     }
20568
20569     /*
20570     We need to register a notification client to detect when the device has been disabled, unplugged or re-routed (when the default device changes). When
20571     we are connecting to the default device we want to do automatic stream routing when the device is disabled or unplugged. Otherwise we want to just
20572     stop the device outright and let the application handle it.
20573     */
20574 #ifdef MA_WIN32_DESKTOP
20575     if (pConfig->wasapi.noAutoStreamRouting == MA_FALSE) {
20576         if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID == NULL) {
20577             pDevice->wasapi.allowCaptureAutoStreamRouting = MA_TRUE;
20578         }
20579         if ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID == NULL) {
20580             pDevice->wasapi.allowPlaybackAutoStreamRouting = MA_TRUE;
20581         }
20582     }
20583
20584     hr = ma_CoCreateInstance(pDevice->pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
20585     if (FAILED(hr)) {
20586         ma_device_uninit__wasapi(pDevice);
20587         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.");
20588         return ma_result_from_HRESULT(hr);
20589     }
20590
20591     pDevice->wasapi.notificationClient.lpVtbl  = (void*)&g_maNotificationCientVtbl;
20592     pDevice->wasapi.notificationClient.counter = 1;
20593     pDevice->wasapi.notificationClient.pDevice = pDevice;
20594
20595     hr = pDeviceEnumerator->lpVtbl->RegisterEndpointNotificationCallback(pDeviceEnumerator, &pDevice->wasapi.notificationClient);
20596     if (SUCCEEDED(hr)) {
20597         pDevice->wasapi.pDeviceEnumerator = (ma_ptr)pDeviceEnumerator;
20598     } else {
20599         /* Not the end of the world if we fail to register the notification callback. We just won't support automatic stream routing. */
20600         ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
20601     }
20602 #endif
20603
20604     c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture,  MA_FALSE);
20605     c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE);
20606
20607     return MA_SUCCESS;
20608 }
20609
20610 static ma_result ma_device__get_available_frames__wasapi(ma_device* pDevice, ma_IAudioClient* pAudioClient, ma_uint32* pFrameCount)
20611 {
20612     ma_uint32 paddingFramesCount;
20613     HRESULT hr;
20614     ma_share_mode shareMode;
20615
20616     MA_ASSERT(pDevice != NULL);
20617     MA_ASSERT(pFrameCount != NULL);
20618
20619     *pFrameCount = 0;
20620
20621     if ((ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientPlayback && (ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientCapture) {
20622         return MA_INVALID_OPERATION;
20623     }
20624
20625     /*
20626     I've had a report that GetCurrentPadding() is returning a frame count of 0 which is preventing
20627     higher level function calls from doing anything because it thinks nothing is available. I have
20628     taken a look at the documentation and it looks like this is unnecessary in exclusive mode.
20629
20630     From Microsoft's documentation:
20631
20632         For an exclusive-mode rendering or capture stream that was initialized with the
20633         AUDCLNT_STREAMFLAGS_EVENTCALLBACK flag, the client typically has no use for the padding
20634         value reported by GetCurrentPadding. Instead, the client accesses an entire buffer during
20635         each processing pass.
20636
20637     Considering this, I'm going to skip GetCurrentPadding() for exclusive mode and just report the
20638     entire buffer. This depends on the caller making sure they wait on the event handler.
20639     */
20640     shareMode = ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) ? pDevice->playback.shareMode : pDevice->capture.shareMode;
20641     if (shareMode == ma_share_mode_shared) {
20642         /* Shared mode. */
20643         hr = ma_IAudioClient_GetCurrentPadding(pAudioClient, &paddingFramesCount);
20644         if (FAILED(hr)) {
20645             return ma_result_from_HRESULT(hr);
20646         }
20647
20648         if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) {
20649             *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesPlayback - paddingFramesCount;
20650         } else {
20651             *pFrameCount = paddingFramesCount;
20652         }
20653     } else {
20654         /* Exclusive mode. */
20655         if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) {
20656             *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesPlayback;
20657         } else {
20658             *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesCapture;
20659         }
20660     }
20661
20662     return MA_SUCCESS;
20663 }
20664
20665
20666 static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type deviceType)
20667 {
20668     ma_result result;
20669
20670     if (deviceType == ma_device_type_duplex) {
20671         return MA_INVALID_ARGS;
20672     }
20673
20674     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "=== CHANGING DEVICE ===\n");
20675
20676     result = ma_device_reinit__wasapi(pDevice, deviceType);
20677     if (result != MA_SUCCESS) {
20678         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Reinitializing device after route change failed.\n");
20679         return result;
20680     }
20681
20682     ma_device__post_init_setup(pDevice, deviceType);
20683
20684     ma_device__on_notification_rerouted(pDevice);
20685
20686     return MA_SUCCESS;
20687 }
20688
20689 static ma_result ma_device_start__wasapi(ma_device* pDevice)
20690 {
20691     HRESULT hr;
20692
20693     MA_ASSERT(pDevice != NULL);
20694
20695     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
20696         hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
20697         if (FAILED(hr)) {
20698             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device.");
20699             return ma_result_from_HRESULT(hr);
20700         }
20701
20702         c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_TRUE);
20703     }
20704
20705     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
20706         /* No need to do anything for playback as that'll be started automatically in the data loop. */
20707     }
20708
20709     return MA_SUCCESS;
20710 }
20711
20712 static ma_result ma_device_stop__wasapi(ma_device* pDevice)
20713 {
20714     ma_result result;
20715     HRESULT hr;
20716
20717     MA_ASSERT(pDevice != NULL);
20718
20719     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
20720         hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
20721         if (FAILED(hr)) {
20722             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device.");
20723             return ma_result_from_HRESULT(hr);
20724         }
20725
20726         /* The audio client needs to be reset otherwise restarting will fail. */
20727         hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
20728         if (FAILED(hr)) {
20729             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal capture device.");
20730             return ma_result_from_HRESULT(hr);
20731         }
20732
20733         c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_FALSE);
20734     }
20735
20736     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
20737         /*
20738         The buffer needs to be drained before stopping the device. Not doing this will result in the last few frames not getting output to
20739         the speakers. This is a problem for very short sounds because it'll result in a significant portion of it not getting played.
20740         */
20741         if (c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) {
20742             /* We need to make sure we put a timeout here or else we'll risk getting stuck in a deadlock in some cases. */
20743             DWORD waitTime = pDevice->wasapi.actualPeriodSizeInFramesPlayback / pDevice->playback.internalSampleRate;
20744
20745             if (pDevice->playback.shareMode == ma_share_mode_exclusive) {
20746                 WaitForSingleObject(pDevice->wasapi.hEventPlayback, waitTime);
20747             } else {
20748                 ma_uint32 prevFramesAvaialablePlayback = (ma_uint32)-1;
20749                 ma_uint32 framesAvailablePlayback;
20750                 for (;;) {
20751                     result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback);
20752                     if (result != MA_SUCCESS) {
20753                         break;
20754                     }
20755
20756                     if (framesAvailablePlayback >= pDevice->wasapi.actualPeriodSizeInFramesPlayback) {
20757                         break;
20758                     }
20759
20760                     /*
20761                     Just a safety check to avoid an infinite loop. If this iteration results in a situation where the number of available frames
20762                     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.
20763                     */
20764                     if (framesAvailablePlayback == prevFramesAvaialablePlayback) {
20765                         break;
20766                     }
20767                     prevFramesAvaialablePlayback = framesAvailablePlayback;
20768
20769                     WaitForSingleObject(pDevice->wasapi.hEventPlayback, waitTime);
20770                     ResetEvent(pDevice->wasapi.hEventPlayback); /* Manual reset. */
20771                 }
20772             }
20773         }
20774
20775         hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
20776         if (FAILED(hr)) {
20777             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal playback device.");
20778             return ma_result_from_HRESULT(hr);
20779         }
20780
20781         /* The audio client needs to be reset otherwise restarting will fail. */
20782         hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
20783         if (FAILED(hr)) {
20784             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal playback device.");
20785             return ma_result_from_HRESULT(hr);
20786         }
20787
20788         c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE);
20789     }
20790
20791     return MA_SUCCESS;
20792 }
20793
20794
20795 #ifndef MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS
20796 #define MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS 5000
20797 #endif
20798
20799 static ma_result ma_device_data_loop__wasapi(ma_device* pDevice)
20800 {
20801     ma_result result;
20802     HRESULT hr;
20803     ma_bool32 exitLoop = MA_FALSE;
20804     ma_uint32 framesWrittenToPlaybackDevice = 0;
20805     ma_uint32 mappedDeviceBufferSizeInFramesCapture = 0;
20806     ma_uint32 mappedDeviceBufferSizeInFramesPlayback = 0;
20807     ma_uint32 mappedDeviceBufferFramesRemainingCapture = 0;
20808     ma_uint32 mappedDeviceBufferFramesRemainingPlayback = 0;
20809     BYTE* pMappedDeviceBufferCapture = NULL;
20810     BYTE* pMappedDeviceBufferPlayback = NULL;
20811     ma_uint32 bpfCaptureDevice = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
20812     ma_uint32 bpfPlaybackDevice = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
20813     ma_uint32 bpfCaptureClient = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
20814     ma_uint32 bpfPlaybackClient = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
20815     ma_uint8  inputDataInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
20816     ma_uint32 inputDataInClientFormatCap = 0;
20817     ma_uint8  outputDataInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
20818     ma_uint32 outputDataInClientFormatCap = 0;
20819     ma_uint32 outputDataInClientFormatCount = 0;
20820     ma_uint32 outputDataInClientFormatConsumed = 0;
20821     ma_uint32 periodSizeInFramesCapture = 0;
20822
20823     MA_ASSERT(pDevice != NULL);
20824
20825     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
20826         periodSizeInFramesCapture  = pDevice->capture.internalPeriodSizeInFrames;
20827         inputDataInClientFormatCap = sizeof(inputDataInClientFormat) / bpfCaptureClient;
20828     }
20829
20830     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
20831         outputDataInClientFormatCap = sizeof(outputDataInClientFormat) / bpfPlaybackClient;
20832     }
20833
20834     while (ma_device_get_state(pDevice) == ma_device_state_started && !exitLoop) {
20835         switch (pDevice->type)
20836         {
20837             case ma_device_type_duplex:
20838             {
20839                 ma_uint32 framesAvailableCapture;
20840                 ma_uint32 framesAvailablePlayback;
20841                 DWORD flagsCapture;    /* Passed to IAudioCaptureClient_GetBuffer(). */
20842
20843                 /* The process is to map the playback buffer and fill it as quickly as possible from input data. */
20844                 if (pMappedDeviceBufferPlayback == NULL) {
20845                     result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback);
20846                     if (result != MA_SUCCESS) {
20847                         return result;
20848                     }
20849
20850                     /* In exclusive mode, the frame count needs to exactly match the value returned by GetCurrentPadding(). */
20851                     if (pDevice->playback.shareMode != ma_share_mode_exclusive) {
20852                         if (framesAvailablePlayback > pDevice->wasapi.periodSizeInFramesPlayback) {
20853                             framesAvailablePlayback = pDevice->wasapi.periodSizeInFramesPlayback;
20854                         }
20855                     }
20856
20857                     /* We're ready to map the playback device's buffer. We don't release this until it's been entirely filled. */
20858                     hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedDeviceBufferPlayback);
20859                     if (FAILED(hr)) {
20860                         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.");
20861                         exitLoop = MA_TRUE;
20862                         break;
20863                     }
20864
20865                     mappedDeviceBufferSizeInFramesPlayback    = framesAvailablePlayback;
20866                     mappedDeviceBufferFramesRemainingPlayback = framesAvailablePlayback;
20867                 }
20868
20869                 if (mappedDeviceBufferFramesRemainingPlayback > 0) {
20870                     /* At this point we should have a buffer available for output. We need to keep writing input samples to it. */
20871                     for (;;) {
20872                         /* Try grabbing some captured data if we haven't already got a mapped buffer. */
20873                         if (pMappedDeviceBufferCapture == NULL) {
20874                             if (pDevice->capture.shareMode == ma_share_mode_shared) {
20875                                 if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
20876                                     return MA_ERROR;   /* Wait failed. */
20877                                 }
20878                             }
20879
20880                             result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture);
20881                             if (result != MA_SUCCESS) {
20882                                 exitLoop = MA_TRUE;
20883                                 break;
20884                             }
20885
20886                             /* Wait for more if nothing is available. */
20887                             if (framesAvailableCapture == 0) {
20888                                 /* In exclusive mode we waited at the top. */
20889                                 if (pDevice->capture.shareMode != ma_share_mode_shared) {
20890                                     if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
20891                                         return MA_ERROR;   /* Wait failed. */
20892                                     }
20893                                 }
20894
20895                                 continue;
20896                             }
20897
20898                             /* Getting here means there's data available for writing to the output device. */
20899                             mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture);
20900                             hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
20901                             if (FAILED(hr)) {
20902                                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.");
20903                                 exitLoop = MA_TRUE;
20904                                 break;
20905                             }
20906
20907
20908                             /* Overrun detection. */
20909                             if ((flagsCapture & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) {
20910                                 /* Glitched. Probably due to an overrun. */
20911                                 ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity (possible overrun). framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
20912
20913                                 /*
20914                                 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
20915                                 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
20916                                 last period.
20917                                 */
20918                                 if (framesAvailableCapture >= pDevice->wasapi.actualPeriodSizeInFramesCapture) {
20919                                     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Synchronizing capture stream. ");
20920                                     do
20921                                     {
20922                                         hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
20923                                         if (FAILED(hr)) {
20924                                             break;
20925                                         }
20926
20927                                         framesAvailableCapture -= mappedDeviceBufferSizeInFramesCapture;
20928
20929                                         if (framesAvailableCapture > 0) {
20930                                             mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture);
20931                                             hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
20932                                             if (FAILED(hr)) {
20933                                                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.");
20934                                                 exitLoop = MA_TRUE;
20935                                                 break;
20936                                             }
20937                                         } else {
20938                                             pMappedDeviceBufferCapture = NULL;
20939                                             mappedDeviceBufferSizeInFramesCapture = 0;
20940                                         }
20941                                     } while (framesAvailableCapture > periodSizeInFramesCapture);
20942                                     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
20943                                 }
20944                             } else {
20945                             #ifdef MA_DEBUG_OUTPUT
20946                                 if (flagsCapture != 0) {
20947                                     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flagsCapture);
20948                                 }
20949                             #endif
20950                             }
20951
20952                             mappedDeviceBufferFramesRemainingCapture = mappedDeviceBufferSizeInFramesCapture;
20953                         }
20954
20955
20956                         /* 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. */
20957                         for (;;) {
20958                             BYTE* pRunningDeviceBufferCapture;
20959                             BYTE* pRunningDeviceBufferPlayback;
20960                             ma_uint32 framesToProcess;
20961                             ma_uint32 framesProcessed;
20962
20963                             pRunningDeviceBufferCapture  = pMappedDeviceBufferCapture  + ((mappedDeviceBufferSizeInFramesCapture  - mappedDeviceBufferFramesRemainingCapture ) * bpfCaptureDevice);
20964                             pRunningDeviceBufferPlayback = pMappedDeviceBufferPlayback + ((mappedDeviceBufferSizeInFramesPlayback - mappedDeviceBufferFramesRemainingPlayback) * bpfPlaybackDevice);
20965
20966                             /* There may be some data sitting in the converter that needs to be processed first. Once this is exhaused, run the data callback again. */
20967                             if (!pDevice->playback.converter.isPassthrough && outputDataInClientFormatConsumed < outputDataInClientFormatCount) {
20968                                 ma_uint64 convertedFrameCountClient = (outputDataInClientFormatCount - outputDataInClientFormatConsumed);
20969                                 ma_uint64 convertedFrameCountDevice = mappedDeviceBufferFramesRemainingPlayback;
20970                                 void* pConvertedFramesClient = outputDataInClientFormat + (outputDataInClientFormatConsumed * bpfPlaybackClient);
20971                                 void* pConvertedFramesDevice = pRunningDeviceBufferPlayback;
20972                                 result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pConvertedFramesClient, &convertedFrameCountClient, pConvertedFramesDevice, &convertedFrameCountDevice);
20973                                 if (result != MA_SUCCESS) {
20974                                     break;
20975                                 }
20976
20977                                 outputDataInClientFormatConsumed          += (ma_uint32)convertedFrameCountClient;  /* Safe cast. */
20978                                 mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)convertedFrameCountDevice;  /* Safe cast. */
20979
20980                                 if (mappedDeviceBufferFramesRemainingPlayback == 0) {
20981                                     break;
20982                                 }
20983                             }
20984
20985                             /*
20986                             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
20987                             buffers directly to the callback.
20988                             */
20989                             if (pDevice->capture.converter.isPassthrough && pDevice->playback.converter.isPassthrough) {
20990                                 /* Optimal path. We can pass mapped pointers directly to the callback. */
20991                                 framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, mappedDeviceBufferFramesRemainingPlayback);
20992                                 framesProcessed = framesToProcess;
20993
20994                                 ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, pRunningDeviceBufferCapture, framesToProcess);
20995
20996                                 mappedDeviceBufferFramesRemainingCapture  -= framesProcessed;
20997                                 mappedDeviceBufferFramesRemainingPlayback -= framesProcessed;
20998
20999                                 if (mappedDeviceBufferFramesRemainingCapture == 0) {
21000                                     break;  /* Exhausted input data. */
21001                                 }
21002                                 if (mappedDeviceBufferFramesRemainingPlayback == 0) {
21003                                     break;  /* Exhausted output data. */
21004                                 }
21005                             } else if (pDevice->capture.converter.isPassthrough) {
21006                                 /* The input buffer is a passthrough, but the playback buffer requires a conversion. */
21007                                 framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, outputDataInClientFormatCap);
21008                                 framesProcessed = framesToProcess;
21009
21010                                 ma_device__on_data(pDevice, outputDataInClientFormat, pRunningDeviceBufferCapture, framesToProcess);
21011                                 outputDataInClientFormatCount    = framesProcessed;
21012                                 outputDataInClientFormatConsumed = 0;
21013
21014                                 mappedDeviceBufferFramesRemainingCapture -= framesProcessed;
21015                                 if (mappedDeviceBufferFramesRemainingCapture == 0) {
21016                                     break;  /* Exhausted input data. */
21017                                 }
21018                             } else if (pDevice->playback.converter.isPassthrough) {
21019                                 /* The input buffer requires conversion, the playback buffer is passthrough. */
21020                                 ma_uint64 capturedDeviceFramesToProcess = mappedDeviceBufferFramesRemainingCapture;
21021                                 ma_uint64 capturedClientFramesToProcess = ma_min(inputDataInClientFormatCap, mappedDeviceBufferFramesRemainingPlayback);
21022
21023                                 result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningDeviceBufferCapture, &capturedDeviceFramesToProcess, inputDataInClientFormat, &capturedClientFramesToProcess);
21024                                 if (result != MA_SUCCESS) {
21025                                     break;
21026                                 }
21027
21028                                 if (capturedClientFramesToProcess == 0) {
21029                                     break;
21030                                 }
21031
21032                                 ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess);   /* Safe cast. */
21033
21034                                 mappedDeviceBufferFramesRemainingCapture  -= (ma_uint32)capturedDeviceFramesToProcess;
21035                                 mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)capturedClientFramesToProcess;
21036                             } else {
21037                                 ma_uint64 capturedDeviceFramesToProcess = mappedDeviceBufferFramesRemainingCapture;
21038                                 ma_uint64 capturedClientFramesToProcess = ma_min(inputDataInClientFormatCap, outputDataInClientFormatCap);
21039
21040                                 result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningDeviceBufferCapture, &capturedDeviceFramesToProcess, inputDataInClientFormat, &capturedClientFramesToProcess);
21041                                 if (result != MA_SUCCESS) {
21042                                     break;
21043                                 }
21044
21045                                 if (capturedClientFramesToProcess == 0) {
21046                                     break;
21047                                 }
21048
21049                                 ma_device__on_data(pDevice, outputDataInClientFormat, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess);
21050
21051                                 mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess;
21052                                 outputDataInClientFormatCount             = (ma_uint32)capturedClientFramesToProcess;
21053                                 outputDataInClientFormatConsumed          = 0;
21054                             }
21055                         }
21056
21057
21058                         /* If at this point we've run out of capture data we need to release the buffer. */
21059                         if (mappedDeviceBufferFramesRemainingCapture == 0 && pMappedDeviceBufferCapture != NULL) {
21060                             hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
21061                             if (FAILED(hr)) {
21062                                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device.");
21063                                 exitLoop = MA_TRUE;
21064                                 break;
21065                             }
21066
21067                             pMappedDeviceBufferCapture = NULL;
21068                             mappedDeviceBufferFramesRemainingCapture = 0;
21069                             mappedDeviceBufferSizeInFramesCapture    = 0;
21070                         }
21071
21072                         /* Get out of this loop if we're run out of room in the playback buffer. */
21073                         if (mappedDeviceBufferFramesRemainingPlayback == 0) {
21074                             break;
21075                         }
21076                     }
21077                 }
21078
21079
21080                 /* If at this point we've run out of data we need to release the buffer. */
21081                 if (mappedDeviceBufferFramesRemainingPlayback == 0 && pMappedDeviceBufferPlayback != NULL) {
21082                     hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedDeviceBufferSizeInFramesPlayback, 0);
21083                     if (FAILED(hr)) {
21084                         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.");
21085                         exitLoop = MA_TRUE;
21086                         break;
21087                     }
21088
21089                     framesWrittenToPlaybackDevice += mappedDeviceBufferSizeInFramesPlayback;
21090
21091                     pMappedDeviceBufferPlayback = NULL;
21092                     mappedDeviceBufferFramesRemainingPlayback = 0;
21093                     mappedDeviceBufferSizeInFramesPlayback    = 0;
21094                 }
21095
21096                 if (!c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) {
21097                     ma_uint32 startThreshold = pDevice->playback.internalPeriodSizeInFrames * 1;
21098
21099                     /* 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. */
21100                     if (startThreshold > pDevice->wasapi.actualPeriodSizeInFramesPlayback) {
21101                         startThreshold = pDevice->wasapi.actualPeriodSizeInFramesPlayback;
21102                     }
21103
21104                     if (pDevice->playback.shareMode == ma_share_mode_exclusive || framesWrittenToPlaybackDevice >= startThreshold) {
21105                         hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
21106                         if (FAILED(hr)) {
21107                             ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
21108                             ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
21109                             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.");
21110                             return ma_result_from_HRESULT(hr);
21111                         }
21112
21113                         c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE);
21114                     }
21115                 }
21116
21117                 /* Make sure the device has started before waiting. */
21118                 if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
21119                     return MA_ERROR;   /* Wait failed. */
21120                 }
21121             } break;
21122
21123
21124
21125             case ma_device_type_capture:
21126             case ma_device_type_loopback:
21127             {
21128                 ma_uint32 framesAvailableCapture;
21129                 DWORD flagsCapture;    /* Passed to IAudioCaptureClient_GetBuffer(). */
21130
21131                 /* Wait for data to become available first. */
21132                 if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
21133                     /*
21134                     For capture we can terminate here because it probably means the microphone just isn't delivering data for whatever reason, but
21135                     for loopback is most likely means nothing is actually playing. We want to keep trying in this situation.
21136                     */
21137                     if (pDevice->type == ma_device_type_loopback) {
21138                         continue;   /* Keep waiting in loopback mode. */
21139                     } else {
21140                         exitLoop = MA_TRUE;
21141                         break;      /* Wait failed. */
21142                     }
21143                 }
21144
21145                 /* 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. */
21146                 result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture);
21147                 if (result != MA_SUCCESS) {
21148                     exitLoop = MA_TRUE;
21149                     break;
21150                 }
21151
21152                 if (framesAvailableCapture < pDevice->wasapi.periodSizeInFramesCapture) {
21153                     continue;   /* Nothing available. Keep waiting. */
21154                 }
21155
21156                 /* Map the data buffer in preparation for sending to the client. */
21157                 mappedDeviceBufferSizeInFramesCapture = framesAvailableCapture;
21158                 hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
21159                 if (FAILED(hr)) {
21160                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.");
21161                     exitLoop = MA_TRUE;
21162                     break;
21163                 }
21164
21165                 /* Overrun detection. */
21166                 if ((flagsCapture & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) {
21167                     /* Glitched. Probably due to an overrun. */
21168                     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Data discontinuity (possible overrun). framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
21169
21170                     /*
21171                     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
21172                     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
21173                     last period.
21174                     */
21175                     if (framesAvailableCapture >= pDevice->wasapi.actualPeriodSizeInFramesCapture) {
21176                         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Synchronizing capture stream. ");
21177                         do
21178                         {
21179                             hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
21180                             if (FAILED(hr)) {
21181                                 break;
21182                             }
21183
21184                             framesAvailableCapture -= mappedDeviceBufferSizeInFramesCapture;
21185
21186                             if (framesAvailableCapture > 0) {
21187                                 mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture);
21188                                 hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
21189                                 if (FAILED(hr)) {
21190                                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.");
21191                                     exitLoop = MA_TRUE;
21192                                     break;
21193                                 }
21194                             } else {
21195                                 pMappedDeviceBufferCapture = NULL;
21196                                 mappedDeviceBufferSizeInFramesCapture = 0;
21197                             }
21198                         } while (framesAvailableCapture > periodSizeInFramesCapture);
21199                         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
21200                     }
21201                 } else {
21202                 #ifdef MA_DEBUG_OUTPUT
21203                     if (flagsCapture != 0) {
21204                         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[WASAPI] Capture Flags: %ld\n", flagsCapture);
21205                     }
21206                 #endif
21207                 }
21208
21209                 /* We should have a buffer at this point, but let's just do a sanity check anyway. */
21210                 if (mappedDeviceBufferSizeInFramesCapture > 0 && pMappedDeviceBufferCapture != NULL) {
21211                     ma_device__send_frames_to_client(pDevice, mappedDeviceBufferSizeInFramesCapture, pMappedDeviceBufferCapture);
21212
21213                     /* At this point we're done with the buffer. */
21214                     hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
21215                     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. */
21216                     mappedDeviceBufferSizeInFramesCapture = 0;
21217                     if (FAILED(hr)) {
21218                         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device.");
21219                         exitLoop = MA_TRUE;
21220                         break;
21221                     }
21222                 }
21223             } break;
21224
21225
21226
21227             case ma_device_type_playback:
21228             {
21229                 ma_uint32 framesAvailablePlayback;
21230
21231                 /* Check how much space is available. If this returns 0 we just keep waiting. */
21232                 result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback);
21233                 if (result != MA_SUCCESS) {
21234                     exitLoop = MA_TRUE;
21235                     break;
21236                 }
21237
21238                 if (framesAvailablePlayback >= pDevice->wasapi.periodSizeInFramesPlayback) {
21239                     /* Map a the data buffer in preparation for the callback. */
21240                     hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedDeviceBufferPlayback);
21241                     if (FAILED(hr)) {
21242                         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.");
21243                         exitLoop = MA_TRUE;
21244                         break;
21245                     }
21246
21247                     /* We should have a buffer at this point. */
21248                     ma_device__read_frames_from_client(pDevice, framesAvailablePlayback, pMappedDeviceBufferPlayback);
21249
21250                     /* At this point we're done writing to the device and we just need to release the buffer. */
21251                     hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, 0);
21252                     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. */
21253                     mappedDeviceBufferSizeInFramesPlayback = 0;
21254
21255                     if (FAILED(hr)) {
21256                         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.");
21257                         exitLoop = MA_TRUE;
21258                         break;
21259                     }
21260
21261                     framesWrittenToPlaybackDevice += framesAvailablePlayback;
21262                 }
21263
21264                 if (!c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) {
21265                     hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
21266                     if (FAILED(hr)) {
21267                         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.");
21268                         exitLoop = MA_TRUE;
21269                         break;
21270                     }
21271
21272                     c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE);
21273                 }
21274
21275                 /* Make sure we don't wait on the event before we've started the device or we may end up deadlocking. */
21276                 if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
21277                     exitLoop = MA_TRUE;
21278                     break;   /* Wait failed. Probably timed out. */
21279                 }
21280             } break;
21281
21282             default: return MA_INVALID_ARGS;
21283         }
21284     }
21285
21286     /* Here is where the device needs to be stopped. */
21287     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
21288         /* Any mapped buffers need to be released. */
21289         if (pMappedDeviceBufferCapture != NULL) {
21290             hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
21291         }
21292     }
21293
21294     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
21295         /* Any mapped buffers need to be released. */
21296         if (pMappedDeviceBufferPlayback != NULL) {
21297             hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedDeviceBufferSizeInFramesPlayback, 0);
21298         }
21299     }
21300
21301     return MA_SUCCESS;
21302 }
21303
21304 static ma_result ma_device_data_loop_wakeup__wasapi(ma_device* pDevice)
21305 {
21306     MA_ASSERT(pDevice != NULL);
21307
21308     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
21309         SetEvent((HANDLE)pDevice->wasapi.hEventCapture);
21310     }
21311
21312     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
21313         SetEvent((HANDLE)pDevice->wasapi.hEventPlayback);
21314     }
21315
21316     return MA_SUCCESS;
21317 }
21318
21319
21320 static ma_result ma_context_uninit__wasapi(ma_context* pContext)
21321 {
21322     MA_ASSERT(pContext != NULL);
21323     MA_ASSERT(pContext->backend == ma_backend_wasapi);
21324
21325     if (pContext->wasapi.commandThread != NULL) {
21326         ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_QUIT__WASAPI);
21327         ma_context_post_command__wasapi(pContext, &cmd);
21328         ma_thread_wait(&pContext->wasapi.commandThread);
21329
21330         /* Only after the thread has been terminated can we uninitialize the sync objects for the command thread. */
21331         ma_semaphore_uninit(&pContext->wasapi.commandSem);
21332         ma_mutex_uninit(&pContext->wasapi.commandLock);
21333     }
21334
21335     return MA_SUCCESS;
21336 }
21337
21338 static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
21339 {
21340     ma_result result = MA_SUCCESS;
21341
21342     MA_ASSERT(pContext != NULL);
21343
21344     (void)pConfig;
21345
21346 #ifdef MA_WIN32_DESKTOP
21347     /*
21348     WASAPI is only supported in Vista SP1 and newer. The reason for SP1 and not the base version of Vista is that event-driven
21349     exclusive mode does not work until SP1.
21350
21351     Unfortunately older compilers don't define these functions so we need to dynamically load them in order to avoid a link error.
21352     */
21353     {
21354         ma_OSVERSIONINFOEXW osvi;
21355         ma_handle kernel32DLL;
21356         ma_PFNVerifyVersionInfoW _VerifyVersionInfoW;
21357         ma_PFNVerSetConditionMask _VerSetConditionMask;
21358
21359         kernel32DLL = ma_dlopen(pContext, "kernel32.dll");
21360         if (kernel32DLL == NULL) {
21361             return MA_NO_BACKEND;
21362         }
21363
21364         _VerifyVersionInfoW  = (ma_PFNVerifyVersionInfoW )ma_dlsym(pContext, kernel32DLL, "VerifyVersionInfoW");
21365         _VerSetConditionMask = (ma_PFNVerSetConditionMask)ma_dlsym(pContext, kernel32DLL, "VerSetConditionMask");
21366         if (_VerifyVersionInfoW == NULL || _VerSetConditionMask == NULL) {
21367             ma_dlclose(pContext, kernel32DLL);
21368             return MA_NO_BACKEND;
21369         }
21370
21371         MA_ZERO_OBJECT(&osvi);
21372         osvi.dwOSVersionInfoSize = sizeof(osvi);
21373         osvi.dwMajorVersion = ((MA_WIN32_WINNT_VISTA >> 8) & 0xFF);
21374         osvi.dwMinorVersion = ((MA_WIN32_WINNT_VISTA >> 0) & 0xFF);
21375         osvi.wServicePackMajor = 1;
21376         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))) {
21377             result = MA_SUCCESS;
21378         } else {
21379             result = MA_NO_BACKEND;
21380         }
21381
21382         ma_dlclose(pContext, kernel32DLL);
21383     }
21384 #endif
21385
21386     if (result != MA_SUCCESS) {
21387         return result;
21388     }
21389
21390     MA_ZERO_OBJECT(&pContext->wasapi);
21391
21392     /*
21393     Annoyingly, WASAPI does not allow you to release an IAudioClient object from a different thread
21394     than the one that retrieved it with GetService(). This can result in a deadlock in two
21395     situations:
21396
21397         1) When calling ma_device_uninit() from a different thread to ma_device_init(); and
21398         2) When uninitializing and reinitializing the internal IAudioClient object in response to
21399            automatic stream routing.
21400
21401     We could define ma_device_uninit() such that it must be called on the same thread as
21402     ma_device_init(). We could also just not release the IAudioClient when performing automatic
21403     stream routing to avoid the deadlock. Neither of these are acceptable solutions in my view so
21404     we're going to have to work around this with a worker thread. This is not ideal, but I can't
21405     think of a better way to do this.
21406
21407     More information about this can be found here:
21408
21409         https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nn-audioclient-iaudiorenderclient
21410
21411     Note this section:
21412
21413         When releasing an IAudioRenderClient interface instance, the client must call the interface's
21414         Release method from the same thread as the call to IAudioClient::GetService that created the
21415         object.
21416     */
21417     {
21418         result = ma_mutex_init(&pContext->wasapi.commandLock);
21419         if (result != MA_SUCCESS) {
21420             return result;
21421         }
21422
21423         result = ma_semaphore_init(0, &pContext->wasapi.commandSem);
21424         if (result != MA_SUCCESS) {
21425             ma_mutex_uninit(&pContext->wasapi.commandLock);
21426             return result;
21427         }
21428
21429         result = ma_thread_create(&pContext->wasapi.commandThread, ma_thread_priority_normal, 0, ma_context_command_thread__wasapi, pContext, &pContext->allocationCallbacks);
21430         if (result != MA_SUCCESS) {
21431             ma_semaphore_uninit(&pContext->wasapi.commandSem);
21432             ma_mutex_uninit(&pContext->wasapi.commandLock);
21433             return result;
21434         }
21435     }
21436
21437
21438     pCallbacks->onContextInit             = ma_context_init__wasapi;
21439     pCallbacks->onContextUninit           = ma_context_uninit__wasapi;
21440     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__wasapi;
21441     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__wasapi;
21442     pCallbacks->onDeviceInit              = ma_device_init__wasapi;
21443     pCallbacks->onDeviceUninit            = ma_device_uninit__wasapi;
21444     pCallbacks->onDeviceStart             = ma_device_start__wasapi;
21445     pCallbacks->onDeviceStop              = ma_device_stop__wasapi;
21446     pCallbacks->onDeviceRead              = NULL;                   /* Not used. Reading is done manually in the audio thread. */
21447     pCallbacks->onDeviceWrite             = NULL;                   /* Not used. Writing is done manually in the audio thread. */
21448     pCallbacks->onDeviceDataLoop          = ma_device_data_loop__wasapi;
21449     pCallbacks->onDeviceDataLoopWakeup    = ma_device_data_loop_wakeup__wasapi;
21450
21451     return MA_SUCCESS;
21452 }
21453 #endif
21454
21455 /******************************************************************************
21456
21457 DirectSound Backend
21458
21459 ******************************************************************************/
21460 #ifdef MA_HAS_DSOUND
21461 /*#include <dsound.h>*/
21462
21463 /*static const GUID MA_GUID_IID_DirectSoundNotify = {0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}};*/
21464
21465 /* miniaudio only uses priority or exclusive modes. */
21466 #define MA_DSSCL_NORMAL                 1
21467 #define MA_DSSCL_PRIORITY               2
21468 #define MA_DSSCL_EXCLUSIVE              3
21469 #define MA_DSSCL_WRITEPRIMARY           4
21470
21471 #define MA_DSCAPS_PRIMARYMONO           0x00000001
21472 #define MA_DSCAPS_PRIMARYSTEREO         0x00000002
21473 #define MA_DSCAPS_PRIMARY8BIT           0x00000004
21474 #define MA_DSCAPS_PRIMARY16BIT          0x00000008
21475 #define MA_DSCAPS_CONTINUOUSRATE        0x00000010
21476 #define MA_DSCAPS_EMULDRIVER            0x00000020
21477 #define MA_DSCAPS_CERTIFIED             0x00000040
21478 #define MA_DSCAPS_SECONDARYMONO         0x00000100
21479 #define MA_DSCAPS_SECONDARYSTEREO       0x00000200
21480 #define MA_DSCAPS_SECONDARY8BIT         0x00000400
21481 #define MA_DSCAPS_SECONDARY16BIT        0x00000800
21482
21483 #define MA_DSBCAPS_PRIMARYBUFFER        0x00000001
21484 #define MA_DSBCAPS_STATIC               0x00000002
21485 #define MA_DSBCAPS_LOCHARDWARE          0x00000004
21486 #define MA_DSBCAPS_LOCSOFTWARE          0x00000008
21487 #define MA_DSBCAPS_CTRL3D               0x00000010
21488 #define MA_DSBCAPS_CTRLFREQUENCY        0x00000020
21489 #define MA_DSBCAPS_CTRLPAN              0x00000040
21490 #define MA_DSBCAPS_CTRLVOLUME           0x00000080
21491 #define MA_DSBCAPS_CTRLPOSITIONNOTIFY   0x00000100
21492 #define MA_DSBCAPS_CTRLFX               0x00000200
21493 #define MA_DSBCAPS_STICKYFOCUS          0x00004000
21494 #define MA_DSBCAPS_GLOBALFOCUS          0x00008000
21495 #define MA_DSBCAPS_GETCURRENTPOSITION2  0x00010000
21496 #define MA_DSBCAPS_MUTE3DATMAXDISTANCE  0x00020000
21497 #define MA_DSBCAPS_LOCDEFER             0x00040000
21498 #define MA_DSBCAPS_TRUEPLAYPOSITION     0x00080000
21499
21500 #define MA_DSBPLAY_LOOPING              0x00000001
21501 #define MA_DSBPLAY_LOCHARDWARE          0x00000002
21502 #define MA_DSBPLAY_LOCSOFTWARE          0x00000004
21503 #define MA_DSBPLAY_TERMINATEBY_TIME     0x00000008
21504 #define MA_DSBPLAY_TERMINATEBY_DISTANCE 0x00000010
21505 #define MA_DSBPLAY_TERMINATEBY_PRIORITY 0x00000020
21506
21507 #define MA_DSCBSTART_LOOPING            0x00000001
21508
21509 typedef struct
21510 {
21511     DWORD dwSize;
21512     DWORD dwFlags;
21513     DWORD dwBufferBytes;
21514     DWORD dwReserved;
21515     WAVEFORMATEX* lpwfxFormat;
21516     GUID guid3DAlgorithm;
21517 } MA_DSBUFFERDESC;
21518
21519 typedef struct
21520 {
21521     DWORD dwSize;
21522     DWORD dwFlags;
21523     DWORD dwBufferBytes;
21524     DWORD dwReserved;
21525     WAVEFORMATEX* lpwfxFormat;
21526     DWORD dwFXCount;
21527     void* lpDSCFXDesc;  /* <-- miniaudio doesn't use this, so set to void*. */
21528 } MA_DSCBUFFERDESC;
21529
21530 typedef struct
21531 {
21532     DWORD dwSize;
21533     DWORD dwFlags;
21534     DWORD dwMinSecondarySampleRate;
21535     DWORD dwMaxSecondarySampleRate;
21536     DWORD dwPrimaryBuffers;
21537     DWORD dwMaxHwMixingAllBuffers;
21538     DWORD dwMaxHwMixingStaticBuffers;
21539     DWORD dwMaxHwMixingStreamingBuffers;
21540     DWORD dwFreeHwMixingAllBuffers;
21541     DWORD dwFreeHwMixingStaticBuffers;
21542     DWORD dwFreeHwMixingStreamingBuffers;
21543     DWORD dwMaxHw3DAllBuffers;
21544     DWORD dwMaxHw3DStaticBuffers;
21545     DWORD dwMaxHw3DStreamingBuffers;
21546     DWORD dwFreeHw3DAllBuffers;
21547     DWORD dwFreeHw3DStaticBuffers;
21548     DWORD dwFreeHw3DStreamingBuffers;
21549     DWORD dwTotalHwMemBytes;
21550     DWORD dwFreeHwMemBytes;
21551     DWORD dwMaxContigFreeHwMemBytes;
21552     DWORD dwUnlockTransferRateHwBuffers;
21553     DWORD dwPlayCpuOverheadSwBuffers;
21554     DWORD dwReserved1;
21555     DWORD dwReserved2;
21556 } MA_DSCAPS;
21557
21558 typedef struct
21559 {
21560     DWORD dwSize;
21561     DWORD dwFlags;
21562     DWORD dwBufferBytes;
21563     DWORD dwUnlockTransferRate;
21564     DWORD dwPlayCpuOverhead;
21565 } MA_DSBCAPS;
21566
21567 typedef struct
21568 {
21569     DWORD dwSize;
21570     DWORD dwFlags;
21571     DWORD dwFormats;
21572     DWORD dwChannels;
21573 } MA_DSCCAPS;
21574
21575 typedef struct
21576 {
21577     DWORD dwSize;
21578     DWORD dwFlags;
21579     DWORD dwBufferBytes;
21580     DWORD dwReserved;
21581 } MA_DSCBCAPS;
21582
21583 typedef struct
21584 {
21585     DWORD  dwOffset;
21586     HANDLE hEventNotify;
21587 } MA_DSBPOSITIONNOTIFY;
21588
21589 typedef struct ma_IDirectSound              ma_IDirectSound;
21590 typedef struct ma_IDirectSoundBuffer        ma_IDirectSoundBuffer;
21591 typedef struct ma_IDirectSoundCapture       ma_IDirectSoundCapture;
21592 typedef struct ma_IDirectSoundCaptureBuffer ma_IDirectSoundCaptureBuffer;
21593 typedef struct ma_IDirectSoundNotify        ma_IDirectSoundNotify;
21594
21595
21596 /*
21597 COM objects. The way these work is that you have a vtable (a list of function pointers, kind of
21598 like how C++ works internally), and then you have a structure with a single member, which is a
21599 pointer to the vtable. The vtable is where the methods of the object are defined. Methods need
21600 to be in a specific order, and parent classes need to have their methods declared first.
21601 */
21602
21603 /* IDirectSound */
21604 typedef struct
21605 {
21606     /* IUnknown */
21607     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSound* pThis, const IID* const riid, void** ppObject);
21608     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IDirectSound* pThis);
21609     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IDirectSound* pThis);
21610
21611     /* IDirectSound */
21612     HRESULT (STDMETHODCALLTYPE * CreateSoundBuffer)   (ma_IDirectSound* pThis, const MA_DSBUFFERDESC* pDSBufferDesc, ma_IDirectSoundBuffer** ppDSBuffer, void* pUnkOuter);
21613     HRESULT (STDMETHODCALLTYPE * GetCaps)             (ma_IDirectSound* pThis, MA_DSCAPS* pDSCaps);
21614     HRESULT (STDMETHODCALLTYPE * DuplicateSoundBuffer)(ma_IDirectSound* pThis, ma_IDirectSoundBuffer* pDSBufferOriginal, ma_IDirectSoundBuffer** ppDSBufferDuplicate);
21615     HRESULT (STDMETHODCALLTYPE * SetCooperativeLevel) (ma_IDirectSound* pThis, HWND hwnd, DWORD dwLevel);
21616     HRESULT (STDMETHODCALLTYPE * Compact)             (ma_IDirectSound* pThis);
21617     HRESULT (STDMETHODCALLTYPE * GetSpeakerConfig)    (ma_IDirectSound* pThis, DWORD* pSpeakerConfig);
21618     HRESULT (STDMETHODCALLTYPE * SetSpeakerConfig)    (ma_IDirectSound* pThis, DWORD dwSpeakerConfig);
21619     HRESULT (STDMETHODCALLTYPE * Initialize)          (ma_IDirectSound* pThis, const GUID* pGuidDevice);
21620 } ma_IDirectSoundVtbl;
21621 struct ma_IDirectSound
21622 {
21623     ma_IDirectSoundVtbl* lpVtbl;
21624 };
21625 static MA_INLINE HRESULT ma_IDirectSound_QueryInterface(ma_IDirectSound* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
21626 static MA_INLINE ULONG   ma_IDirectSound_AddRef(ma_IDirectSound* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
21627 static MA_INLINE ULONG   ma_IDirectSound_Release(ma_IDirectSound* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
21628 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); }
21629 static MA_INLINE HRESULT ma_IDirectSound_GetCaps(ma_IDirectSound* pThis, MA_DSCAPS* pDSCaps)                            { return pThis->lpVtbl->GetCaps(pThis, pDSCaps); }
21630 static MA_INLINE HRESULT ma_IDirectSound_DuplicateSoundBuffer(ma_IDirectSound* pThis, ma_IDirectSoundBuffer* pDSBufferOriginal, ma_IDirectSoundBuffer** ppDSBufferDuplicate) { return pThis->lpVtbl->DuplicateSoundBuffer(pThis, pDSBufferOriginal, ppDSBufferDuplicate); }
21631 static MA_INLINE HRESULT ma_IDirectSound_SetCooperativeLevel(ma_IDirectSound* pThis, HWND hwnd, DWORD dwLevel)          { return pThis->lpVtbl->SetCooperativeLevel(pThis, hwnd, dwLevel); }
21632 static MA_INLINE HRESULT ma_IDirectSound_Compact(ma_IDirectSound* pThis)                                                { return pThis->lpVtbl->Compact(pThis); }
21633 static MA_INLINE HRESULT ma_IDirectSound_GetSpeakerConfig(ma_IDirectSound* pThis, DWORD* pSpeakerConfig)                { return pThis->lpVtbl->GetSpeakerConfig(pThis, pSpeakerConfig); }
21634 static MA_INLINE HRESULT ma_IDirectSound_SetSpeakerConfig(ma_IDirectSound* pThis, DWORD dwSpeakerConfig)                { return pThis->lpVtbl->SetSpeakerConfig(pThis, dwSpeakerConfig); }
21635 static MA_INLINE HRESULT ma_IDirectSound_Initialize(ma_IDirectSound* pThis, const GUID* pGuidDevice)                    { return pThis->lpVtbl->Initialize(pThis, pGuidDevice); }
21636
21637
21638 /* IDirectSoundBuffer */
21639 typedef struct
21640 {
21641     /* IUnknown */
21642     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundBuffer* pThis, const IID* const riid, void** ppObject);
21643     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IDirectSoundBuffer* pThis);
21644     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IDirectSoundBuffer* pThis);
21645
21646     /* IDirectSoundBuffer */
21647     HRESULT (STDMETHODCALLTYPE * GetCaps)           (ma_IDirectSoundBuffer* pThis, MA_DSBCAPS* pDSBufferCaps);
21648     HRESULT (STDMETHODCALLTYPE * GetCurrentPosition)(ma_IDirectSoundBuffer* pThis, DWORD* pCurrentPlayCursor, DWORD* pCurrentWriteCursor);
21649     HRESULT (STDMETHODCALLTYPE * GetFormat)         (ma_IDirectSoundBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten);
21650     HRESULT (STDMETHODCALLTYPE * GetVolume)         (ma_IDirectSoundBuffer* pThis, LONG* pVolume);
21651     HRESULT (STDMETHODCALLTYPE * GetPan)            (ma_IDirectSoundBuffer* pThis, LONG* pPan);
21652     HRESULT (STDMETHODCALLTYPE * GetFrequency)      (ma_IDirectSoundBuffer* pThis, DWORD* pFrequency);
21653     HRESULT (STDMETHODCALLTYPE * GetStatus)         (ma_IDirectSoundBuffer* pThis, DWORD* pStatus);
21654     HRESULT (STDMETHODCALLTYPE * Initialize)        (ma_IDirectSoundBuffer* pThis, ma_IDirectSound* pDirectSound, const MA_DSBUFFERDESC* pDSBufferDesc);
21655     HRESULT (STDMETHODCALLTYPE * Lock)              (ma_IDirectSoundBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags);
21656     HRESULT (STDMETHODCALLTYPE * Play)              (ma_IDirectSoundBuffer* pThis, DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags);
21657     HRESULT (STDMETHODCALLTYPE * SetCurrentPosition)(ma_IDirectSoundBuffer* pThis, DWORD dwNewPosition);
21658     HRESULT (STDMETHODCALLTYPE * SetFormat)         (ma_IDirectSoundBuffer* pThis, const WAVEFORMATEX* pFormat);
21659     HRESULT (STDMETHODCALLTYPE * SetVolume)         (ma_IDirectSoundBuffer* pThis, LONG volume);
21660     HRESULT (STDMETHODCALLTYPE * SetPan)            (ma_IDirectSoundBuffer* pThis, LONG pan);
21661     HRESULT (STDMETHODCALLTYPE * SetFrequency)      (ma_IDirectSoundBuffer* pThis, DWORD dwFrequency);
21662     HRESULT (STDMETHODCALLTYPE * Stop)              (ma_IDirectSoundBuffer* pThis);
21663     HRESULT (STDMETHODCALLTYPE * Unlock)            (ma_IDirectSoundBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2);
21664     HRESULT (STDMETHODCALLTYPE * Restore)           (ma_IDirectSoundBuffer* pThis);
21665 } ma_IDirectSoundBufferVtbl;
21666 struct ma_IDirectSoundBuffer
21667 {
21668     ma_IDirectSoundBufferVtbl* lpVtbl;
21669 };
21670 static MA_INLINE HRESULT ma_IDirectSoundBuffer_QueryInterface(ma_IDirectSoundBuffer* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
21671 static MA_INLINE ULONG   ma_IDirectSoundBuffer_AddRef(ma_IDirectSoundBuffer* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
21672 static MA_INLINE ULONG   ma_IDirectSoundBuffer_Release(ma_IDirectSoundBuffer* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
21673 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetCaps(ma_IDirectSoundBuffer* pThis, MA_DSBCAPS* pDSBufferCaps)                     { return pThis->lpVtbl->GetCaps(pThis, pDSBufferCaps); }
21674 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetCurrentPosition(ma_IDirectSoundBuffer* pThis, DWORD* pCurrentPlayCursor, DWORD* pCurrentWriteCursor) { return pThis->lpVtbl->GetCurrentPosition(pThis, pCurrentPlayCursor, pCurrentWriteCursor); }
21675 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetFormat(ma_IDirectSoundBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); }
21676 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetVolume(ma_IDirectSoundBuffer* pThis, LONG* pVolume)                               { return pThis->lpVtbl->GetVolume(pThis, pVolume); }
21677 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetPan(ma_IDirectSoundBuffer* pThis, LONG* pPan)                                     { return pThis->lpVtbl->GetPan(pThis, pPan); }
21678 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetFrequency(ma_IDirectSoundBuffer* pThis, DWORD* pFrequency)                        { return pThis->lpVtbl->GetFrequency(pThis, pFrequency); }
21679 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetStatus(ma_IDirectSoundBuffer* pThis, DWORD* pStatus)                              { return pThis->lpVtbl->GetStatus(pThis, pStatus); }
21680 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Initialize(ma_IDirectSoundBuffer* pThis, ma_IDirectSound* pDirectSound, const MA_DSBUFFERDESC* pDSBufferDesc) { return pThis->lpVtbl->Initialize(pThis, pDirectSound, pDSBufferDesc); }
21681 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); }
21682 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Play(ma_IDirectSoundBuffer* pThis, DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) { return pThis->lpVtbl->Play(pThis, dwReserved1, dwPriority, dwFlags); }
21683 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetCurrentPosition(ma_IDirectSoundBuffer* pThis, DWORD dwNewPosition)                { return pThis->lpVtbl->SetCurrentPosition(pThis, dwNewPosition); }
21684 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetFormat(ma_IDirectSoundBuffer* pThis, const WAVEFORMATEX* pFormat)                 { return pThis->lpVtbl->SetFormat(pThis, pFormat); }
21685 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetVolume(ma_IDirectSoundBuffer* pThis, LONG volume)                                 { return pThis->lpVtbl->SetVolume(pThis, volume); }
21686 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetPan(ma_IDirectSoundBuffer* pThis, LONG pan)                                       { return pThis->lpVtbl->SetPan(pThis, pan); }
21687 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetFrequency(ma_IDirectSoundBuffer* pThis, DWORD dwFrequency)                        { return pThis->lpVtbl->SetFrequency(pThis, dwFrequency); }
21688 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Stop(ma_IDirectSoundBuffer* pThis)                                                   { return pThis->lpVtbl->Stop(pThis); }
21689 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); }
21690 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Restore(ma_IDirectSoundBuffer* pThis)                                                { return pThis->lpVtbl->Restore(pThis); }
21691
21692
21693 /* IDirectSoundCapture */
21694 typedef struct
21695 {
21696     /* IUnknown */
21697     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject);
21698     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IDirectSoundCapture* pThis);
21699     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IDirectSoundCapture* pThis);
21700
21701     /* IDirectSoundCapture */
21702     HRESULT (STDMETHODCALLTYPE * CreateCaptureBuffer)(ma_IDirectSoundCapture* pThis, const MA_DSCBUFFERDESC* pDSCBufferDesc, ma_IDirectSoundCaptureBuffer** ppDSCBuffer, void* pUnkOuter);
21703     HRESULT (STDMETHODCALLTYPE * GetCaps)            (ma_IDirectSoundCapture* pThis, MA_DSCCAPS* pDSCCaps);
21704     HRESULT (STDMETHODCALLTYPE * Initialize)         (ma_IDirectSoundCapture* pThis, const GUID* pGuidDevice);
21705 } ma_IDirectSoundCaptureVtbl;
21706 struct ma_IDirectSoundCapture
21707 {
21708     ma_IDirectSoundCaptureVtbl* lpVtbl;
21709 };
21710 static MA_INLINE HRESULT ma_IDirectSoundCapture_QueryInterface     (ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
21711 static MA_INLINE ULONG   ma_IDirectSoundCapture_AddRef             (ma_IDirectSoundCapture* pThis)                                    { return pThis->lpVtbl->AddRef(pThis); }
21712 static MA_INLINE ULONG   ma_IDirectSoundCapture_Release            (ma_IDirectSoundCapture* pThis)                                    { return pThis->lpVtbl->Release(pThis); }
21713 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); }
21714 static MA_INLINE HRESULT ma_IDirectSoundCapture_GetCaps            (ma_IDirectSoundCapture* pThis, MA_DSCCAPS* pDSCCaps)              { return pThis->lpVtbl->GetCaps(pThis, pDSCCaps); }
21715 static MA_INLINE HRESULT ma_IDirectSoundCapture_Initialize         (ma_IDirectSoundCapture* pThis, const GUID* pGuidDevice)           { return pThis->lpVtbl->Initialize(pThis, pGuidDevice); }
21716
21717
21718 /* IDirectSoundCaptureBuffer */
21719 typedef struct
21720 {
21721     /* IUnknown */
21722     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundCaptureBuffer* pThis, const IID* const riid, void** ppObject);
21723     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IDirectSoundCaptureBuffer* pThis);
21724     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IDirectSoundCaptureBuffer* pThis);
21725
21726     /* IDirectSoundCaptureBuffer */
21727     HRESULT (STDMETHODCALLTYPE * GetCaps)           (ma_IDirectSoundCaptureBuffer* pThis, MA_DSCBCAPS* pDSCBCaps);
21728     HRESULT (STDMETHODCALLTYPE * GetCurrentPosition)(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pCapturePosition, DWORD* pReadPosition);
21729     HRESULT (STDMETHODCALLTYPE * GetFormat)         (ma_IDirectSoundCaptureBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten);
21730     HRESULT (STDMETHODCALLTYPE * GetStatus)         (ma_IDirectSoundCaptureBuffer* pThis, DWORD* pStatus);
21731     HRESULT (STDMETHODCALLTYPE * Initialize)        (ma_IDirectSoundCaptureBuffer* pThis, ma_IDirectSoundCapture* pDirectSoundCapture, const MA_DSCBUFFERDESC* pDSCBufferDesc);
21732     HRESULT (STDMETHODCALLTYPE * Lock)              (ma_IDirectSoundCaptureBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags);
21733     HRESULT (STDMETHODCALLTYPE * Start)             (ma_IDirectSoundCaptureBuffer* pThis, DWORD dwFlags);
21734     HRESULT (STDMETHODCALLTYPE * Stop)              (ma_IDirectSoundCaptureBuffer* pThis);
21735     HRESULT (STDMETHODCALLTYPE * Unlock)            (ma_IDirectSoundCaptureBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2);
21736 } ma_IDirectSoundCaptureBufferVtbl;
21737 struct ma_IDirectSoundCaptureBuffer
21738 {
21739     ma_IDirectSoundCaptureBufferVtbl* lpVtbl;
21740 };
21741 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_QueryInterface(ma_IDirectSoundCaptureBuffer* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
21742 static MA_INLINE ULONG   ma_IDirectSoundCaptureBuffer_AddRef(ma_IDirectSoundCaptureBuffer* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
21743 static MA_INLINE ULONG   ma_IDirectSoundCaptureBuffer_Release(ma_IDirectSoundCaptureBuffer* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
21744 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetCaps(ma_IDirectSoundCaptureBuffer* pThis, MA_DSCBCAPS* pDSCBCaps)                        { return pThis->lpVtbl->GetCaps(pThis, pDSCBCaps); }
21745 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetCurrentPosition(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pCapturePosition, DWORD* pReadPosition) { return pThis->lpVtbl->GetCurrentPosition(pThis, pCapturePosition, pReadPosition); }
21746 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetFormat(ma_IDirectSoundCaptureBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); }
21747 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetStatus(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pStatus)                              { return pThis->lpVtbl->GetStatus(pThis, pStatus); }
21748 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Initialize(ma_IDirectSoundCaptureBuffer* pThis, ma_IDirectSoundCapture* pDirectSoundCapture, const MA_DSCBUFFERDESC* pDSCBufferDesc) { return pThis->lpVtbl->Initialize(pThis, pDirectSoundCapture, pDSCBufferDesc); }
21749 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); }
21750 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Start(ma_IDirectSoundCaptureBuffer* pThis, DWORD dwFlags)                                   { return pThis->lpVtbl->Start(pThis, dwFlags); }
21751 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Stop(ma_IDirectSoundCaptureBuffer* pThis)                                                   { return pThis->lpVtbl->Stop(pThis); }
21752 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); }
21753
21754
21755 /* IDirectSoundNotify */
21756 typedef struct
21757 {
21758     /* IUnknown */
21759     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundNotify* pThis, const IID* const riid, void** ppObject);
21760     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IDirectSoundNotify* pThis);
21761     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IDirectSoundNotify* pThis);
21762
21763     /* IDirectSoundNotify */
21764     HRESULT (STDMETHODCALLTYPE * SetNotificationPositions)(ma_IDirectSoundNotify* pThis, DWORD dwPositionNotifies, const MA_DSBPOSITIONNOTIFY* pPositionNotifies);
21765 } ma_IDirectSoundNotifyVtbl;
21766 struct ma_IDirectSoundNotify
21767 {
21768     ma_IDirectSoundNotifyVtbl* lpVtbl;
21769 };
21770 static MA_INLINE HRESULT ma_IDirectSoundNotify_QueryInterface(ma_IDirectSoundNotify* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
21771 static MA_INLINE ULONG   ma_IDirectSoundNotify_AddRef(ma_IDirectSoundNotify* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
21772 static MA_INLINE ULONG   ma_IDirectSoundNotify_Release(ma_IDirectSoundNotify* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
21773 static MA_INLINE HRESULT ma_IDirectSoundNotify_SetNotificationPositions(ma_IDirectSoundNotify* pThis, DWORD dwPositionNotifies, const MA_DSBPOSITIONNOTIFY* pPositionNotifies) { return pThis->lpVtbl->SetNotificationPositions(pThis, dwPositionNotifies, pPositionNotifies); }
21774
21775
21776 typedef BOOL    (CALLBACK * ma_DSEnumCallbackAProc)             (LPGUID pDeviceGUID, LPCSTR pDeviceDescription, LPCSTR pModule, LPVOID pContext);
21777 typedef HRESULT (WINAPI   * ma_DirectSoundCreateProc)           (const GUID* pcGuidDevice, ma_IDirectSound** ppDS8, LPUNKNOWN pUnkOuter);
21778 typedef HRESULT (WINAPI   * ma_DirectSoundEnumerateAProc)       (ma_DSEnumCallbackAProc pDSEnumCallback, LPVOID pContext);
21779 typedef HRESULT (WINAPI   * ma_DirectSoundCaptureCreateProc)    (const GUID* pcGuidDevice, ma_IDirectSoundCapture** ppDSC8, LPUNKNOWN pUnkOuter);
21780 typedef HRESULT (WINAPI   * ma_DirectSoundCaptureEnumerateAProc)(ma_DSEnumCallbackAProc pDSEnumCallback, LPVOID pContext);
21781
21782 static ma_uint32 ma_get_best_sample_rate_within_range(ma_uint32 sampleRateMin, ma_uint32 sampleRateMax)
21783 {
21784     /* Normalize the range in case we were given something stupid. */
21785     if (sampleRateMin < (ma_uint32)ma_standard_sample_rate_min) {
21786         sampleRateMin = (ma_uint32)ma_standard_sample_rate_min;
21787     }
21788     if (sampleRateMax > (ma_uint32)ma_standard_sample_rate_max) {
21789         sampleRateMax = (ma_uint32)ma_standard_sample_rate_max;
21790     }
21791     if (sampleRateMin > sampleRateMax) {
21792         sampleRateMin = sampleRateMax;
21793     }
21794
21795     if (sampleRateMin == sampleRateMax) {
21796         return sampleRateMax;
21797     } else {
21798         size_t iStandardRate;
21799         for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) {
21800             ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate];
21801             if (standardRate >= sampleRateMin && standardRate <= sampleRateMax) {
21802                 return standardRate;
21803             }
21804         }
21805     }
21806
21807     /* Should never get here. */
21808     MA_ASSERT(MA_FALSE);
21809     return 0;
21810 }
21811
21812 /*
21813 Retrieves the channel count and channel map for the given speaker configuration. If the speaker configuration is unknown,
21814 the channel count and channel map will be left unmodified.
21815 */
21816 static void ma_get_channels_from_speaker_config__dsound(DWORD speakerConfig, WORD* pChannelsOut, DWORD* pChannelMapOut)
21817 {
21818     WORD  channels;
21819     DWORD channelMap;
21820
21821     channels = 0;
21822     if (pChannelsOut != NULL) {
21823         channels = *pChannelsOut;
21824     }
21825
21826     channelMap = 0;
21827     if (pChannelMapOut != NULL) {
21828         channelMap = *pChannelMapOut;
21829     }
21830
21831     /*
21832     The speaker configuration is a combination of speaker config and speaker geometry. The lower 8 bits is what we care about. The upper
21833     16 bits is for the geometry.
21834     */
21835     switch ((BYTE)(speakerConfig)) {
21836         case 1 /*DSSPEAKER_HEADPHONE*/:                          channels = 2; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break;
21837         case 2 /*DSSPEAKER_MONO*/:                               channels = 1; channelMap = SPEAKER_FRONT_CENTER; break;
21838         case 3 /*DSSPEAKER_QUAD*/:                               channels = 4; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
21839         case 4 /*DSSPEAKER_STEREO*/:                             channels = 2; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break;
21840         case 5 /*DSSPEAKER_SURROUND*/:                           channels = 4; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER; break;
21841         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;
21842         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;
21843         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;
21844         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;
21845         default: break;
21846     }
21847
21848     if (pChannelsOut != NULL) {
21849         *pChannelsOut = channels;
21850     }
21851
21852     if (pChannelMapOut != NULL) {
21853         *pChannelMapOut = channelMap;
21854     }
21855 }
21856
21857
21858 static ma_result ma_context_create_IDirectSound__dsound(ma_context* pContext, ma_share_mode shareMode, const ma_device_id* pDeviceID, ma_IDirectSound** ppDirectSound)
21859 {
21860     ma_IDirectSound* pDirectSound;
21861     HWND hWnd;
21862     HRESULT hr;
21863
21864     MA_ASSERT(pContext != NULL);
21865     MA_ASSERT(ppDirectSound != NULL);
21866
21867     *ppDirectSound = NULL;
21868     pDirectSound = NULL;
21869
21870     if (FAILED(((ma_DirectSoundCreateProc)pContext->dsound.DirectSoundCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSound, NULL))) {
21871         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCreate() failed for playback device.");
21872         return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
21873     }
21874
21875     /* The cooperative level must be set before doing anything else. */
21876     hWnd = ((MA_PFN_GetForegroundWindow)pContext->win32.GetForegroundWindow)();
21877     if (hWnd == NULL) {
21878         hWnd = ((MA_PFN_GetDesktopWindow)pContext->win32.GetDesktopWindow)();
21879     }
21880
21881     hr = ma_IDirectSound_SetCooperativeLevel(pDirectSound, hWnd, (shareMode == ma_share_mode_exclusive) ? MA_DSSCL_EXCLUSIVE : MA_DSSCL_PRIORITY);
21882     if (FAILED(hr)) {
21883         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device.");
21884         return ma_result_from_HRESULT(hr);
21885     }
21886
21887     *ppDirectSound = pDirectSound;
21888     return MA_SUCCESS;
21889 }
21890
21891 static ma_result ma_context_create_IDirectSoundCapture__dsound(ma_context* pContext, ma_share_mode shareMode, const ma_device_id* pDeviceID, ma_IDirectSoundCapture** ppDirectSoundCapture)
21892 {
21893     ma_IDirectSoundCapture* pDirectSoundCapture;
21894     HRESULT hr;
21895
21896     MA_ASSERT(pContext != NULL);
21897     MA_ASSERT(ppDirectSoundCapture != NULL);
21898
21899     /* DirectSound does not support exclusive mode for capture. */
21900     if (shareMode == ma_share_mode_exclusive) {
21901         return MA_SHARE_MODE_NOT_SUPPORTED;
21902     }
21903
21904     *ppDirectSoundCapture = NULL;
21905     pDirectSoundCapture = NULL;
21906
21907     hr = ((ma_DirectSoundCaptureCreateProc)pContext->dsound.DirectSoundCaptureCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSoundCapture, NULL);
21908     if (FAILED(hr)) {
21909         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCaptureCreate() failed for capture device.");
21910         return ma_result_from_HRESULT(hr);
21911     }
21912
21913     *ppDirectSoundCapture = pDirectSoundCapture;
21914     return MA_SUCCESS;
21915 }
21916
21917 static ma_result ma_context_get_format_info_for_IDirectSoundCapture__dsound(ma_context* pContext, ma_IDirectSoundCapture* pDirectSoundCapture, WORD* pChannels, WORD* pBitsPerSample, DWORD* pSampleRate)
21918 {
21919     HRESULT hr;
21920     MA_DSCCAPS caps;
21921     WORD bitsPerSample;
21922     DWORD sampleRate;
21923
21924     MA_ASSERT(pContext != NULL);
21925     MA_ASSERT(pDirectSoundCapture != NULL);
21926
21927     if (pChannels) {
21928         *pChannels = 0;
21929     }
21930     if (pBitsPerSample) {
21931         *pBitsPerSample = 0;
21932     }
21933     if (pSampleRate) {
21934         *pSampleRate = 0;
21935     }
21936
21937     MA_ZERO_OBJECT(&caps);
21938     caps.dwSize = sizeof(caps);
21939     hr = ma_IDirectSoundCapture_GetCaps(pDirectSoundCapture, &caps);
21940     if (FAILED(hr)) {
21941         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_GetCaps() failed for capture device.");
21942         return ma_result_from_HRESULT(hr);
21943     }
21944
21945     if (pChannels) {
21946         *pChannels = (WORD)caps.dwChannels;
21947     }
21948
21949     /* 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. */
21950     bitsPerSample = 16;
21951     sampleRate = 48000;
21952
21953     if (caps.dwChannels == 1) {
21954         if ((caps.dwFormats & WAVE_FORMAT_48M16) != 0) {
21955             sampleRate = 48000;
21956         } else if ((caps.dwFormats & WAVE_FORMAT_44M16) != 0) {
21957             sampleRate = 44100;
21958         } else if ((caps.dwFormats & WAVE_FORMAT_2M16) != 0) {
21959             sampleRate = 22050;
21960         } else if ((caps.dwFormats & WAVE_FORMAT_1M16) != 0) {
21961             sampleRate = 11025;
21962         } else if ((caps.dwFormats & WAVE_FORMAT_96M16) != 0) {
21963             sampleRate = 96000;
21964         } else {
21965             bitsPerSample = 8;
21966             if ((caps.dwFormats & WAVE_FORMAT_48M08) != 0) {
21967                 sampleRate = 48000;
21968             } else if ((caps.dwFormats & WAVE_FORMAT_44M08) != 0) {
21969                 sampleRate = 44100;
21970             } else if ((caps.dwFormats & WAVE_FORMAT_2M08) != 0) {
21971                 sampleRate = 22050;
21972             } else if ((caps.dwFormats & WAVE_FORMAT_1M08) != 0) {
21973                 sampleRate = 11025;
21974             } else if ((caps.dwFormats & WAVE_FORMAT_96M08) != 0) {
21975                 sampleRate = 96000;
21976             } else {
21977                 bitsPerSample = 16;  /* Didn't find it. Just fall back to 16-bit. */
21978             }
21979         }
21980     } else if (caps.dwChannels == 2) {
21981         if ((caps.dwFormats & WAVE_FORMAT_48S16) != 0) {
21982             sampleRate = 48000;
21983         } else if ((caps.dwFormats & WAVE_FORMAT_44S16) != 0) {
21984             sampleRate = 44100;
21985         } else if ((caps.dwFormats & WAVE_FORMAT_2S16) != 0) {
21986             sampleRate = 22050;
21987         } else if ((caps.dwFormats & WAVE_FORMAT_1S16) != 0) {
21988             sampleRate = 11025;
21989         } else if ((caps.dwFormats & WAVE_FORMAT_96S16) != 0) {
21990             sampleRate = 96000;
21991         } else {
21992             bitsPerSample = 8;
21993             if ((caps.dwFormats & WAVE_FORMAT_48S08) != 0) {
21994                 sampleRate = 48000;
21995             } else if ((caps.dwFormats & WAVE_FORMAT_44S08) != 0) {
21996                 sampleRate = 44100;
21997             } else if ((caps.dwFormats & WAVE_FORMAT_2S08) != 0) {
21998                 sampleRate = 22050;
21999             } else if ((caps.dwFormats & WAVE_FORMAT_1S08) != 0) {
22000                 sampleRate = 11025;
22001             } else if ((caps.dwFormats & WAVE_FORMAT_96S08) != 0) {
22002                 sampleRate = 96000;
22003             } else {
22004                 bitsPerSample = 16;  /* Didn't find it. Just fall back to 16-bit. */
22005             }
22006         }
22007     }
22008
22009     if (pBitsPerSample) {
22010         *pBitsPerSample = bitsPerSample;
22011     }
22012     if (pSampleRate) {
22013         *pSampleRate = sampleRate;
22014     }
22015
22016     return MA_SUCCESS;
22017 }
22018
22019
22020 typedef struct
22021 {
22022     ma_context* pContext;
22023     ma_device_type deviceType;
22024     ma_enum_devices_callback_proc callback;
22025     void* pUserData;
22026     ma_bool32 terminated;
22027 } ma_context_enumerate_devices_callback_data__dsound;
22028
22029 static BOOL CALLBACK ma_context_enumerate_devices_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext)
22030 {
22031     ma_context_enumerate_devices_callback_data__dsound* pData = (ma_context_enumerate_devices_callback_data__dsound*)lpContext;
22032     ma_device_info deviceInfo;
22033
22034     (void)lpcstrModule;
22035
22036     MA_ZERO_OBJECT(&deviceInfo);
22037
22038     /* ID. */
22039     if (lpGuid != NULL) {
22040         MA_COPY_MEMORY(deviceInfo.id.dsound, lpGuid, 16);
22041     } else {
22042         MA_ZERO_MEMORY(deviceInfo.id.dsound, 16);
22043         deviceInfo.isDefault = MA_TRUE;
22044     }
22045
22046     /* Name / Description */
22047     ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), lpcstrDescription, (size_t)-1);
22048
22049
22050     /* Call the callback function, but make sure we stop enumerating if the callee requested so. */
22051     MA_ASSERT(pData != NULL);
22052     pData->terminated = !pData->callback(pData->pContext, pData->deviceType, &deviceInfo, pData->pUserData);
22053     if (pData->terminated) {
22054         return FALSE;   /* Stop enumeration. */
22055     } else {
22056         return TRUE;    /* Continue enumeration. */
22057     }
22058 }
22059
22060 static ma_result ma_context_enumerate_devices__dsound(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
22061 {
22062     ma_context_enumerate_devices_callback_data__dsound data;
22063
22064     MA_ASSERT(pContext != NULL);
22065     MA_ASSERT(callback != NULL);
22066
22067     data.pContext = pContext;
22068     data.callback = callback;
22069     data.pUserData = pUserData;
22070     data.terminated = MA_FALSE;
22071
22072     /* Playback. */
22073     if (!data.terminated) {
22074         data.deviceType = ma_device_type_playback;
22075         ((ma_DirectSoundEnumerateAProc)pContext->dsound.DirectSoundEnumerateA)(ma_context_enumerate_devices_callback__dsound, &data);
22076     }
22077
22078     /* Capture. */
22079     if (!data.terminated) {
22080         data.deviceType = ma_device_type_capture;
22081         ((ma_DirectSoundCaptureEnumerateAProc)pContext->dsound.DirectSoundCaptureEnumerateA)(ma_context_enumerate_devices_callback__dsound, &data);
22082     }
22083
22084     return MA_SUCCESS;
22085 }
22086
22087
22088 typedef struct
22089 {
22090     const ma_device_id* pDeviceID;
22091     ma_device_info* pDeviceInfo;
22092     ma_bool32 found;
22093 } ma_context_get_device_info_callback_data__dsound;
22094
22095 static BOOL CALLBACK ma_context_get_device_info_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext)
22096 {
22097     ma_context_get_device_info_callback_data__dsound* pData = (ma_context_get_device_info_callback_data__dsound*)lpContext;
22098     MA_ASSERT(pData != NULL);
22099
22100     if ((pData->pDeviceID == NULL || ma_is_guid_null(pData->pDeviceID->dsound)) && (lpGuid == NULL || ma_is_guid_null(lpGuid))) {
22101         /* Default device. */
22102         ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), lpcstrDescription, (size_t)-1);
22103         pData->pDeviceInfo->isDefault = MA_TRUE;
22104         pData->found = MA_TRUE;
22105         return FALSE;   /* Stop enumeration. */
22106     } else {
22107         /* Not the default device. */
22108         if (lpGuid != NULL && pData->pDeviceID != NULL) {
22109             if (memcmp(pData->pDeviceID->dsound, lpGuid, sizeof(pData->pDeviceID->dsound)) == 0) {
22110                 ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), lpcstrDescription, (size_t)-1);
22111                 pData->found = MA_TRUE;
22112                 return FALSE;   /* Stop enumeration. */
22113             }
22114         }
22115     }
22116
22117     (void)lpcstrModule;
22118     return TRUE;
22119 }
22120
22121 static ma_result ma_context_get_device_info__dsound(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
22122 {
22123     ma_result result;
22124     HRESULT hr;
22125
22126     if (pDeviceID != NULL) {
22127         ma_context_get_device_info_callback_data__dsound data;
22128
22129         /* ID. */
22130         MA_COPY_MEMORY(pDeviceInfo->id.dsound, pDeviceID->dsound, 16);
22131
22132         /* Name / Description. This is retrieved by enumerating over each device until we find that one that matches the input ID. */
22133         data.pDeviceID = pDeviceID;
22134         data.pDeviceInfo = pDeviceInfo;
22135         data.found = MA_FALSE;
22136         if (deviceType == ma_device_type_playback) {
22137             ((ma_DirectSoundEnumerateAProc)pContext->dsound.DirectSoundEnumerateA)(ma_context_get_device_info_callback__dsound, &data);
22138         } else {
22139             ((ma_DirectSoundCaptureEnumerateAProc)pContext->dsound.DirectSoundCaptureEnumerateA)(ma_context_get_device_info_callback__dsound, &data);
22140         }
22141
22142         if (!data.found) {
22143             return MA_NO_DEVICE;
22144         }
22145     } else {
22146         /* 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. */
22147
22148         /* ID */
22149         MA_ZERO_MEMORY(pDeviceInfo->id.dsound, 16);
22150
22151         /* Name / Description */
22152         if (deviceType == ma_device_type_playback) {
22153             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
22154         } else {
22155             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
22156         }
22157
22158         pDeviceInfo->isDefault = MA_TRUE;
22159     }
22160
22161     /* Retrieving detailed information is slightly different depending on the device type. */
22162     if (deviceType == ma_device_type_playback) {
22163         /* Playback. */
22164         ma_IDirectSound* pDirectSound;
22165         MA_DSCAPS caps;
22166         WORD channels;
22167
22168         result = ma_context_create_IDirectSound__dsound(pContext, ma_share_mode_shared, pDeviceID, &pDirectSound);
22169         if (result != MA_SUCCESS) {
22170             return result;
22171         }
22172
22173         MA_ZERO_OBJECT(&caps);
22174         caps.dwSize = sizeof(caps);
22175         hr = ma_IDirectSound_GetCaps(pDirectSound, &caps);
22176         if (FAILED(hr)) {
22177             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.");
22178             return ma_result_from_HRESULT(hr);
22179         }
22180
22181
22182         /* Channels. Only a single channel count is reported for DirectSound. */
22183         if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) {
22184             /* It supports at least stereo, but could support more. */
22185             DWORD speakerConfig;
22186
22187             channels = 2;
22188
22189             /* Look at the speaker configuration to get a better idea on the channel count. */
22190             hr = ma_IDirectSound_GetSpeakerConfig(pDirectSound, &speakerConfig);
22191             if (SUCCEEDED(hr)) {
22192                 ma_get_channels_from_speaker_config__dsound(speakerConfig, &channels, NULL);
22193             }
22194         } else {
22195             /* It does not support stereo, which means we are stuck with mono. */
22196             channels = 1;
22197         }
22198
22199
22200         /*
22201         In DirectSound, our native formats are centered around sample rates. All formats are supported, and we're only reporting a single channel
22202         count. However, DirectSound can report a range of supported sample rates. We're only going to include standard rates known by miniaudio
22203         in order to keep the size of this within reason.
22204         */
22205         if ((caps.dwFlags & MA_DSCAPS_CONTINUOUSRATE) != 0) {
22206             /* Multiple sample rates are supported. We'll report in order of our preferred sample rates. */
22207             size_t iStandardSampleRate;
22208             for (iStandardSampleRate = 0; iStandardSampleRate < ma_countof(g_maStandardSampleRatePriorities); iStandardSampleRate += 1) {
22209                 ma_uint32 sampleRate = g_maStandardSampleRatePriorities[iStandardSampleRate];
22210                 if (sampleRate >= caps.dwMinSecondarySampleRate && sampleRate <= caps.dwMaxSecondarySampleRate) {
22211                     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = ma_format_unknown;
22212                     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
22213                     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate;
22214                     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = 0;
22215                     pDeviceInfo->nativeDataFormatCount += 1;
22216                 }
22217             }
22218         } else {
22219             /* Only a single sample rate is supported. */
22220             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = ma_format_unknown;
22221             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
22222             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = caps.dwMaxSecondarySampleRate;
22223             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = 0;
22224             pDeviceInfo->nativeDataFormatCount += 1;
22225         }
22226
22227         ma_IDirectSound_Release(pDirectSound);
22228     } else {
22229         /*
22230         Capture. This is a little different to playback due to the say the supported formats are reported. Technically capture
22231         devices can support a number of different formats, but for simplicity and consistency with ma_device_init() I'm just
22232         reporting the best format.
22233         */
22234         ma_IDirectSoundCapture* pDirectSoundCapture;
22235         WORD channels;
22236         WORD bitsPerSample;
22237         DWORD sampleRate;
22238
22239         result = ma_context_create_IDirectSoundCapture__dsound(pContext, ma_share_mode_shared, pDeviceID, &pDirectSoundCapture);
22240         if (result != MA_SUCCESS) {
22241             return result;
22242         }
22243
22244         result = ma_context_get_format_info_for_IDirectSoundCapture__dsound(pContext, pDirectSoundCapture, &channels, &bitsPerSample, &sampleRate);
22245         if (result != MA_SUCCESS) {
22246             ma_IDirectSoundCapture_Release(pDirectSoundCapture);
22247             return result;
22248         }
22249
22250         ma_IDirectSoundCapture_Release(pDirectSoundCapture);
22251
22252         /* The format is always an integer format and is based on the bits per sample. */
22253         if (bitsPerSample == 8) {
22254             pDeviceInfo->nativeDataFormats[0].format = ma_format_u8;
22255         } else if (bitsPerSample == 16) {
22256             pDeviceInfo->nativeDataFormats[0].format = ma_format_s16;
22257         } else if (bitsPerSample == 24) {
22258             pDeviceInfo->nativeDataFormats[0].format = ma_format_s24;
22259         } else if (bitsPerSample == 32) {
22260             pDeviceInfo->nativeDataFormats[0].format = ma_format_s32;
22261         } else {
22262             return MA_FORMAT_NOT_SUPPORTED;
22263         }
22264
22265         pDeviceInfo->nativeDataFormats[0].channels   = channels;
22266         pDeviceInfo->nativeDataFormats[0].sampleRate = sampleRate;
22267         pDeviceInfo->nativeDataFormats[0].flags      = 0;
22268         pDeviceInfo->nativeDataFormatCount = 1;
22269     }
22270
22271     return MA_SUCCESS;
22272 }
22273
22274
22275
22276 static ma_result ma_device_uninit__dsound(ma_device* pDevice)
22277 {
22278     MA_ASSERT(pDevice != NULL);
22279
22280     if (pDevice->dsound.pCaptureBuffer != NULL) {
22281         ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
22282     }
22283     if (pDevice->dsound.pCapture != NULL) {
22284         ma_IDirectSoundCapture_Release((ma_IDirectSoundCapture*)pDevice->dsound.pCapture);
22285     }
22286
22287     if (pDevice->dsound.pPlaybackBuffer != NULL) {
22288         ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer);
22289     }
22290     if (pDevice->dsound.pPlaybackPrimaryBuffer != NULL) {
22291         ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer);
22292     }
22293     if (pDevice->dsound.pPlayback != NULL) {
22294         ma_IDirectSound_Release((ma_IDirectSound*)pDevice->dsound.pPlayback);
22295     }
22296
22297     return MA_SUCCESS;
22298 }
22299
22300 static ma_result ma_config_to_WAVEFORMATEXTENSIBLE(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const ma_channel* pChannelMap, WAVEFORMATEXTENSIBLE* pWF)
22301 {
22302     GUID subformat;
22303
22304     if (format == ma_format_unknown) {
22305         format = MA_DEFAULT_FORMAT;
22306     }
22307
22308     if (channels == 0) {
22309         channels = MA_DEFAULT_CHANNELS;
22310     }
22311
22312     if (sampleRate == 0) {
22313         sampleRate = MA_DEFAULT_SAMPLE_RATE;
22314     }
22315
22316     switch (format)
22317     {
22318         case ma_format_u8:
22319         case ma_format_s16:
22320         case ma_format_s24:
22321         /*case ma_format_s24_32:*/
22322         case ma_format_s32:
22323         {
22324             subformat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
22325         } break;
22326
22327         case ma_format_f32:
22328         {
22329             subformat = MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
22330         } break;
22331
22332         default:
22333         return MA_FORMAT_NOT_SUPPORTED;
22334     }
22335
22336     MA_ZERO_OBJECT(pWF);
22337     pWF->Format.cbSize               = sizeof(*pWF);
22338     pWF->Format.wFormatTag           = WAVE_FORMAT_EXTENSIBLE;
22339     pWF->Format.nChannels            = (WORD)channels;
22340     pWF->Format.nSamplesPerSec       = (DWORD)sampleRate;
22341     pWF->Format.wBitsPerSample       = (WORD)(ma_get_bytes_per_sample(format)*8);
22342     pWF->Format.nBlockAlign          = (WORD)(pWF->Format.nChannels * pWF->Format.wBitsPerSample / 8);
22343     pWF->Format.nAvgBytesPerSec      = pWF->Format.nBlockAlign * pWF->Format.nSamplesPerSec;
22344     pWF->Samples.wValidBitsPerSample = pWF->Format.wBitsPerSample;
22345     pWF->dwChannelMask               = ma_channel_map_to_channel_mask__win32(pChannelMap, channels);
22346     pWF->SubFormat                   = subformat;
22347
22348     return MA_SUCCESS;
22349 }
22350
22351 static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__dsound(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile)
22352 {
22353     /* DirectSound has a minimum period size of 20ms. */
22354     ma_uint32 minPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(20, nativeSampleRate);
22355     ma_uint32 periodSizeInFrames;
22356
22357     periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, nativeSampleRate, performanceProfile);
22358     if (periodSizeInFrames < minPeriodSizeInFrames) {
22359         periodSizeInFrames = minPeriodSizeInFrames;
22360     }
22361
22362     return periodSizeInFrames;
22363 }
22364
22365 static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
22366 {
22367     ma_result result;
22368     HRESULT hr;
22369
22370     MA_ASSERT(pDevice != NULL);
22371
22372     MA_ZERO_OBJECT(&pDevice->dsound);
22373
22374     if (pConfig->deviceType == ma_device_type_loopback) {
22375         return MA_DEVICE_TYPE_NOT_SUPPORTED;
22376     }
22377
22378     /*
22379     Unfortunately DirectSound uses different APIs and data structures for playback and catpure devices. We need to initialize
22380     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
22381     full-duplex mode.
22382     */
22383     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
22384         WAVEFORMATEXTENSIBLE wf;
22385         MA_DSCBUFFERDESC descDS;
22386         ma_uint32 periodSizeInFrames;
22387         ma_uint32 periodCount;
22388         char rawdata[1024]; /* <-- Ugly hack to avoid a malloc() due to a crappy DirectSound API. */
22389         WAVEFORMATEXTENSIBLE* pActualFormat;
22390
22391         result = ma_config_to_WAVEFORMATEXTENSIBLE(pDescriptorCapture->format, pDescriptorCapture->channels, pDescriptorCapture->sampleRate, pDescriptorCapture->channelMap, &wf);
22392         if (result != MA_SUCCESS) {
22393             return result;
22394         }
22395
22396         result = ma_context_create_IDirectSoundCapture__dsound(pDevice->pContext, pDescriptorCapture->shareMode, pDescriptorCapture->pDeviceID, (ma_IDirectSoundCapture**)&pDevice->dsound.pCapture);
22397         if (result != MA_SUCCESS) {
22398             ma_device_uninit__dsound(pDevice);
22399             return result;
22400         }
22401
22402         result = ma_context_get_format_info_for_IDirectSoundCapture__dsound(pDevice->pContext, (ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &wf.Format.nChannels, &wf.Format.wBitsPerSample, &wf.Format.nSamplesPerSec);
22403         if (result != MA_SUCCESS) {
22404             ma_device_uninit__dsound(pDevice);
22405             return result;
22406         }
22407
22408         wf.Format.nBlockAlign          = (WORD)(wf.Format.nChannels * wf.Format.wBitsPerSample / 8);
22409         wf.Format.nAvgBytesPerSec      = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
22410         wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample;
22411         wf.SubFormat                   = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
22412
22413         /* The size of the buffer must be a clean multiple of the period count. */
22414         periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__dsound(pDescriptorCapture, wf.Format.nSamplesPerSec, pConfig->performanceProfile);
22415         periodCount = (pDescriptorCapture->periodCount > 0) ? pDescriptorCapture->periodCount : MA_DEFAULT_PERIODS;
22416
22417         MA_ZERO_OBJECT(&descDS);
22418         descDS.dwSize        = sizeof(descDS);
22419         descDS.dwFlags       = 0;
22420         descDS.dwBufferBytes = periodSizeInFrames * periodCount * wf.Format.nBlockAlign;
22421         descDS.lpwfxFormat   = (WAVEFORMATEX*)&wf;
22422         hr = ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL);
22423         if (FAILED(hr)) {
22424             ma_device_uninit__dsound(pDevice);
22425             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.");
22426             return ma_result_from_HRESULT(hr);
22427         }
22428
22429         /* Get the _actual_ properties of the buffer. */
22430         pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata;
22431         hr = ma_IDirectSoundCaptureBuffer_GetFormat((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL);
22432         if (FAILED(hr)) {
22433             ma_device_uninit__dsound(pDevice);
22434             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the capture device's buffer.");
22435             return ma_result_from_HRESULT(hr);
22436         }
22437
22438         /* We can now start setting the output data formats. */
22439         pDescriptorCapture->format     = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)pActualFormat);
22440         pDescriptorCapture->channels   = pActualFormat->Format.nChannels;
22441         pDescriptorCapture->sampleRate = pActualFormat->Format.nSamplesPerSec;
22442
22443         /* Get the native channel map based on the channel mask. */
22444         if (pActualFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
22445             ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDescriptorCapture->channels, pDescriptorCapture->channelMap);
22446         } else {
22447             ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDescriptorCapture->channels, pDescriptorCapture->channelMap);
22448         }
22449
22450         /*
22451         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
22452         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.
22453         */
22454         if (periodSizeInFrames != (descDS.dwBufferBytes / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / periodCount)) {
22455             descDS.dwBufferBytes = periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) * periodCount;
22456             ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
22457
22458             hr = ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL);
22459             if (FAILED(hr)) {
22460                 ma_device_uninit__dsound(pDevice);
22461                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Second attempt at IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.");
22462                 return ma_result_from_HRESULT(hr);
22463             }
22464         }
22465
22466         /* DirectSound should give us a buffer exactly the size we asked for. */
22467         pDescriptorCapture->periodSizeInFrames = periodSizeInFrames;
22468         pDescriptorCapture->periodCount        = periodCount;
22469     }
22470
22471     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
22472         WAVEFORMATEXTENSIBLE wf;
22473         MA_DSBUFFERDESC descDSPrimary;
22474         MA_DSCAPS caps;
22475         char rawdata[1024]; /* <-- Ugly hack to avoid a malloc() due to a crappy DirectSound API. */
22476         WAVEFORMATEXTENSIBLE* pActualFormat;
22477         ma_uint32 periodSizeInFrames;
22478         ma_uint32 periodCount;
22479         MA_DSBUFFERDESC descDS;
22480
22481         result = ma_config_to_WAVEFORMATEXTENSIBLE(pDescriptorPlayback->format, pDescriptorPlayback->channels, pDescriptorPlayback->sampleRate, pDescriptorPlayback->channelMap, &wf);
22482         if (result != MA_SUCCESS) {
22483             return result;
22484         }
22485
22486         result = ma_context_create_IDirectSound__dsound(pDevice->pContext, pDescriptorPlayback->shareMode, pDescriptorPlayback->pDeviceID, (ma_IDirectSound**)&pDevice->dsound.pPlayback);
22487         if (result != MA_SUCCESS) {
22488             ma_device_uninit__dsound(pDevice);
22489             return result;
22490         }
22491
22492         MA_ZERO_OBJECT(&descDSPrimary);
22493         descDSPrimary.dwSize  = sizeof(MA_DSBUFFERDESC);
22494         descDSPrimary.dwFlags = MA_DSBCAPS_PRIMARYBUFFER | MA_DSBCAPS_CTRLVOLUME;
22495         hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDSPrimary, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackPrimaryBuffer, NULL);
22496         if (FAILED(hr)) {
22497             ma_device_uninit__dsound(pDevice);
22498             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's primary buffer.");
22499             return ma_result_from_HRESULT(hr);
22500         }
22501
22502
22503         /* We may want to make some adjustments to the format if we are using defaults. */
22504         MA_ZERO_OBJECT(&caps);
22505         caps.dwSize = sizeof(caps);
22506         hr = ma_IDirectSound_GetCaps((ma_IDirectSound*)pDevice->dsound.pPlayback, &caps);
22507         if (FAILED(hr)) {
22508             ma_device_uninit__dsound(pDevice);
22509             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.");
22510             return ma_result_from_HRESULT(hr);
22511         }
22512
22513         if (pDescriptorPlayback->channels == 0) {
22514             if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) {
22515                 DWORD speakerConfig;
22516
22517                 /* It supports at least stereo, but could support more. */
22518                 wf.Format.nChannels = 2;
22519
22520                 /* Look at the speaker configuration to get a better idea on the channel count. */
22521                 if (SUCCEEDED(ma_IDirectSound_GetSpeakerConfig((ma_IDirectSound*)pDevice->dsound.pPlayback, &speakerConfig))) {
22522                     ma_get_channels_from_speaker_config__dsound(speakerConfig, &wf.Format.nChannels, &wf.dwChannelMask);
22523                 }
22524             } else {
22525                 /* It does not support stereo, which means we are stuck with mono. */
22526                 wf.Format.nChannels = 1;
22527             }
22528         }
22529
22530         if (pDescriptorPlayback->sampleRate == 0) {
22531             /* We base the sample rate on the values returned by GetCaps(). */
22532             if ((caps.dwFlags & MA_DSCAPS_CONTINUOUSRATE) != 0) {
22533                 wf.Format.nSamplesPerSec = ma_get_best_sample_rate_within_range(caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate);
22534             } else {
22535                 wf.Format.nSamplesPerSec = caps.dwMaxSecondarySampleRate;
22536             }
22537         }
22538
22539         wf.Format.nBlockAlign     = (WORD)(wf.Format.nChannels * wf.Format.wBitsPerSample / 8);
22540         wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
22541
22542         /*
22543         From MSDN:
22544
22545         The method succeeds even if the hardware does not support the requested format; DirectSound sets the buffer to the closest
22546         supported format. To determine whether this has happened, an application can call the GetFormat method for the primary buffer
22547         and compare the result with the format that was requested with the SetFormat method.
22548         */
22549         hr = ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)&wf);
22550         if (FAILED(hr)) {
22551             ma_device_uninit__dsound(pDevice);
22552             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer.");
22553             return ma_result_from_HRESULT(hr);
22554         }
22555
22556         /* Get the _actual_ properties of the buffer. */
22557         pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata;
22558         hr = ma_IDirectSoundBuffer_GetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL);
22559         if (FAILED(hr)) {
22560             ma_device_uninit__dsound(pDevice);
22561             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.");
22562             return ma_result_from_HRESULT(hr);
22563         }
22564
22565         /* We now have enough information to start setting some output properties. */
22566         pDescriptorPlayback->format     = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)pActualFormat);
22567         pDescriptorPlayback->channels   = pActualFormat->Format.nChannels;
22568         pDescriptorPlayback->sampleRate = pActualFormat->Format.nSamplesPerSec;
22569
22570         /* Get the internal channel map based on the channel mask. */
22571         if (pActualFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
22572             ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap);
22573         } else {
22574             ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap);
22575         }
22576
22577         /* The size of the buffer must be a clean multiple of the period count. */
22578         periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__dsound(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
22579         periodCount = (pDescriptorPlayback->periodCount > 0) ? pDescriptorPlayback->periodCount : MA_DEFAULT_PERIODS;
22580
22581         /*
22582         Meaning of dwFlags (from MSDN):
22583
22584         DSBCAPS_CTRLPOSITIONNOTIFY
22585           The buffer has position notification capability.
22586
22587         DSBCAPS_GLOBALFOCUS
22588           With this flag set, an application using DirectSound can continue to play its buffers if the user switches focus to
22589           another application, even if the new application uses DirectSound.
22590
22591         DSBCAPS_GETCURRENTPOSITION2
22592           In the first version of DirectSound, the play cursor was significantly ahead of the actual playing sound on emulated
22593           sound cards; it was directly behind the write cursor. Now, if the DSBCAPS_GETCURRENTPOSITION2 flag is specified, the
22594           application can get a more accurate play cursor.
22595         */
22596         MA_ZERO_OBJECT(&descDS);
22597         descDS.dwSize = sizeof(descDS);
22598         descDS.dwFlags = MA_DSBCAPS_CTRLPOSITIONNOTIFY | MA_DSBCAPS_GLOBALFOCUS | MA_DSBCAPS_GETCURRENTPOSITION2;
22599         descDS.dwBufferBytes = periodSizeInFrames * periodCount * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels);
22600         descDS.lpwfxFormat = (WAVEFORMATEX*)&wf;
22601         hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDS, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackBuffer, NULL);
22602         if (FAILED(hr)) {
22603             ma_device_uninit__dsound(pDevice);
22604             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer.");
22605             return ma_result_from_HRESULT(hr);
22606         }
22607
22608         /* DirectSound should give us a buffer exactly the size we asked for. */
22609         pDescriptorPlayback->periodSizeInFrames = periodSizeInFrames;
22610         pDescriptorPlayback->periodCount        = periodCount;
22611     }
22612
22613     return MA_SUCCESS;
22614 }
22615
22616
22617 static ma_result ma_device_data_loop__dsound(ma_device* pDevice)
22618 {
22619     ma_result result = MA_SUCCESS;
22620     ma_uint32 bpfDeviceCapture  = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
22621     ma_uint32 bpfDevicePlayback = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
22622     HRESULT hr;
22623     DWORD lockOffsetInBytesCapture;
22624     DWORD lockSizeInBytesCapture;
22625     DWORD mappedSizeInBytesCapture;
22626     DWORD mappedDeviceFramesProcessedCapture;
22627     void* pMappedDeviceBufferCapture;
22628     DWORD lockOffsetInBytesPlayback;
22629     DWORD lockSizeInBytesPlayback;
22630     DWORD mappedSizeInBytesPlayback;
22631     void* pMappedDeviceBufferPlayback;
22632     DWORD prevReadCursorInBytesCapture = 0;
22633     DWORD prevPlayCursorInBytesPlayback = 0;
22634     ma_bool32 physicalPlayCursorLoopFlagPlayback = 0;
22635     DWORD virtualWriteCursorInBytesPlayback = 0;
22636     ma_bool32 virtualWriteCursorLoopFlagPlayback = 0;
22637     ma_bool32 isPlaybackDeviceStarted = MA_FALSE;
22638     ma_uint32 framesWrittenToPlaybackDevice = 0;   /* For knowing whether or not the playback device needs to be started. */
22639     ma_uint32 waitTimeInMilliseconds = 1;
22640
22641     MA_ASSERT(pDevice != NULL);
22642
22643     /* The first thing to do is start the capture device. The playback device is only started after the first period is written. */
22644     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
22645         hr = ma_IDirectSoundCaptureBuffer_Start((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, MA_DSCBSTART_LOOPING);
22646         if (FAILED(hr)) {
22647             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed.");
22648             return ma_result_from_HRESULT(hr);
22649         }
22650     }
22651
22652     while (ma_device_get_state(pDevice) == ma_device_state_started) {
22653         switch (pDevice->type)
22654         {
22655             case ma_device_type_duplex:
22656             {
22657                 DWORD physicalCaptureCursorInBytes;
22658                 DWORD physicalReadCursorInBytes;
22659                 hr = ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, &physicalCaptureCursorInBytes, &physicalReadCursorInBytes);
22660                 if (FAILED(hr)) {
22661                     return ma_result_from_HRESULT(hr);
22662                 }
22663
22664                 /* If nothing is available we just sleep for a bit and return from this iteration. */
22665                 if (physicalReadCursorInBytes == prevReadCursorInBytesCapture) {
22666                     ma_sleep(waitTimeInMilliseconds);
22667                     continue; /* Nothing is available in the capture buffer. */
22668                 }
22669
22670                 /*
22671                 The current position has moved. We need to map all of the captured samples and write them to the playback device, making sure
22672                 we don't return until every frame has been copied over.
22673                 */
22674                 if (prevReadCursorInBytesCapture < physicalReadCursorInBytes) {
22675                     /* The capture position has not looped. This is the simple case. */
22676                     lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
22677                     lockSizeInBytesCapture   = (physicalReadCursorInBytes - prevReadCursorInBytesCapture);
22678                 } else {
22679                     /*
22680                     The capture position has looped. This is the more complex case. Map to the end of the buffer. If this does not return anything,
22681                     do it again from the start.
22682                     */
22683                     if (prevReadCursorInBytesCapture < pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) {
22684                         /* Lock up to the end of the buffer. */
22685                         lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
22686                         lockSizeInBytesCapture   = (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) - prevReadCursorInBytesCapture;
22687                     } else {
22688                         /* Lock starting from the start of the buffer. */
22689                         lockOffsetInBytesCapture = 0;
22690                         lockSizeInBytesCapture   = physicalReadCursorInBytes;
22691                     }
22692                 }
22693
22694                 if (lockSizeInBytesCapture == 0) {
22695                     ma_sleep(waitTimeInMilliseconds);
22696                     continue; /* Nothing is available in the capture buffer. */
22697                 }
22698
22699                 hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0);
22700                 if (FAILED(hr)) {
22701                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.");
22702                     return ma_result_from_HRESULT(hr);
22703                 }
22704
22705
22706                 /* 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. */
22707                 mappedDeviceFramesProcessedCapture = 0;
22708
22709                 for (;;) {  /* Keep writing to the playback device. */
22710                     ma_uint8  inputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
22711                     ma_uint32 inputFramesInClientFormatCap = sizeof(inputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
22712                     ma_uint8  outputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
22713                     ma_uint32 outputFramesInClientFormatCap = sizeof(outputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
22714                     ma_uint32 outputFramesInClientFormatCount;
22715                     ma_uint32 outputFramesInClientFormatConsumed = 0;
22716                     ma_uint64 clientCapturedFramesToProcess = ma_min(inputFramesInClientFormatCap, outputFramesInClientFormatCap);
22717                     ma_uint64 deviceCapturedFramesToProcess = (mappedSizeInBytesCapture / bpfDeviceCapture) - mappedDeviceFramesProcessedCapture;
22718                     void* pRunningMappedDeviceBufferCapture = ma_offset_ptr(pMappedDeviceBufferCapture, mappedDeviceFramesProcessedCapture * bpfDeviceCapture);
22719
22720                     result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningMappedDeviceBufferCapture, &deviceCapturedFramesToProcess, inputFramesInClientFormat, &clientCapturedFramesToProcess);
22721                     if (result != MA_SUCCESS) {
22722                         break;
22723                     }
22724
22725                     outputFramesInClientFormatCount     = (ma_uint32)clientCapturedFramesToProcess;
22726                     mappedDeviceFramesProcessedCapture += (ma_uint32)deviceCapturedFramesToProcess;
22727
22728                     ma_device__on_data(pDevice, outputFramesInClientFormat, inputFramesInClientFormat, (ma_uint32)clientCapturedFramesToProcess);
22729
22730                     /* 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. */
22731                     for (;;) {
22732                         ma_uint32 framesWrittenThisIteration;
22733                         DWORD physicalPlayCursorInBytes;
22734                         DWORD physicalWriteCursorInBytes;
22735                         DWORD availableBytesPlayback;
22736                         DWORD silentPaddingInBytes = 0; /* <-- Must be initialized to 0. */
22737
22738                         /* We need the physical play and write cursors. */
22739                         if (FAILED(ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes))) {
22740                             break;
22741                         }
22742
22743                         if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
22744                             physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
22745                         }
22746                         prevPlayCursorInBytesPlayback  = physicalPlayCursorInBytes;
22747
22748                         /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */
22749                         if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
22750                             /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
22751                             if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
22752                                 availableBytesPlayback  = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
22753                                 availableBytesPlayback += physicalPlayCursorInBytes;    /* Wrap around. */
22754                             } else {
22755                                 /* This is an error. */
22756                                 ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Duplex/Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
22757                                 availableBytesPlayback = 0;
22758                             }
22759                         } else {
22760                             /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
22761                             if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
22762                                 availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
22763                             } else {
22764                                 /* This is an error. */
22765                                 ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Duplex/Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
22766                                 availableBytesPlayback = 0;
22767                             }
22768                         }
22769
22770                         /* If there's no room available for writing we need to wait for more. */
22771                         if (availableBytesPlayback == 0) {
22772                             /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */
22773                             if (!isPlaybackDeviceStarted) {
22774                                 hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
22775                                 if (FAILED(hr)) {
22776                                     ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
22777                                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.");
22778                                     return ma_result_from_HRESULT(hr);
22779                                 }
22780                                 isPlaybackDeviceStarted = MA_TRUE;
22781                             } else {
22782                                 ma_sleep(waitTimeInMilliseconds);
22783                                 continue;
22784                             }
22785                         }
22786
22787
22788                         /* 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. */
22789                         lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback;
22790                         if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
22791                             /* Same loop iteration. Go up to the end of the buffer. */
22792                             lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
22793                         } else {
22794                             /* Different loop iterations. Go up to the physical play cursor. */
22795                             lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
22796                         }
22797
22798                         hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0);
22799                         if (FAILED(hr)) {
22800                             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.");
22801                             result = ma_result_from_HRESULT(hr);
22802                             break;
22803                         }
22804
22805                         /*
22806                         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
22807                         endless glitching due to it constantly running out of data.
22808                         */
22809                         if (isPlaybackDeviceStarted) {
22810                             DWORD bytesQueuedForPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - availableBytesPlayback;
22811                             if (bytesQueuedForPlayback < (pDevice->playback.internalPeriodSizeInFrames*bpfDevicePlayback)) {
22812                                 silentPaddingInBytes   = (pDevice->playback.internalPeriodSizeInFrames*2*bpfDevicePlayback) - bytesQueuedForPlayback;
22813                                 if (silentPaddingInBytes > lockSizeInBytesPlayback) {
22814                                     silentPaddingInBytes = lockSizeInBytesPlayback;
22815                                 }
22816
22817                                 ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%ld, silentPaddingInBytes=%ld\n", availableBytesPlayback, silentPaddingInBytes);
22818                             }
22819                         }
22820
22821                         /* At this point we have a buffer for output. */
22822                         if (silentPaddingInBytes > 0) {
22823                             MA_ZERO_MEMORY(pMappedDeviceBufferPlayback, silentPaddingInBytes);
22824                             framesWrittenThisIteration = silentPaddingInBytes/bpfDevicePlayback;
22825                         } else {
22826                             ma_uint64 convertedFrameCountIn  = (outputFramesInClientFormatCount - outputFramesInClientFormatConsumed);
22827                             ma_uint64 convertedFrameCountOut = mappedSizeInBytesPlayback/bpfDevicePlayback;
22828                             void* pConvertedFramesIn  = ma_offset_ptr(outputFramesInClientFormat, outputFramesInClientFormatConsumed * bpfDevicePlayback);
22829                             void* pConvertedFramesOut = pMappedDeviceBufferPlayback;
22830
22831                             result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pConvertedFramesIn, &convertedFrameCountIn, pConvertedFramesOut, &convertedFrameCountOut);
22832                             if (result != MA_SUCCESS) {
22833                                 break;
22834                             }
22835
22836                             outputFramesInClientFormatConsumed += (ma_uint32)convertedFrameCountOut;
22837                             framesWrittenThisIteration          = (ma_uint32)convertedFrameCountOut;
22838                         }
22839
22840
22841                         hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, framesWrittenThisIteration*bpfDevicePlayback, NULL, 0);
22842                         if (FAILED(hr)) {
22843                             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.");
22844                             result = ma_result_from_HRESULT(hr);
22845                             break;
22846                         }
22847
22848                         virtualWriteCursorInBytesPlayback += framesWrittenThisIteration*bpfDevicePlayback;
22849                         if ((virtualWriteCursorInBytesPlayback/bpfDevicePlayback) == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods) {
22850                             virtualWriteCursorInBytesPlayback  = 0;
22851                             virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback;
22852                         }
22853
22854                         /*
22855                         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
22856                         a bit of a buffer to prevent the playback buffer from getting starved.
22857                         */
22858                         framesWrittenToPlaybackDevice += framesWrittenThisIteration;
22859                         if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= (pDevice->playback.internalPeriodSizeInFrames*2)) {
22860                             hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
22861                             if (FAILED(hr)) {
22862                                 ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
22863                                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.");
22864                                 return ma_result_from_HRESULT(hr);
22865                             }
22866                             isPlaybackDeviceStarted = MA_TRUE;
22867                         }
22868
22869                         if (framesWrittenThisIteration < mappedSizeInBytesPlayback/bpfDevicePlayback) {
22870                             break;  /* We're finished with the output data.*/
22871                         }
22872                     }
22873
22874                     if (clientCapturedFramesToProcess == 0) {
22875                         break;  /* We just consumed every input sample. */
22876                     }
22877                 }
22878
22879
22880                 /* At this point we're done with the mapped portion of the capture buffer. */
22881                 hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0);
22882                 if (FAILED(hr)) {
22883                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.");
22884                     return ma_result_from_HRESULT(hr);
22885                 }
22886                 prevReadCursorInBytesCapture = (lockOffsetInBytesCapture + mappedSizeInBytesCapture);
22887             } break;
22888
22889
22890
22891             case ma_device_type_capture:
22892             {
22893                 DWORD physicalCaptureCursorInBytes;
22894                 DWORD physicalReadCursorInBytes;
22895                 hr = ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, &physicalCaptureCursorInBytes, &physicalReadCursorInBytes);
22896                 if (FAILED(hr)) {
22897                     return MA_ERROR;
22898                 }
22899
22900                 /* If the previous capture position is the same as the current position we need to wait a bit longer. */
22901                 if (prevReadCursorInBytesCapture == physicalReadCursorInBytes) {
22902                     ma_sleep(waitTimeInMilliseconds);
22903                     continue;
22904                 }
22905
22906                 /* Getting here means we have capture data available. */
22907                 if (prevReadCursorInBytesCapture < physicalReadCursorInBytes) {
22908                     /* The capture position has not looped. This is the simple case. */
22909                     lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
22910                     lockSizeInBytesCapture   = (physicalReadCursorInBytes - prevReadCursorInBytesCapture);
22911                 } else {
22912                     /*
22913                     The capture position has looped. This is the more complex case. Map to the end of the buffer. If this does not return anything,
22914                     do it again from the start.
22915                     */
22916                     if (prevReadCursorInBytesCapture < pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) {
22917                         /* Lock up to the end of the buffer. */
22918                         lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
22919                         lockSizeInBytesCapture   = (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) - prevReadCursorInBytesCapture;
22920                     } else {
22921                         /* Lock starting from the start of the buffer. */
22922                         lockOffsetInBytesCapture = 0;
22923                         lockSizeInBytesCapture   = physicalReadCursorInBytes;
22924                     }
22925                 }
22926
22927                 if (lockSizeInBytesCapture < pDevice->capture.internalPeriodSizeInFrames) {
22928                     ma_sleep(waitTimeInMilliseconds);
22929                     continue; /* Nothing is available in the capture buffer. */
22930                 }
22931
22932                 hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0);
22933                 if (FAILED(hr)) {
22934                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.");
22935                     result = ma_result_from_HRESULT(hr);
22936                 }
22937
22938             #ifdef MA_DEBUG_OUTPUT
22939                 if (lockSizeInBytesCapture != mappedSizeInBytesCapture) {
22940                     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Capture) lockSizeInBytesCapture=%ld != mappedSizeInBytesCapture=%ld\n", lockSizeInBytesCapture, mappedSizeInBytesCapture);
22941                 }
22942             #endif
22943
22944                 ma_device__send_frames_to_client(pDevice, mappedSizeInBytesCapture/bpfDeviceCapture, pMappedDeviceBufferCapture);
22945
22946                 hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0);
22947                 if (FAILED(hr)) {
22948                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.");
22949                     return ma_result_from_HRESULT(hr);
22950                 }
22951                 prevReadCursorInBytesCapture = lockOffsetInBytesCapture + mappedSizeInBytesCapture;
22952
22953                 if (prevReadCursorInBytesCapture == (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture)) {
22954                     prevReadCursorInBytesCapture = 0;
22955                 }
22956             } break;
22957
22958
22959
22960             case ma_device_type_playback:
22961             {
22962                 DWORD availableBytesPlayback;
22963                 DWORD physicalPlayCursorInBytes;
22964                 DWORD physicalWriteCursorInBytes;
22965                 hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes);
22966                 if (FAILED(hr)) {
22967                     break;
22968                 }
22969
22970                 if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
22971                     physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
22972                 }
22973                 prevPlayCursorInBytesPlayback  = physicalPlayCursorInBytes;
22974
22975                 /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */
22976                 if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
22977                     /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
22978                     if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
22979                         availableBytesPlayback  = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
22980                         availableBytesPlayback += physicalPlayCursorInBytes;    /* Wrap around. */
22981                     } else {
22982                         /* This is an error. */
22983                         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
22984                         availableBytesPlayback = 0;
22985                     }
22986                 } else {
22987                     /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
22988                     if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
22989                         availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
22990                     } else {
22991                         /* This is an error. */
22992                         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[DirectSound] (Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
22993                         availableBytesPlayback = 0;
22994                     }
22995                 }
22996
22997                 /* If there's no room available for writing we need to wait for more. */
22998                 if (availableBytesPlayback < pDevice->playback.internalPeriodSizeInFrames) {
22999                     /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */
23000                     if (availableBytesPlayback == 0 && !isPlaybackDeviceStarted) {
23001                         hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
23002                         if (FAILED(hr)) {
23003                             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.");
23004                             return ma_result_from_HRESULT(hr);
23005                         }
23006                         isPlaybackDeviceStarted = MA_TRUE;
23007                     } else {
23008                         ma_sleep(waitTimeInMilliseconds);
23009                         continue;
23010                     }
23011                 }
23012
23013                 /* 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. */
23014                 lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback;
23015                 if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
23016                     /* Same loop iteration. Go up to the end of the buffer. */
23017                     lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
23018                 } else {
23019                     /* Different loop iterations. Go up to the physical play cursor. */
23020                     lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
23021                 }
23022
23023                 hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0);
23024                 if (FAILED(hr)) {
23025                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.");
23026                     result = ma_result_from_HRESULT(hr);
23027                     break;
23028                 }
23029
23030                 /* At this point we have a buffer for output. */
23031                 ma_device__read_frames_from_client(pDevice, (mappedSizeInBytesPlayback/bpfDevicePlayback), pMappedDeviceBufferPlayback);
23032
23033                 hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, mappedSizeInBytesPlayback, NULL, 0);
23034                 if (FAILED(hr)) {
23035                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.");
23036                     result = ma_result_from_HRESULT(hr);
23037                     break;
23038                 }
23039
23040                 virtualWriteCursorInBytesPlayback += mappedSizeInBytesPlayback;
23041                 if (virtualWriteCursorInBytesPlayback == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) {
23042                     virtualWriteCursorInBytesPlayback  = 0;
23043                     virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback;
23044                 }
23045
23046                 /*
23047                 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
23048                 a bit of a buffer to prevent the playback buffer from getting starved.
23049                 */
23050                 framesWrittenToPlaybackDevice += mappedSizeInBytesPlayback/bpfDevicePlayback;
23051                 if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= pDevice->playback.internalPeriodSizeInFrames) {
23052                     hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
23053                     if (FAILED(hr)) {
23054                         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.");
23055                         return ma_result_from_HRESULT(hr);
23056                     }
23057                     isPlaybackDeviceStarted = MA_TRUE;
23058                 }
23059             } break;
23060
23061
23062             default: return MA_INVALID_ARGS;   /* Invalid device type. */
23063         }
23064
23065         if (result != MA_SUCCESS) {
23066             return result;
23067         }
23068     }
23069
23070     /* Getting here means the device is being stopped. */
23071     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
23072         hr = ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
23073         if (FAILED(hr)) {
23074             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed.");
23075             return ma_result_from_HRESULT(hr);
23076         }
23077     }
23078
23079     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
23080         /* 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. */
23081         if (isPlaybackDeviceStarted) {
23082             for (;;) {
23083                 DWORD availableBytesPlayback = 0;
23084                 DWORD physicalPlayCursorInBytes;
23085                 DWORD physicalWriteCursorInBytes;
23086                 hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes);
23087                 if (FAILED(hr)) {
23088                     break;
23089                 }
23090
23091                 if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
23092                     physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
23093                 }
23094                 prevPlayCursorInBytesPlayback  = physicalPlayCursorInBytes;
23095
23096                 if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
23097                     /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
23098                     if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
23099                         availableBytesPlayback  = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
23100                         availableBytesPlayback += physicalPlayCursorInBytes;    /* Wrap around. */
23101                     } else {
23102                         break;
23103                     }
23104                 } else {
23105                     /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
23106                     if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
23107                         availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
23108                     } else {
23109                         break;
23110                     }
23111                 }
23112
23113                 if (availableBytesPlayback >= (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback)) {
23114                     break;
23115                 }
23116
23117                 ma_sleep(waitTimeInMilliseconds);
23118             }
23119         }
23120
23121         hr = ma_IDirectSoundBuffer_Stop((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer);
23122         if (FAILED(hr)) {
23123             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Stop() failed.");
23124             return ma_result_from_HRESULT(hr);
23125         }
23126
23127         ma_IDirectSoundBuffer_SetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0);
23128     }
23129
23130     return MA_SUCCESS;
23131 }
23132
23133 static ma_result ma_context_uninit__dsound(ma_context* pContext)
23134 {
23135     MA_ASSERT(pContext != NULL);
23136     MA_ASSERT(pContext->backend == ma_backend_dsound);
23137
23138     ma_dlclose(pContext, pContext->dsound.hDSoundDLL);
23139
23140     return MA_SUCCESS;
23141 }
23142
23143 static ma_result ma_context_init__dsound(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
23144 {
23145     MA_ASSERT(pContext != NULL);
23146
23147     (void)pConfig;
23148
23149     pContext->dsound.hDSoundDLL = ma_dlopen(pContext, "dsound.dll");
23150     if (pContext->dsound.hDSoundDLL == NULL) {
23151         return MA_API_NOT_FOUND;
23152     }
23153
23154     pContext->dsound.DirectSoundCreate            = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCreate");
23155     pContext->dsound.DirectSoundEnumerateA        = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundEnumerateA");
23156     pContext->dsound.DirectSoundCaptureCreate     = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureCreate");
23157     pContext->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA");
23158
23159     pCallbacks->onContextInit             = ma_context_init__dsound;
23160     pCallbacks->onContextUninit           = ma_context_uninit__dsound;
23161     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__dsound;
23162     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__dsound;
23163     pCallbacks->onDeviceInit              = ma_device_init__dsound;
23164     pCallbacks->onDeviceUninit            = ma_device_uninit__dsound;
23165     pCallbacks->onDeviceStart             = NULL;   /* Not used. Started in onDeviceDataLoop. */
23166     pCallbacks->onDeviceStop              = NULL;   /* Not used. Stopped in onDeviceDataLoop. */
23167     pCallbacks->onDeviceRead              = NULL;   /* Not used. Data is read directly in onDeviceDataLoop. */
23168     pCallbacks->onDeviceWrite             = NULL;   /* Not used. Data is written directly in onDeviceDataLoop. */
23169     pCallbacks->onDeviceDataLoop          = ma_device_data_loop__dsound;
23170
23171     return MA_SUCCESS;
23172 }
23173 #endif
23174
23175
23176
23177 /******************************************************************************
23178
23179 WinMM Backend
23180
23181 ******************************************************************************/
23182 #ifdef MA_HAS_WINMM
23183
23184 /*
23185 Some older compilers don't have WAVEOUTCAPS2A and WAVEINCAPS2A, so we'll need to write this ourselves. These structures
23186 are exactly the same as the older ones but they have a few GUIDs for manufacturer/product/name identification. I'm keeping
23187 the names the same as the Win32 library for consistency, but namespaced to avoid naming conflicts with the Win32 version.
23188 */
23189 typedef struct
23190 {
23191     WORD wMid;
23192     WORD wPid;
23193     MMVERSION vDriverVersion;
23194     CHAR szPname[MAXPNAMELEN];
23195     DWORD dwFormats;
23196     WORD wChannels;
23197     WORD wReserved1;
23198     DWORD dwSupport;
23199     GUID ManufacturerGuid;
23200     GUID ProductGuid;
23201     GUID NameGuid;
23202 } MA_WAVEOUTCAPS2A;
23203 typedef struct
23204 {
23205     WORD wMid;
23206     WORD wPid;
23207     MMVERSION vDriverVersion;
23208     CHAR szPname[MAXPNAMELEN];
23209     DWORD dwFormats;
23210     WORD wChannels;
23211     WORD wReserved1;
23212     GUID ManufacturerGuid;
23213     GUID ProductGuid;
23214     GUID NameGuid;
23215 } MA_WAVEINCAPS2A;
23216
23217 typedef UINT     (WINAPI * MA_PFN_waveOutGetNumDevs)(void);
23218 typedef MMRESULT (WINAPI * MA_PFN_waveOutGetDevCapsA)(ma_uintptr uDeviceID, LPWAVEOUTCAPSA pwoc, UINT cbwoc);
23219 typedef MMRESULT (WINAPI * MA_PFN_waveOutOpen)(LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
23220 typedef MMRESULT (WINAPI * MA_PFN_waveOutClose)(HWAVEOUT hwo);
23221 typedef MMRESULT (WINAPI * MA_PFN_waveOutPrepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
23222 typedef MMRESULT (WINAPI * MA_PFN_waveOutUnprepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
23223 typedef MMRESULT (WINAPI * MA_PFN_waveOutWrite)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
23224 typedef MMRESULT (WINAPI * MA_PFN_waveOutReset)(HWAVEOUT hwo);
23225 typedef UINT     (WINAPI * MA_PFN_waveInGetNumDevs)(void);
23226 typedef MMRESULT (WINAPI * MA_PFN_waveInGetDevCapsA)(ma_uintptr uDeviceID, LPWAVEINCAPSA pwic, UINT cbwic);
23227 typedef MMRESULT (WINAPI * MA_PFN_waveInOpen)(LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
23228 typedef MMRESULT (WINAPI * MA_PFN_waveInClose)(HWAVEIN hwi);
23229 typedef MMRESULT (WINAPI * MA_PFN_waveInPrepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
23230 typedef MMRESULT (WINAPI * MA_PFN_waveInUnprepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
23231 typedef MMRESULT (WINAPI * MA_PFN_waveInAddBuffer)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
23232 typedef MMRESULT (WINAPI * MA_PFN_waveInStart)(HWAVEIN hwi);
23233 typedef MMRESULT (WINAPI * MA_PFN_waveInReset)(HWAVEIN hwi);
23234
23235 static ma_result ma_result_from_MMRESULT(MMRESULT resultMM)
23236 {
23237     switch (resultMM) {
23238         case MMSYSERR_NOERROR:      return MA_SUCCESS;
23239         case MMSYSERR_BADDEVICEID:  return MA_INVALID_ARGS;
23240         case MMSYSERR_INVALHANDLE:  return MA_INVALID_ARGS;
23241         case MMSYSERR_NOMEM:        return MA_OUT_OF_MEMORY;
23242         case MMSYSERR_INVALFLAG:    return MA_INVALID_ARGS;
23243         case MMSYSERR_INVALPARAM:   return MA_INVALID_ARGS;
23244         case MMSYSERR_HANDLEBUSY:   return MA_BUSY;
23245         case MMSYSERR_ERROR:        return MA_ERROR;
23246         default:                    return MA_ERROR;
23247     }
23248 }
23249
23250 static char* ma_find_last_character(char* str, char ch)
23251 {
23252     char* last;
23253
23254     if (str == NULL) {
23255         return NULL;
23256     }
23257
23258     last = NULL;
23259     while (*str != '\0') {
23260         if (*str == ch) {
23261             last = str;
23262         }
23263
23264         str += 1;
23265     }
23266
23267     return last;
23268 }
23269
23270 static ma_uint32 ma_get_period_size_in_bytes(ma_uint32 periodSizeInFrames, ma_format format, ma_uint32 channels)
23271 {
23272     return periodSizeInFrames * ma_get_bytes_per_frame(format, channels);
23273 }
23274
23275
23276 /*
23277 Our own "WAVECAPS" structure that contains generic information shared between WAVEOUTCAPS2 and WAVEINCAPS2 so
23278 we can do things generically and typesafely. Names are being kept the same for consistency.
23279 */
23280 typedef struct
23281 {
23282     CHAR szPname[MAXPNAMELEN];
23283     DWORD dwFormats;
23284     WORD wChannels;
23285     GUID NameGuid;
23286 } MA_WAVECAPSA;
23287
23288 static ma_result ma_get_best_info_from_formats_flags__winmm(DWORD dwFormats, WORD channels, WORD* pBitsPerSample, DWORD* pSampleRate)
23289 {
23290     WORD bitsPerSample = 0;
23291     DWORD sampleRate = 0;
23292
23293     if (pBitsPerSample) {
23294         *pBitsPerSample = 0;
23295     }
23296     if (pSampleRate) {
23297         *pSampleRate = 0;
23298     }
23299
23300     if (channels == 1) {
23301         bitsPerSample = 16;
23302         if ((dwFormats & WAVE_FORMAT_48M16) != 0) {
23303             sampleRate = 48000;
23304         } else if ((dwFormats & WAVE_FORMAT_44M16) != 0) {
23305             sampleRate = 44100;
23306         } else if ((dwFormats & WAVE_FORMAT_2M16) != 0) {
23307             sampleRate = 22050;
23308         } else if ((dwFormats & WAVE_FORMAT_1M16) != 0) {
23309             sampleRate = 11025;
23310         } else if ((dwFormats & WAVE_FORMAT_96M16) != 0) {
23311             sampleRate = 96000;
23312         } else {
23313             bitsPerSample = 8;
23314             if ((dwFormats & WAVE_FORMAT_48M08) != 0) {
23315                 sampleRate = 48000;
23316             } else if ((dwFormats & WAVE_FORMAT_44M08) != 0) {
23317                 sampleRate = 44100;
23318             } else if ((dwFormats & WAVE_FORMAT_2M08) != 0) {
23319                 sampleRate = 22050;
23320             } else if ((dwFormats & WAVE_FORMAT_1M08) != 0) {
23321                 sampleRate = 11025;
23322             } else if ((dwFormats & WAVE_FORMAT_96M08) != 0) {
23323                 sampleRate = 96000;
23324             } else {
23325                 return MA_FORMAT_NOT_SUPPORTED;
23326             }
23327         }
23328     } else {
23329         bitsPerSample = 16;
23330         if ((dwFormats & WAVE_FORMAT_48S16) != 0) {
23331             sampleRate = 48000;
23332         } else if ((dwFormats & WAVE_FORMAT_44S16) != 0) {
23333             sampleRate = 44100;
23334         } else if ((dwFormats & WAVE_FORMAT_2S16) != 0) {
23335             sampleRate = 22050;
23336         } else if ((dwFormats & WAVE_FORMAT_1S16) != 0) {
23337             sampleRate = 11025;
23338         } else if ((dwFormats & WAVE_FORMAT_96S16) != 0) {
23339             sampleRate = 96000;
23340         } else {
23341             bitsPerSample = 8;
23342             if ((dwFormats & WAVE_FORMAT_48S08) != 0) {
23343                 sampleRate = 48000;
23344             } else if ((dwFormats & WAVE_FORMAT_44S08) != 0) {
23345                 sampleRate = 44100;
23346             } else if ((dwFormats & WAVE_FORMAT_2S08) != 0) {
23347                 sampleRate = 22050;
23348             } else if ((dwFormats & WAVE_FORMAT_1S08) != 0) {
23349                 sampleRate = 11025;
23350             } else if ((dwFormats & WAVE_FORMAT_96S08) != 0) {
23351                 sampleRate = 96000;
23352             } else {
23353                 return MA_FORMAT_NOT_SUPPORTED;
23354             }
23355         }
23356     }
23357
23358     if (pBitsPerSample) {
23359         *pBitsPerSample = bitsPerSample;
23360     }
23361     if (pSampleRate) {
23362         *pSampleRate = sampleRate;
23363     }
23364
23365     return MA_SUCCESS;
23366 }
23367
23368 static ma_result ma_formats_flags_to_WAVEFORMATEX__winmm(DWORD dwFormats, WORD channels, WAVEFORMATEX* pWF)
23369 {
23370     ma_result result;
23371
23372     MA_ASSERT(pWF != NULL);
23373
23374     MA_ZERO_OBJECT(pWF);
23375     pWF->cbSize     = sizeof(*pWF);
23376     pWF->wFormatTag = WAVE_FORMAT_PCM;
23377     pWF->nChannels  = (WORD)channels;
23378     if (pWF->nChannels > 2) {
23379         pWF->nChannels = 2;
23380     }
23381
23382     result = ma_get_best_info_from_formats_flags__winmm(dwFormats, channels, &pWF->wBitsPerSample, &pWF->nSamplesPerSec);
23383     if (result != MA_SUCCESS) {
23384         return result;
23385     }
23386
23387     pWF->nBlockAlign     = (WORD)(pWF->nChannels * pWF->wBitsPerSample / 8);
23388     pWF->nAvgBytesPerSec = pWF->nBlockAlign * pWF->nSamplesPerSec;
23389
23390     return MA_SUCCESS;
23391 }
23392
23393 static ma_result ma_context_get_device_info_from_WAVECAPS(ma_context* pContext, MA_WAVECAPSA* pCaps, ma_device_info* pDeviceInfo)
23394 {
23395     WORD bitsPerSample;
23396     DWORD sampleRate;
23397     ma_result result;
23398
23399     MA_ASSERT(pContext != NULL);
23400     MA_ASSERT(pCaps != NULL);
23401     MA_ASSERT(pDeviceInfo != NULL);
23402
23403     /*
23404     Name / Description
23405
23406     Unfortunately the name specified in WAVE(OUT/IN)CAPS2 is limited to 31 characters. This results in an unprofessional looking
23407     situation where the names of the devices are truncated. To help work around this, we need to look at the name GUID and try
23408     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.
23409     */
23410
23411     /* Set the default to begin with. */
23412     ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), pCaps->szPname, (size_t)-1);
23413
23414     /*
23415     Now try the registry. There's a few things to consider here:
23416     - The name GUID can be null, in which we case we just need to stick to the original 31 characters.
23417     - If the name GUID is not present in the registry we'll also need to stick to the original 31 characters.
23418     - I like consistency, so I want the returned device names to be consistent with those returned by WASAPI and DirectSound. The
23419       problem, however is that WASAPI and DirectSound use "<component> (<name>)" format (such as "Speakers (High Definition Audio)"),
23420       but WinMM does not specificy the component name. From my admittedly limited testing, I've notice the component name seems to
23421       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
23422       name, and then concatenate the name from the registry.
23423     */
23424     if (!ma_is_guid_null(&pCaps->NameGuid)) {
23425         wchar_t guidStrW[256];
23426         if (((MA_PFN_StringFromGUID2)pContext->win32.StringFromGUID2)(&pCaps->NameGuid, guidStrW, ma_countof(guidStrW)) > 0) {
23427             char guidStr[256];
23428             char keyStr[1024];
23429             HKEY hKey;
23430
23431             WideCharToMultiByte(CP_UTF8, 0, guidStrW, -1, guidStr, sizeof(guidStr), 0, FALSE);
23432
23433             ma_strcpy_s(keyStr, sizeof(keyStr), "SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\");
23434             ma_strcat_s(keyStr, sizeof(keyStr), guidStr);
23435
23436             if (((MA_PFN_RegOpenKeyExA)pContext->win32.RegOpenKeyExA)(HKEY_LOCAL_MACHINE, keyStr, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
23437                 BYTE nameFromReg[512];
23438                 DWORD nameFromRegSize = sizeof(nameFromReg);
23439                 LONG resultWin32 = ((MA_PFN_RegQueryValueExA)pContext->win32.RegQueryValueExA)(hKey, "Name", 0, NULL, (LPBYTE)nameFromReg, (LPDWORD)&nameFromRegSize);
23440                 ((MA_PFN_RegCloseKey)pContext->win32.RegCloseKey)(hKey);
23441
23442                 if (resultWin32 == ERROR_SUCCESS) {
23443                     /* We have the value from the registry, so now we need to construct the name string. */
23444                     char name[1024];
23445                     if (ma_strcpy_s(name, sizeof(name), pDeviceInfo->name) == 0) {
23446                         char* nameBeg = ma_find_last_character(name, '(');
23447                         if (nameBeg != NULL) {
23448                             size_t leadingLen = (nameBeg - name);
23449                             ma_strncpy_s(nameBeg + 1, sizeof(name) - leadingLen, (const char*)nameFromReg, (size_t)-1);
23450
23451                             /* The closing ")", if it can fit. */
23452                             if (leadingLen + nameFromRegSize < sizeof(name)-1) {
23453                                 ma_strcat_s(name, sizeof(name), ")");
23454                             }
23455
23456                             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), name, (size_t)-1);
23457                         }
23458                     }
23459                 }
23460             }
23461         }
23462     }
23463
23464
23465     result = ma_get_best_info_from_formats_flags__winmm(pCaps->dwFormats, pCaps->wChannels, &bitsPerSample, &sampleRate);
23466     if (result != MA_SUCCESS) {
23467         return result;
23468     }
23469
23470     if (bitsPerSample == 8) {
23471         pDeviceInfo->nativeDataFormats[0].format = ma_format_u8;
23472     } else if (bitsPerSample == 16) {
23473         pDeviceInfo->nativeDataFormats[0].format = ma_format_s16;
23474     } else if (bitsPerSample == 24) {
23475         pDeviceInfo->nativeDataFormats[0].format = ma_format_s24;
23476     } else if (bitsPerSample == 32) {
23477         pDeviceInfo->nativeDataFormats[0].format = ma_format_s32;
23478     } else {
23479         return MA_FORMAT_NOT_SUPPORTED;
23480     }
23481     pDeviceInfo->nativeDataFormats[0].channels   = pCaps->wChannels;
23482     pDeviceInfo->nativeDataFormats[0].sampleRate = sampleRate;
23483     pDeviceInfo->nativeDataFormats[0].flags      = 0;
23484     pDeviceInfo->nativeDataFormatCount = 1;
23485
23486     return MA_SUCCESS;
23487 }
23488
23489 static ma_result ma_context_get_device_info_from_WAVEOUTCAPS2(ma_context* pContext, MA_WAVEOUTCAPS2A* pCaps, ma_device_info* pDeviceInfo)
23490 {
23491     MA_WAVECAPSA caps;
23492
23493     MA_ASSERT(pContext != NULL);
23494     MA_ASSERT(pCaps != NULL);
23495     MA_ASSERT(pDeviceInfo != NULL);
23496
23497     MA_COPY_MEMORY(caps.szPname, pCaps->szPname, sizeof(caps.szPname));
23498     caps.dwFormats = pCaps->dwFormats;
23499     caps.wChannels = pCaps->wChannels;
23500     caps.NameGuid  = pCaps->NameGuid;
23501     return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo);
23502 }
23503
23504 static ma_result ma_context_get_device_info_from_WAVEINCAPS2(ma_context* pContext, MA_WAVEINCAPS2A* pCaps, ma_device_info* pDeviceInfo)
23505 {
23506     MA_WAVECAPSA caps;
23507
23508     MA_ASSERT(pContext != NULL);
23509     MA_ASSERT(pCaps != NULL);
23510     MA_ASSERT(pDeviceInfo != NULL);
23511
23512     MA_COPY_MEMORY(caps.szPname, pCaps->szPname, sizeof(caps.szPname));
23513     caps.dwFormats = pCaps->dwFormats;
23514     caps.wChannels = pCaps->wChannels;
23515     caps.NameGuid  = pCaps->NameGuid;
23516     return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo);
23517 }
23518
23519
23520 static ma_result ma_context_enumerate_devices__winmm(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
23521 {
23522     UINT playbackDeviceCount;
23523     UINT captureDeviceCount;
23524     UINT iPlaybackDevice;
23525     UINT iCaptureDevice;
23526
23527     MA_ASSERT(pContext != NULL);
23528     MA_ASSERT(callback != NULL);
23529
23530     /* Playback. */
23531     playbackDeviceCount = ((MA_PFN_waveOutGetNumDevs)pContext->winmm.waveOutGetNumDevs)();
23532     for (iPlaybackDevice = 0; iPlaybackDevice < playbackDeviceCount; ++iPlaybackDevice) {
23533         MMRESULT result;
23534         MA_WAVEOUTCAPS2A caps;
23535
23536         MA_ZERO_OBJECT(&caps);
23537
23538         result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(iPlaybackDevice, (WAVEOUTCAPSA*)&caps, sizeof(caps));
23539         if (result == MMSYSERR_NOERROR) {
23540             ma_device_info deviceInfo;
23541
23542             MA_ZERO_OBJECT(&deviceInfo);
23543             deviceInfo.id.winmm = iPlaybackDevice;
23544
23545             /* The first enumerated device is the default device. */
23546             if (iPlaybackDevice == 0) {
23547                 deviceInfo.isDefault = MA_TRUE;
23548             }
23549
23550             if (ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, &deviceInfo) == MA_SUCCESS) {
23551                 ma_bool32 cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
23552                 if (cbResult == MA_FALSE) {
23553                     return MA_SUCCESS; /* Enumeration was stopped. */
23554                 }
23555             }
23556         }
23557     }
23558
23559     /* Capture. */
23560     captureDeviceCount = ((MA_PFN_waveInGetNumDevs)pContext->winmm.waveInGetNumDevs)();
23561     for (iCaptureDevice = 0; iCaptureDevice < captureDeviceCount; ++iCaptureDevice) {
23562         MMRESULT result;
23563         MA_WAVEINCAPS2A caps;
23564
23565         MA_ZERO_OBJECT(&caps);
23566
23567         result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(iCaptureDevice, (WAVEINCAPSA*)&caps, sizeof(caps));
23568         if (result == MMSYSERR_NOERROR) {
23569             ma_device_info deviceInfo;
23570
23571             MA_ZERO_OBJECT(&deviceInfo);
23572             deviceInfo.id.winmm = iCaptureDevice;
23573
23574             /* The first enumerated device is the default device. */
23575             if (iCaptureDevice == 0) {
23576                 deviceInfo.isDefault = MA_TRUE;
23577             }
23578
23579             if (ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, &deviceInfo) == MA_SUCCESS) {
23580                 ma_bool32 cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
23581                 if (cbResult == MA_FALSE) {
23582                     return MA_SUCCESS; /* Enumeration was stopped. */
23583                 }
23584             }
23585         }
23586     }
23587
23588     return MA_SUCCESS;
23589 }
23590
23591 static ma_result ma_context_get_device_info__winmm(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
23592 {
23593     UINT winMMDeviceID;
23594
23595     MA_ASSERT(pContext != NULL);
23596
23597     winMMDeviceID = 0;
23598     if (pDeviceID != NULL) {
23599         winMMDeviceID = (UINT)pDeviceID->winmm;
23600     }
23601
23602     pDeviceInfo->id.winmm = winMMDeviceID;
23603
23604     /* The first ID is the default device. */
23605     if (winMMDeviceID == 0) {
23606         pDeviceInfo->isDefault = MA_TRUE;
23607     }
23608
23609     if (deviceType == ma_device_type_playback) {
23610         MMRESULT result;
23611         MA_WAVEOUTCAPS2A caps;
23612
23613         MA_ZERO_OBJECT(&caps);
23614
23615         result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceID, (WAVEOUTCAPSA*)&caps, sizeof(caps));
23616         if (result == MMSYSERR_NOERROR) {
23617             return ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, pDeviceInfo);
23618         }
23619     } else {
23620         MMRESULT result;
23621         MA_WAVEINCAPS2A caps;
23622
23623         MA_ZERO_OBJECT(&caps);
23624
23625         result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceID, (WAVEINCAPSA*)&caps, sizeof(caps));
23626         if (result == MMSYSERR_NOERROR) {
23627             return ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, pDeviceInfo);
23628         }
23629     }
23630
23631     return MA_NO_DEVICE;
23632 }
23633
23634
23635 static ma_result ma_device_uninit__winmm(ma_device* pDevice)
23636 {
23637     MA_ASSERT(pDevice != NULL);
23638
23639     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
23640         ((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture);
23641         CloseHandle((HANDLE)pDevice->winmm.hEventCapture);
23642     }
23643
23644     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
23645         ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
23646         ((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
23647         CloseHandle((HANDLE)pDevice->winmm.hEventPlayback);
23648     }
23649
23650     ma_free(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks);
23651
23652     MA_ZERO_OBJECT(&pDevice->winmm);   /* Safety. */
23653
23654     return MA_SUCCESS;
23655 }
23656
23657 static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__winmm(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile)
23658 {
23659     /* WinMM has a minimum period size of 40ms. */
23660     ma_uint32 minPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(40, nativeSampleRate);
23661     ma_uint32 periodSizeInFrames;
23662
23663     periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, nativeSampleRate, performanceProfile);
23664     if (periodSizeInFrames < minPeriodSizeInFrames) {
23665         periodSizeInFrames = minPeriodSizeInFrames;
23666     }
23667
23668     return periodSizeInFrames;
23669 }
23670
23671 static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
23672 {
23673     const char* errorMsg = "";
23674     ma_result errorCode = MA_ERROR;
23675     ma_result result = MA_SUCCESS;
23676     ma_uint32 heapSize;
23677     UINT winMMDeviceIDPlayback = 0;
23678     UINT winMMDeviceIDCapture  = 0;
23679
23680     MA_ASSERT(pDevice != NULL);
23681
23682     MA_ZERO_OBJECT(&pDevice->winmm);
23683
23684     if (pConfig->deviceType == ma_device_type_loopback) {
23685         return MA_DEVICE_TYPE_NOT_SUPPORTED;
23686     }
23687
23688     /* No exlusive mode with WinMM. */
23689     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
23690         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive)) {
23691         return MA_SHARE_MODE_NOT_SUPPORTED;
23692     }
23693
23694     if (pDescriptorPlayback->pDeviceID != NULL) {
23695         winMMDeviceIDPlayback = (UINT)pDescriptorPlayback->pDeviceID->winmm;
23696     }
23697     if (pDescriptorCapture->pDeviceID != NULL) {
23698         winMMDeviceIDCapture = (UINT)pDescriptorCapture->pDeviceID->winmm;
23699     }
23700
23701     /* The capture device needs to be initialized first. */
23702     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
23703         WAVEINCAPSA caps;
23704         WAVEFORMATEX wf;
23705         MMRESULT resultMM;
23706
23707         /* We use an event to know when a new fragment needs to be enqueued. */
23708         pDevice->winmm.hEventCapture = (ma_handle)CreateEventW(NULL, TRUE, TRUE, NULL);
23709         if (pDevice->winmm.hEventCapture == NULL) {
23710             errorMsg = "[WinMM] Failed to create event for fragment enqueing for the capture device.", errorCode = ma_result_from_GetLastError(GetLastError());
23711             goto on_error;
23712         }
23713
23714         /* The format should be based on the device's actual format. */
23715         if (((MA_PFN_waveInGetDevCapsA)pDevice->pContext->winmm.waveInGetDevCapsA)(winMMDeviceIDCapture, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
23716             errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
23717             goto on_error;
23718         }
23719
23720         result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf);
23721         if (result != MA_SUCCESS) {
23722             errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result;
23723             goto on_error;
23724         }
23725
23726         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);
23727         if (resultMM != MMSYSERR_NOERROR) {
23728             errorMsg = "[WinMM] Failed to open capture device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
23729             goto on_error;
23730         }
23731
23732         pDescriptorCapture->format             = ma_format_from_WAVEFORMATEX(&wf);
23733         pDescriptorCapture->channels           = wf.nChannels;
23734         pDescriptorCapture->sampleRate         = wf.nSamplesPerSec;
23735         ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels);
23736         pDescriptorCapture->periodCount        = pDescriptorCapture->periodCount;
23737         pDescriptorCapture->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile);
23738     }
23739
23740     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
23741         WAVEOUTCAPSA caps;
23742         WAVEFORMATEX wf;
23743         MMRESULT resultMM;
23744
23745         /* We use an event to know when a new fragment needs to be enqueued. */
23746         pDevice->winmm.hEventPlayback = (ma_handle)CreateEvent(NULL, TRUE, TRUE, NULL);
23747         if (pDevice->winmm.hEventPlayback == NULL) {
23748             errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError());
23749             goto on_error;
23750         }
23751
23752         /* The format should be based on the device's actual format. */
23753         if (((MA_PFN_waveOutGetDevCapsA)pDevice->pContext->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
23754             errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
23755             goto on_error;
23756         }
23757
23758         result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf);
23759         if (result != MA_SUCCESS) {
23760             errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result;
23761             goto on_error;
23762         }
23763
23764         resultMM = ((MA_PFN_waveOutOpen)pDevice->pContext->winmm.waveOutOpen)((LPHWAVEOUT)&pDevice->winmm.hDevicePlayback, winMMDeviceIDPlayback, &wf, (DWORD_PTR)pDevice->winmm.hEventPlayback, (DWORD_PTR)pDevice, CALLBACK_EVENT | WAVE_ALLOWSYNC);
23765         if (resultMM != MMSYSERR_NOERROR) {
23766             errorMsg = "[WinMM] Failed to open playback device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
23767             goto on_error;
23768         }
23769
23770         pDescriptorPlayback->format             = ma_format_from_WAVEFORMATEX(&wf);
23771         pDescriptorPlayback->channels           = wf.nChannels;
23772         pDescriptorPlayback->sampleRate         = wf.nSamplesPerSec;
23773         ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels);
23774         pDescriptorPlayback->periodCount        = pDescriptorPlayback->periodCount;
23775         pDescriptorPlayback->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
23776     }
23777
23778     /*
23779     The heap allocated data is allocated like so:
23780
23781     [Capture WAVEHDRs][Playback WAVEHDRs][Capture Intermediary Buffer][Playback Intermediary Buffer]
23782     */
23783     heapSize = 0;
23784     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
23785         heapSize += sizeof(WAVEHDR)*pDescriptorCapture->periodCount + (pDescriptorCapture->periodSizeInFrames * pDescriptorCapture->periodCount * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels));
23786     }
23787     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
23788         heapSize += sizeof(WAVEHDR)*pDescriptorPlayback->periodCount + (pDescriptorPlayback->periodSizeInFrames * pDescriptorPlayback->periodCount * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels));
23789     }
23790
23791     pDevice->winmm._pHeapData = (ma_uint8*)ma_calloc(heapSize, &pDevice->pContext->allocationCallbacks);
23792     if (pDevice->winmm._pHeapData == NULL) {
23793         errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MA_OUT_OF_MEMORY;
23794         goto on_error;
23795     }
23796
23797     MA_ZERO_MEMORY(pDevice->winmm._pHeapData, heapSize);
23798
23799     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
23800         ma_uint32 iPeriod;
23801
23802         if (pConfig->deviceType == ma_device_type_capture) {
23803             pDevice->winmm.pWAVEHDRCapture            = pDevice->winmm._pHeapData;
23804             pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount));
23805         } else {
23806             pDevice->winmm.pWAVEHDRCapture            = pDevice->winmm._pHeapData;
23807             pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount + pDescriptorPlayback->periodCount));
23808         }
23809
23810         /* Prepare headers. */
23811         for (iPeriod = 0; iPeriod < pDescriptorCapture->periodCount; ++iPeriod) {
23812             ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->format, pDescriptorCapture->channels);
23813
23814             ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].lpData         = (LPSTR)(pDevice->winmm.pIntermediaryBufferCapture + (periodSizeInBytes*iPeriod));
23815             ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwBufferLength = periodSizeInBytes;
23816             ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwFlags        = 0L;
23817             ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwLoops        = 0L;
23818             ((MA_PFN_waveInPrepareHeader)pDevice->pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
23819
23820             /*
23821             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
23822             it's unlocked and available for writing. A value of 1 means it's locked.
23823             */
23824             ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwUser = 0;
23825         }
23826     }
23827
23828     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
23829         ma_uint32 iPeriod;
23830
23831         if (pConfig->deviceType == ma_device_type_playback) {
23832             pDevice->winmm.pWAVEHDRPlayback            = pDevice->winmm._pHeapData;
23833             pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*pDescriptorPlayback->periodCount);
23834         } else {
23835             pDevice->winmm.pWAVEHDRPlayback            = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount));
23836             pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount + pDescriptorPlayback->periodCount)) + (pDescriptorCapture->periodSizeInFrames*pDescriptorCapture->periodCount*ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels));
23837         }
23838
23839         /* Prepare headers. */
23840         for (iPeriod = 0; iPeriod < pDescriptorPlayback->periodCount; ++iPeriod) {
23841             ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->format, pDescriptorPlayback->channels);
23842
23843             ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].lpData         = (LPSTR)(pDevice->winmm.pIntermediaryBufferPlayback + (periodSizeInBytes*iPeriod));
23844             ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwBufferLength = periodSizeInBytes;
23845             ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwFlags        = 0L;
23846             ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwLoops        = 0L;
23847             ((MA_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
23848
23849             /*
23850             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
23851             it's unlocked and available for writing. A value of 1 means it's locked.
23852             */
23853             ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwUser = 0;
23854         }
23855     }
23856
23857     return MA_SUCCESS;
23858
23859 on_error:
23860     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
23861         if (pDevice->winmm.pWAVEHDRCapture != NULL) {
23862             ma_uint32 iPeriod;
23863             for (iPeriod = 0; iPeriod < pDescriptorCapture->periodCount; ++iPeriod) {
23864                 ((MA_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
23865             }
23866         }
23867
23868         ((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture);
23869     }
23870
23871     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
23872         if (pDevice->winmm.pWAVEHDRCapture != NULL) {
23873             ma_uint32 iPeriod;
23874             for (iPeriod = 0; iPeriod < pDescriptorPlayback->periodCount; ++iPeriod) {
23875                 ((MA_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
23876             }
23877         }
23878
23879         ((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
23880     }
23881
23882     ma_free(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks);
23883
23884     if (errorMsg != NULL && errorMsg[0] != '\0') {
23885         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "%s", errorMsg);
23886     }
23887
23888     return errorCode;
23889 }
23890
23891 static ma_result ma_device_start__winmm(ma_device* pDevice)
23892 {
23893     MA_ASSERT(pDevice != NULL);
23894
23895     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
23896         MMRESULT resultMM;
23897         WAVEHDR* pWAVEHDR;
23898         ma_uint32 iPeriod;
23899
23900         pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRCapture;
23901
23902         /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */
23903         ResetEvent((HANDLE)pDevice->winmm.hEventCapture);
23904
23905         /* 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. */
23906         for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
23907             resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
23908             if (resultMM != MMSYSERR_NOERROR) {
23909                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] Failed to attach input buffers to capture device in preparation for capture.");
23910                 return ma_result_from_MMRESULT(resultMM);
23911             }
23912
23913             /* Make sure all of the buffers start out locked. We don't want to access them until the backend tells us we can. */
23914             pWAVEHDR[iPeriod].dwUser = 1;   /* 1 = locked. */
23915         }
23916
23917         /* Capture devices need to be explicitly started, unlike playback devices. */
23918         resultMM = ((MA_PFN_waveInStart)pDevice->pContext->winmm.waveInStart)((HWAVEIN)pDevice->winmm.hDeviceCapture);
23919         if (resultMM != MMSYSERR_NOERROR) {
23920             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device.");
23921             return ma_result_from_MMRESULT(resultMM);
23922         }
23923     }
23924
23925     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
23926         /* Don't need to do anything for playback. It'll be started automatically in ma_device_start__winmm(). */
23927     }
23928
23929     return MA_SUCCESS;
23930 }
23931
23932 static ma_result ma_device_stop__winmm(ma_device* pDevice)
23933 {
23934     MMRESULT resultMM;
23935
23936     MA_ASSERT(pDevice != NULL);
23937
23938     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
23939         if (pDevice->winmm.hDeviceCapture == NULL) {
23940             return MA_INVALID_ARGS;
23941         }
23942
23943         resultMM = ((MA_PFN_waveInReset)pDevice->pContext->winmm.waveInReset)((HWAVEIN)pDevice->winmm.hDeviceCapture);
23944         if (resultMM != MMSYSERR_NOERROR) {
23945             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[WinMM] WARNING: Failed to reset capture device.");
23946         }
23947     }
23948
23949     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
23950         ma_uint32 iPeriod;
23951         WAVEHDR* pWAVEHDR;
23952
23953         if (pDevice->winmm.hDevicePlayback == NULL) {
23954             return MA_INVALID_ARGS;
23955         }
23956
23957         /* 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. */
23958         pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback;
23959         for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; iPeriod += 1) {
23960             if (pWAVEHDR[iPeriod].dwUser == 1) { /* 1 = locked. */
23961                 if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventPlayback, INFINITE) != WAIT_OBJECT_0) {
23962                     break;  /* An error occurred so just abandon ship and stop the device without draining. */
23963                 }
23964
23965                 pWAVEHDR[iPeriod].dwUser = 0;
23966             }
23967         }
23968
23969         resultMM = ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
23970         if (resultMM != MMSYSERR_NOERROR) {
23971             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[WinMM] WARNING: Failed to reset playback device.");
23972         }
23973     }
23974
23975     return MA_SUCCESS;
23976 }
23977
23978 static ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
23979 {
23980     ma_result result = MA_SUCCESS;
23981     MMRESULT resultMM;
23982     ma_uint32 totalFramesWritten;
23983     WAVEHDR* pWAVEHDR;
23984
23985     MA_ASSERT(pDevice != NULL);
23986     MA_ASSERT(pPCMFrames != NULL);
23987
23988     if (pFramesWritten != NULL) {
23989         *pFramesWritten = 0;
23990     }
23991
23992     pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback;
23993
23994     /* Keep processing as much data as possible. */
23995     totalFramesWritten = 0;
23996     while (totalFramesWritten < frameCount) {
23997         /* If the current header has some space available we need to write part of it. */
23998         if (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser == 0) { /* 0 = unlocked. */
23999             /*
24000             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
24001             write it out and move on to the next iteration.
24002             */
24003             ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
24004             ma_uint32 framesRemainingInHeader = (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwBufferLength/bpf) - pDevice->winmm.headerFramesConsumedPlayback;
24005
24006             ma_uint32 framesToCopy = ma_min(framesRemainingInHeader, (frameCount - totalFramesWritten));
24007             const void* pSrc = ma_offset_ptr(pPCMFrames, totalFramesWritten*bpf);
24008             void* pDst = ma_offset_ptr(pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].lpData, pDevice->winmm.headerFramesConsumedPlayback*bpf);
24009             MA_COPY_MEMORY(pDst, pSrc, framesToCopy*bpf);
24010
24011             pDevice->winmm.headerFramesConsumedPlayback += framesToCopy;
24012             totalFramesWritten += framesToCopy;
24013
24014             /* If we've consumed the buffer entirely we need to write it out to the device. */
24015             if (pDevice->winmm.headerFramesConsumedPlayback == (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwBufferLength/bpf)) {
24016                 pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser = 1;            /* 1 = locked. */
24017                 pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags &= ~WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */
24018
24019                 /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */
24020                 ResetEvent((HANDLE)pDevice->winmm.hEventPlayback);
24021
24022                 /* The device will be started here. */
24023                 resultMM = ((MA_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &pWAVEHDR[pDevice->winmm.iNextHeaderPlayback], sizeof(WAVEHDR));
24024                 if (resultMM != MMSYSERR_NOERROR) {
24025                     result = ma_result_from_MMRESULT(resultMM);
24026                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] waveOutWrite() failed.");
24027                     break;
24028                 }
24029
24030                 /* Make sure we move to the next header. */
24031                 pDevice->winmm.iNextHeaderPlayback = (pDevice->winmm.iNextHeaderPlayback + 1) % pDevice->playback.internalPeriods;
24032                 pDevice->winmm.headerFramesConsumedPlayback = 0;
24033             }
24034
24035             /* If at this point we have consumed the entire input buffer we can return. */
24036             MA_ASSERT(totalFramesWritten <= frameCount);
24037             if (totalFramesWritten == frameCount) {
24038                 break;
24039             }
24040
24041             /* Getting here means there's more to process. */
24042             continue;
24043         }
24044
24045         /* Getting here means there isn't enough room in the buffer and we need to wait for one to become available. */
24046         if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventPlayback, INFINITE) != WAIT_OBJECT_0) {
24047             result = MA_ERROR;
24048             break;
24049         }
24050
24051         /* Something happened. If the next buffer has been marked as done we need to reset a bit of state. */
24052         if ((pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags & WHDR_DONE) != 0) {
24053             pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser = 0;    /* 0 = unlocked (make it available for writing). */
24054             pDevice->winmm.headerFramesConsumedPlayback = 0;
24055         }
24056
24057         /* If the device has been stopped we need to break. */
24058         if (ma_device_get_state(pDevice) != ma_device_state_started) {
24059             break;
24060         }
24061     }
24062
24063     if (pFramesWritten != NULL) {
24064         *pFramesWritten = totalFramesWritten;
24065     }
24066
24067     return result;
24068 }
24069
24070 static ma_result ma_device_read__winmm(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
24071 {
24072     ma_result result = MA_SUCCESS;
24073     MMRESULT resultMM;
24074     ma_uint32 totalFramesRead;
24075     WAVEHDR* pWAVEHDR;
24076
24077     MA_ASSERT(pDevice != NULL);
24078     MA_ASSERT(pPCMFrames != NULL);
24079
24080     if (pFramesRead != NULL) {
24081         *pFramesRead = 0;
24082     }
24083
24084     pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRCapture;
24085
24086     /* Keep processing as much data as possible. */
24087     totalFramesRead = 0;
24088     while (totalFramesRead < frameCount) {
24089         /* If the current header has some space available we need to write part of it. */
24090         if (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser == 0) { /* 0 = unlocked. */
24091             /* The buffer is available for reading. If we fully consume it we need to add it back to the buffer. */
24092             ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
24093             ma_uint32 framesRemainingInHeader = (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwBufferLength/bpf) - pDevice->winmm.headerFramesConsumedCapture;
24094
24095             ma_uint32 framesToCopy = ma_min(framesRemainingInHeader, (frameCount - totalFramesRead));
24096             const void* pSrc = ma_offset_ptr(pWAVEHDR[pDevice->winmm.iNextHeaderCapture].lpData, pDevice->winmm.headerFramesConsumedCapture*bpf);
24097             void* pDst = ma_offset_ptr(pPCMFrames, totalFramesRead*bpf);
24098             MA_COPY_MEMORY(pDst, pSrc, framesToCopy*bpf);
24099
24100             pDevice->winmm.headerFramesConsumedCapture += framesToCopy;
24101             totalFramesRead += framesToCopy;
24102
24103             /* If we've consumed the buffer entirely we need to add it back to the device. */
24104             if (pDevice->winmm.headerFramesConsumedCapture == (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwBufferLength/bpf)) {
24105                 pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser = 1;            /* 1 = locked. */
24106                 pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags &= ~WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */
24107
24108                 /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */
24109                 ResetEvent((HANDLE)pDevice->winmm.hEventCapture);
24110
24111                 /* The device will be started here. */
24112                 resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[pDevice->winmm.iNextHeaderCapture], sizeof(WAVEHDR));
24113                 if (resultMM != MMSYSERR_NOERROR) {
24114                     result = ma_result_from_MMRESULT(resultMM);
24115                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WinMM] waveInAddBuffer() failed.");
24116                     break;
24117                 }
24118
24119                 /* Make sure we move to the next header. */
24120                 pDevice->winmm.iNextHeaderCapture = (pDevice->winmm.iNextHeaderCapture + 1) % pDevice->capture.internalPeriods;
24121                 pDevice->winmm.headerFramesConsumedCapture = 0;
24122             }
24123
24124             /* If at this point we have filled the entire input buffer we can return. */
24125             MA_ASSERT(totalFramesRead <= frameCount);
24126             if (totalFramesRead == frameCount) {
24127                 break;
24128             }
24129
24130             /* Getting here means there's more to process. */
24131             continue;
24132         }
24133
24134         /* Getting here means there isn't enough any data left to send to the client which means we need to wait for more. */
24135         if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventCapture, INFINITE) != WAIT_OBJECT_0) {
24136             result = MA_ERROR;
24137             break;
24138         }
24139
24140         /* Something happened. If the next buffer has been marked as done we need to reset a bit of state. */
24141         if ((pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags & WHDR_DONE) != 0) {
24142             pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser = 0;    /* 0 = unlocked (make it available for reading). */
24143             pDevice->winmm.headerFramesConsumedCapture = 0;
24144         }
24145
24146         /* If the device has been stopped we need to break. */
24147         if (ma_device_get_state(pDevice) != ma_device_state_started) {
24148             break;
24149         }
24150     }
24151
24152     if (pFramesRead != NULL) {
24153         *pFramesRead = totalFramesRead;
24154     }
24155
24156     return result;
24157 }
24158
24159 static ma_result ma_context_uninit__winmm(ma_context* pContext)
24160 {
24161     MA_ASSERT(pContext != NULL);
24162     MA_ASSERT(pContext->backend == ma_backend_winmm);
24163
24164     ma_dlclose(pContext, pContext->winmm.hWinMM);
24165     return MA_SUCCESS;
24166 }
24167
24168 static ma_result ma_context_init__winmm(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
24169 {
24170     MA_ASSERT(pContext != NULL);
24171
24172     (void)pConfig;
24173
24174     pContext->winmm.hWinMM = ma_dlopen(pContext, "winmm.dll");
24175     if (pContext->winmm.hWinMM == NULL) {
24176         return MA_NO_BACKEND;
24177     }
24178
24179     pContext->winmm.waveOutGetNumDevs      = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetNumDevs");
24180     pContext->winmm.waveOutGetDevCapsA     = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetDevCapsA");
24181     pContext->winmm.waveOutOpen            = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutOpen");
24182     pContext->winmm.waveOutClose           = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutClose");
24183     pContext->winmm.waveOutPrepareHeader   = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutPrepareHeader");
24184     pContext->winmm.waveOutUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutUnprepareHeader");
24185     pContext->winmm.waveOutWrite           = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutWrite");
24186     pContext->winmm.waveOutReset           = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutReset");
24187     pContext->winmm.waveInGetNumDevs       = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetNumDevs");
24188     pContext->winmm.waveInGetDevCapsA      = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetDevCapsA");
24189     pContext->winmm.waveInOpen             = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInOpen");
24190     pContext->winmm.waveInClose            = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInClose");
24191     pContext->winmm.waveInPrepareHeader    = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInPrepareHeader");
24192     pContext->winmm.waveInUnprepareHeader  = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInUnprepareHeader");
24193     pContext->winmm.waveInAddBuffer        = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInAddBuffer");
24194     pContext->winmm.waveInStart            = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInStart");
24195     pContext->winmm.waveInReset            = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInReset");
24196
24197     pCallbacks->onContextInit             = ma_context_init__winmm;
24198     pCallbacks->onContextUninit           = ma_context_uninit__winmm;
24199     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__winmm;
24200     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__winmm;
24201     pCallbacks->onDeviceInit              = ma_device_init__winmm;
24202     pCallbacks->onDeviceUninit            = ma_device_uninit__winmm;
24203     pCallbacks->onDeviceStart             = ma_device_start__winmm;
24204     pCallbacks->onDeviceStop              = ma_device_stop__winmm;
24205     pCallbacks->onDeviceRead              = ma_device_read__winmm;
24206     pCallbacks->onDeviceWrite             = ma_device_write__winmm;
24207     pCallbacks->onDeviceDataLoop          = NULL;   /* This is a blocking read-write API, so this can be NULL since miniaudio will manage the audio thread for us. */
24208
24209     return MA_SUCCESS;
24210 }
24211 #endif
24212
24213
24214
24215
24216 /******************************************************************************
24217
24218 ALSA Backend
24219
24220 ******************************************************************************/
24221 #ifdef MA_HAS_ALSA
24222
24223 #include <poll.h>           /* poll(), struct pollfd */
24224 #include <sys/eventfd.h>    /* eventfd() */
24225
24226 #ifdef MA_NO_RUNTIME_LINKING
24227
24228 /* asoundlib.h marks some functions with "inline" which isn't always supported. Need to emulate it. */
24229 #if !defined(__cplusplus)
24230     #if defined(__STRICT_ANSI__)
24231         #if !defined(inline)
24232             #define inline __inline__ __attribute__((always_inline))
24233             #define MA_INLINE_DEFINED
24234         #endif
24235     #endif
24236 #endif
24237 #include <alsa/asoundlib.h>
24238 #if defined(MA_INLINE_DEFINED)
24239     #undef inline
24240     #undef MA_INLINE_DEFINED
24241 #endif
24242
24243 typedef snd_pcm_uframes_t                       ma_snd_pcm_uframes_t;
24244 typedef snd_pcm_sframes_t                       ma_snd_pcm_sframes_t;
24245 typedef snd_pcm_stream_t                        ma_snd_pcm_stream_t;
24246 typedef snd_pcm_format_t                        ma_snd_pcm_format_t;
24247 typedef snd_pcm_access_t                        ma_snd_pcm_access_t;
24248 typedef snd_pcm_t                               ma_snd_pcm_t;
24249 typedef snd_pcm_hw_params_t                     ma_snd_pcm_hw_params_t;
24250 typedef snd_pcm_sw_params_t                     ma_snd_pcm_sw_params_t;
24251 typedef snd_pcm_format_mask_t                   ma_snd_pcm_format_mask_t;
24252 typedef snd_pcm_info_t                          ma_snd_pcm_info_t;
24253 typedef snd_pcm_channel_area_t                  ma_snd_pcm_channel_area_t;
24254 typedef snd_pcm_chmap_t                         ma_snd_pcm_chmap_t;
24255 typedef snd_pcm_state_t                         ma_snd_pcm_state_t;
24256
24257 /* snd_pcm_stream_t */
24258 #define MA_SND_PCM_STREAM_PLAYBACK              SND_PCM_STREAM_PLAYBACK
24259 #define MA_SND_PCM_STREAM_CAPTURE               SND_PCM_STREAM_CAPTURE
24260
24261 /* snd_pcm_format_t */
24262 #define MA_SND_PCM_FORMAT_UNKNOWN               SND_PCM_FORMAT_UNKNOWN
24263 #define MA_SND_PCM_FORMAT_U8                    SND_PCM_FORMAT_U8
24264 #define MA_SND_PCM_FORMAT_S16_LE                SND_PCM_FORMAT_S16_LE
24265 #define MA_SND_PCM_FORMAT_S16_BE                SND_PCM_FORMAT_S16_BE
24266 #define MA_SND_PCM_FORMAT_S24_LE                SND_PCM_FORMAT_S24_LE
24267 #define MA_SND_PCM_FORMAT_S24_BE                SND_PCM_FORMAT_S24_BE
24268 #define MA_SND_PCM_FORMAT_S32_LE                SND_PCM_FORMAT_S32_LE
24269 #define MA_SND_PCM_FORMAT_S32_BE                SND_PCM_FORMAT_S32_BE
24270 #define MA_SND_PCM_FORMAT_FLOAT_LE              SND_PCM_FORMAT_FLOAT_LE
24271 #define MA_SND_PCM_FORMAT_FLOAT_BE              SND_PCM_FORMAT_FLOAT_BE
24272 #define MA_SND_PCM_FORMAT_FLOAT64_LE            SND_PCM_FORMAT_FLOAT64_LE
24273 #define MA_SND_PCM_FORMAT_FLOAT64_BE            SND_PCM_FORMAT_FLOAT64_BE
24274 #define MA_SND_PCM_FORMAT_MU_LAW                SND_PCM_FORMAT_MU_LAW
24275 #define MA_SND_PCM_FORMAT_A_LAW                 SND_PCM_FORMAT_A_LAW
24276 #define MA_SND_PCM_FORMAT_S24_3LE               SND_PCM_FORMAT_S24_3LE
24277 #define MA_SND_PCM_FORMAT_S24_3BE               SND_PCM_FORMAT_S24_3BE
24278
24279 /* ma_snd_pcm_access_t */
24280 #define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED      SND_PCM_ACCESS_MMAP_INTERLEAVED
24281 #define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED   SND_PCM_ACCESS_MMAP_NONINTERLEAVED
24282 #define MA_SND_PCM_ACCESS_MMAP_COMPLEX          SND_PCM_ACCESS_MMAP_COMPLEX
24283 #define MA_SND_PCM_ACCESS_RW_INTERLEAVED        SND_PCM_ACCESS_RW_INTERLEAVED
24284 #define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED     SND_PCM_ACCESS_RW_NONINTERLEAVED
24285
24286 /* Channel positions. */
24287 #define MA_SND_CHMAP_UNKNOWN                    SND_CHMAP_UNKNOWN
24288 #define MA_SND_CHMAP_NA                         SND_CHMAP_NA
24289 #define MA_SND_CHMAP_MONO                       SND_CHMAP_MONO
24290 #define MA_SND_CHMAP_FL                         SND_CHMAP_FL
24291 #define MA_SND_CHMAP_FR                         SND_CHMAP_FR
24292 #define MA_SND_CHMAP_RL                         SND_CHMAP_RL
24293 #define MA_SND_CHMAP_RR                         SND_CHMAP_RR
24294 #define MA_SND_CHMAP_FC                         SND_CHMAP_FC
24295 #define MA_SND_CHMAP_LFE                        SND_CHMAP_LFE
24296 #define MA_SND_CHMAP_SL                         SND_CHMAP_SL
24297 #define MA_SND_CHMAP_SR                         SND_CHMAP_SR
24298 #define MA_SND_CHMAP_RC                         SND_CHMAP_RC
24299 #define MA_SND_CHMAP_FLC                        SND_CHMAP_FLC
24300 #define MA_SND_CHMAP_FRC                        SND_CHMAP_FRC
24301 #define MA_SND_CHMAP_RLC                        SND_CHMAP_RLC
24302 #define MA_SND_CHMAP_RRC                        SND_CHMAP_RRC
24303 #define MA_SND_CHMAP_FLW                        SND_CHMAP_FLW
24304 #define MA_SND_CHMAP_FRW                        SND_CHMAP_FRW
24305 #define MA_SND_CHMAP_FLH                        SND_CHMAP_FLH
24306 #define MA_SND_CHMAP_FCH                        SND_CHMAP_FCH
24307 #define MA_SND_CHMAP_FRH                        SND_CHMAP_FRH
24308 #define MA_SND_CHMAP_TC                         SND_CHMAP_TC
24309 #define MA_SND_CHMAP_TFL                        SND_CHMAP_TFL
24310 #define MA_SND_CHMAP_TFR                        SND_CHMAP_TFR
24311 #define MA_SND_CHMAP_TFC                        SND_CHMAP_TFC
24312 #define MA_SND_CHMAP_TRL                        SND_CHMAP_TRL
24313 #define MA_SND_CHMAP_TRR                        SND_CHMAP_TRR
24314 #define MA_SND_CHMAP_TRC                        SND_CHMAP_TRC
24315 #define MA_SND_CHMAP_TFLC                       SND_CHMAP_TFLC
24316 #define MA_SND_CHMAP_TFRC                       SND_CHMAP_TFRC
24317 #define MA_SND_CHMAP_TSL                        SND_CHMAP_TSL
24318 #define MA_SND_CHMAP_TSR                        SND_CHMAP_TSR
24319 #define MA_SND_CHMAP_LLFE                       SND_CHMAP_LLFE
24320 #define MA_SND_CHMAP_RLFE                       SND_CHMAP_RLFE
24321 #define MA_SND_CHMAP_BC                         SND_CHMAP_BC
24322 #define MA_SND_CHMAP_BLC                        SND_CHMAP_BLC
24323 #define MA_SND_CHMAP_BRC                        SND_CHMAP_BRC
24324
24325 /* Open mode flags. */
24326 #define MA_SND_PCM_NO_AUTO_RESAMPLE             SND_PCM_NO_AUTO_RESAMPLE
24327 #define MA_SND_PCM_NO_AUTO_CHANNELS             SND_PCM_NO_AUTO_CHANNELS
24328 #define MA_SND_PCM_NO_AUTO_FORMAT               SND_PCM_NO_AUTO_FORMAT
24329 #else
24330 #include <errno.h>  /* For EPIPE, etc. */
24331 typedef unsigned long                           ma_snd_pcm_uframes_t;
24332 typedef long                                    ma_snd_pcm_sframes_t;
24333 typedef int                                     ma_snd_pcm_stream_t;
24334 typedef int                                     ma_snd_pcm_format_t;
24335 typedef int                                     ma_snd_pcm_access_t;
24336 typedef int                                     ma_snd_pcm_state_t;
24337 typedef struct ma_snd_pcm_t                     ma_snd_pcm_t;
24338 typedef struct ma_snd_pcm_hw_params_t           ma_snd_pcm_hw_params_t;
24339 typedef struct ma_snd_pcm_sw_params_t           ma_snd_pcm_sw_params_t;
24340 typedef struct ma_snd_pcm_format_mask_t         ma_snd_pcm_format_mask_t;
24341 typedef struct ma_snd_pcm_info_t                ma_snd_pcm_info_t;
24342 typedef struct
24343 {
24344     void* addr;
24345     unsigned int first;
24346     unsigned int step;
24347 } ma_snd_pcm_channel_area_t;
24348 typedef struct
24349 {
24350     unsigned int channels;
24351     unsigned int pos[1];
24352 } ma_snd_pcm_chmap_t;
24353
24354 /* snd_pcm_state_t */
24355 #define MA_SND_PCM_STATE_OPEN                  0
24356 #define MA_SND_PCM_STATE_SETUP                 1
24357 #define MA_SND_PCM_STATE_PREPARED              2
24358 #define MA_SND_PCM_STATE_RUNNING               3
24359 #define MA_SND_PCM_STATE_XRUN                  4
24360 #define MA_SND_PCM_STATE_DRAINING              5
24361 #define MA_SND_PCM_STATE_PAUSED                6
24362 #define MA_SND_PCM_STATE_SUSPENDED             7
24363 #define MA_SND_PCM_STATE_DISCONNECTED          8
24364
24365 /* snd_pcm_stream_t */
24366 #define MA_SND_PCM_STREAM_PLAYBACK             0
24367 #define MA_SND_PCM_STREAM_CAPTURE              1
24368
24369 /* snd_pcm_format_t */
24370 #define MA_SND_PCM_FORMAT_UNKNOWN              -1
24371 #define MA_SND_PCM_FORMAT_U8                   1
24372 #define MA_SND_PCM_FORMAT_S16_LE               2
24373 #define MA_SND_PCM_FORMAT_S16_BE               3
24374 #define MA_SND_PCM_FORMAT_S24_LE               6
24375 #define MA_SND_PCM_FORMAT_S24_BE               7
24376 #define MA_SND_PCM_FORMAT_S32_LE               10
24377 #define MA_SND_PCM_FORMAT_S32_BE               11
24378 #define MA_SND_PCM_FORMAT_FLOAT_LE             14
24379 #define MA_SND_PCM_FORMAT_FLOAT_BE             15
24380 #define MA_SND_PCM_FORMAT_FLOAT64_LE           16
24381 #define MA_SND_PCM_FORMAT_FLOAT64_BE           17
24382 #define MA_SND_PCM_FORMAT_MU_LAW               20
24383 #define MA_SND_PCM_FORMAT_A_LAW                21
24384 #define MA_SND_PCM_FORMAT_S24_3LE              32
24385 #define MA_SND_PCM_FORMAT_S24_3BE              33
24386
24387 /* snd_pcm_access_t */
24388 #define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED     0
24389 #define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED  1
24390 #define MA_SND_PCM_ACCESS_MMAP_COMPLEX         2
24391 #define MA_SND_PCM_ACCESS_RW_INTERLEAVED       3
24392 #define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED    4
24393
24394 /* Channel positions. */
24395 #define MA_SND_CHMAP_UNKNOWN                   0
24396 #define MA_SND_CHMAP_NA                        1
24397 #define MA_SND_CHMAP_MONO                      2
24398 #define MA_SND_CHMAP_FL                        3
24399 #define MA_SND_CHMAP_FR                        4
24400 #define MA_SND_CHMAP_RL                        5
24401 #define MA_SND_CHMAP_RR                        6
24402 #define MA_SND_CHMAP_FC                        7
24403 #define MA_SND_CHMAP_LFE                       8
24404 #define MA_SND_CHMAP_SL                        9
24405 #define MA_SND_CHMAP_SR                        10
24406 #define MA_SND_CHMAP_RC                        11
24407 #define MA_SND_CHMAP_FLC                       12
24408 #define MA_SND_CHMAP_FRC                       13
24409 #define MA_SND_CHMAP_RLC                       14
24410 #define MA_SND_CHMAP_RRC                       15
24411 #define MA_SND_CHMAP_FLW                       16
24412 #define MA_SND_CHMAP_FRW                       17
24413 #define MA_SND_CHMAP_FLH                       18
24414 #define MA_SND_CHMAP_FCH                       19
24415 #define MA_SND_CHMAP_FRH                       20
24416 #define MA_SND_CHMAP_TC                        21
24417 #define MA_SND_CHMAP_TFL                       22
24418 #define MA_SND_CHMAP_TFR                       23
24419 #define MA_SND_CHMAP_TFC                       24
24420 #define MA_SND_CHMAP_TRL                       25
24421 #define MA_SND_CHMAP_TRR                       26
24422 #define MA_SND_CHMAP_TRC                       27
24423 #define MA_SND_CHMAP_TFLC                      28
24424 #define MA_SND_CHMAP_TFRC                      29
24425 #define MA_SND_CHMAP_TSL                       30
24426 #define MA_SND_CHMAP_TSR                       31
24427 #define MA_SND_CHMAP_LLFE                      32
24428 #define MA_SND_CHMAP_RLFE                      33
24429 #define MA_SND_CHMAP_BC                        34
24430 #define MA_SND_CHMAP_BLC                       35
24431 #define MA_SND_CHMAP_BRC                       36
24432
24433 /* Open mode flags. */
24434 #define MA_SND_PCM_NO_AUTO_RESAMPLE            0x00010000
24435 #define MA_SND_PCM_NO_AUTO_CHANNELS            0x00020000
24436 #define MA_SND_PCM_NO_AUTO_FORMAT              0x00040000
24437 #endif
24438
24439 typedef int                  (* ma_snd_pcm_open_proc)                          (ma_snd_pcm_t **pcm, const char *name, ma_snd_pcm_stream_t stream, int mode);
24440 typedef int                  (* ma_snd_pcm_close_proc)                         (ma_snd_pcm_t *pcm);
24441 typedef size_t               (* ma_snd_pcm_hw_params_sizeof_proc)              (void);
24442 typedef int                  (* ma_snd_pcm_hw_params_any_proc)                 (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params);
24443 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);
24444 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);
24445 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);
24446 typedef int                  (* ma_snd_pcm_hw_params_set_channels_proc)        (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val);
24447 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);
24448 typedef int                  (* ma_snd_pcm_hw_params_set_channels_minmax_proc) (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int *minimum, unsigned int *maximum);
24449 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);
24450 typedef int                  (* ma_snd_pcm_hw_params_set_rate_proc)            (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val, int dir);
24451 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);
24452 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);
24453 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);
24454 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);
24455 typedef int                  (* ma_snd_pcm_hw_params_get_format_proc)          (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t *format);
24456 typedef int                  (* ma_snd_pcm_hw_params_get_channels_proc)        (const ma_snd_pcm_hw_params_t *params, unsigned int *val);
24457 typedef int                  (* ma_snd_pcm_hw_params_get_channels_min_proc)    (const ma_snd_pcm_hw_params_t *params, unsigned int *val);
24458 typedef int                  (* ma_snd_pcm_hw_params_get_channels_max_proc)    (const ma_snd_pcm_hw_params_t *params, unsigned int *val);
24459 typedef int                  (* ma_snd_pcm_hw_params_get_rate_proc)            (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir);
24460 typedef int                  (* ma_snd_pcm_hw_params_get_rate_min_proc)        (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir);
24461 typedef int                  (* ma_snd_pcm_hw_params_get_rate_max_proc)        (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir);
24462 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);
24463 typedef int                  (* ma_snd_pcm_hw_params_get_periods_proc)         (const ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
24464 typedef int                  (* ma_snd_pcm_hw_params_get_access_proc)          (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t *_access);
24465 typedef int                  (* ma_snd_pcm_hw_params_test_format_proc)         (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t val);
24466 typedef int                  (* ma_snd_pcm_hw_params_test_channels_proc)       (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val);
24467 typedef int                  (* ma_snd_pcm_hw_params_test_rate_proc)           (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params, unsigned int val, int dir);
24468 typedef int                  (* ma_snd_pcm_hw_params_proc)                     (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params);
24469 typedef size_t               (* ma_snd_pcm_sw_params_sizeof_proc)              (void);
24470 typedef int                  (* ma_snd_pcm_sw_params_current_proc)             (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params);
24471 typedef int                  (* ma_snd_pcm_sw_params_get_boundary_proc)        (const ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t* val);
24472 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);
24473 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);
24474 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);
24475 typedef int                  (* ma_snd_pcm_sw_params_proc)                     (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params);
24476 typedef size_t               (* ma_snd_pcm_format_mask_sizeof_proc)            (void);
24477 typedef int                  (* ma_snd_pcm_format_mask_test_proc)              (const ma_snd_pcm_format_mask_t *mask, ma_snd_pcm_format_t val);
24478 typedef ma_snd_pcm_chmap_t * (* ma_snd_pcm_get_chmap_proc)                     (ma_snd_pcm_t *pcm);
24479 typedef ma_snd_pcm_state_t   (* ma_snd_pcm_state_proc)                         (ma_snd_pcm_t *pcm);
24480 typedef int                  (* ma_snd_pcm_prepare_proc)                       (ma_snd_pcm_t *pcm);
24481 typedef int                  (* ma_snd_pcm_start_proc)                         (ma_snd_pcm_t *pcm);
24482 typedef int                  (* ma_snd_pcm_drop_proc)                          (ma_snd_pcm_t *pcm);
24483 typedef int                  (* ma_snd_pcm_drain_proc)                         (ma_snd_pcm_t *pcm);
24484 typedef int                  (* ma_snd_pcm_reset_proc)                         (ma_snd_pcm_t *pcm);
24485 typedef int                  (* ma_snd_device_name_hint_proc)                  (int card, const char *iface, void ***hints);
24486 typedef char *               (* ma_snd_device_name_get_hint_proc)              (const void *hint, const char *id);
24487 typedef int                  (* ma_snd_card_get_index_proc)                    (const char *name);
24488 typedef int                  (* ma_snd_device_name_free_hint_proc)             (void **hints);
24489 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);
24490 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);
24491 typedef int                  (* ma_snd_pcm_recover_proc)                       (ma_snd_pcm_t *pcm, int err, int silent);
24492 typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_readi_proc)                         (ma_snd_pcm_t *pcm, void *buffer, ma_snd_pcm_uframes_t size);
24493 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);
24494 typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_avail_proc)                         (ma_snd_pcm_t *pcm);
24495 typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_avail_update_proc)                  (ma_snd_pcm_t *pcm);
24496 typedef int                  (* ma_snd_pcm_wait_proc)                          (ma_snd_pcm_t *pcm, int timeout);
24497 typedef int                  (* ma_snd_pcm_nonblock_proc)                      (ma_snd_pcm_t *pcm, int nonblock);
24498 typedef int                  (* ma_snd_pcm_info_proc)                          (ma_snd_pcm_t *pcm, ma_snd_pcm_info_t* info);
24499 typedef size_t               (* ma_snd_pcm_info_sizeof_proc)                   (void);
24500 typedef const char*          (* ma_snd_pcm_info_get_name_proc)                 (const ma_snd_pcm_info_t* info);
24501 typedef int                  (* ma_snd_pcm_poll_descriptors_proc)              (ma_snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space);
24502 typedef int                  (* ma_snd_pcm_poll_descriptors_count_proc)        (ma_snd_pcm_t *pcm);
24503 typedef int                  (* ma_snd_pcm_poll_descriptors_revents_proc)      (ma_snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
24504 typedef int                  (* ma_snd_config_update_free_global_proc)         (void);
24505
24506 /* This array specifies each of the common devices that can be used for both playback and capture. */
24507 static const char* g_maCommonDeviceNamesALSA[] = {
24508     "default",
24509     "null",
24510     "pulse",
24511     "jack"
24512 };
24513
24514 /* This array allows us to blacklist specific playback devices. */
24515 static const char* g_maBlacklistedPlaybackDeviceNamesALSA[] = {
24516     ""
24517 };
24518
24519 /* This array allows us to blacklist specific capture devices. */
24520 static const char* g_maBlacklistedCaptureDeviceNamesALSA[] = {
24521     ""
24522 };
24523
24524
24525 static ma_snd_pcm_format_t ma_convert_ma_format_to_alsa_format(ma_format format)
24526 {
24527     ma_snd_pcm_format_t ALSAFormats[] = {
24528         MA_SND_PCM_FORMAT_UNKNOWN,     /* ma_format_unknown */
24529         MA_SND_PCM_FORMAT_U8,          /* ma_format_u8 */
24530         MA_SND_PCM_FORMAT_S16_LE,      /* ma_format_s16 */
24531         MA_SND_PCM_FORMAT_S24_3LE,     /* ma_format_s24 */
24532         MA_SND_PCM_FORMAT_S32_LE,      /* ma_format_s32 */
24533         MA_SND_PCM_FORMAT_FLOAT_LE     /* ma_format_f32 */
24534     };
24535
24536     if (ma_is_big_endian()) {
24537         ALSAFormats[0] = MA_SND_PCM_FORMAT_UNKNOWN;
24538         ALSAFormats[1] = MA_SND_PCM_FORMAT_U8;
24539         ALSAFormats[2] = MA_SND_PCM_FORMAT_S16_BE;
24540         ALSAFormats[3] = MA_SND_PCM_FORMAT_S24_3BE;
24541         ALSAFormats[4] = MA_SND_PCM_FORMAT_S32_BE;
24542         ALSAFormats[5] = MA_SND_PCM_FORMAT_FLOAT_BE;
24543     }
24544
24545     return ALSAFormats[format];
24546 }
24547
24548 static ma_format ma_format_from_alsa(ma_snd_pcm_format_t formatALSA)
24549 {
24550     if (ma_is_little_endian()) {
24551         switch (formatALSA) {
24552             case MA_SND_PCM_FORMAT_S16_LE:   return ma_format_s16;
24553             case MA_SND_PCM_FORMAT_S24_3LE:  return ma_format_s24;
24554             case MA_SND_PCM_FORMAT_S32_LE:   return ma_format_s32;
24555             case MA_SND_PCM_FORMAT_FLOAT_LE: return ma_format_f32;
24556             default: break;
24557         }
24558     } else {
24559         switch (formatALSA) {
24560             case MA_SND_PCM_FORMAT_S16_BE:   return ma_format_s16;
24561             case MA_SND_PCM_FORMAT_S24_3BE:  return ma_format_s24;
24562             case MA_SND_PCM_FORMAT_S32_BE:   return ma_format_s32;
24563             case MA_SND_PCM_FORMAT_FLOAT_BE: return ma_format_f32;
24564             default: break;
24565         }
24566     }
24567
24568     /* Endian agnostic. */
24569     switch (formatALSA) {
24570         case MA_SND_PCM_FORMAT_U8: return ma_format_u8;
24571         default: return ma_format_unknown;
24572     }
24573 }
24574
24575 static ma_channel ma_convert_alsa_channel_position_to_ma_channel(unsigned int alsaChannelPos)
24576 {
24577     switch (alsaChannelPos)
24578     {
24579         case MA_SND_CHMAP_MONO: return MA_CHANNEL_MONO;
24580         case MA_SND_CHMAP_FL:   return MA_CHANNEL_FRONT_LEFT;
24581         case MA_SND_CHMAP_FR:   return MA_CHANNEL_FRONT_RIGHT;
24582         case MA_SND_CHMAP_RL:   return MA_CHANNEL_BACK_LEFT;
24583         case MA_SND_CHMAP_RR:   return MA_CHANNEL_BACK_RIGHT;
24584         case MA_SND_CHMAP_FC:   return MA_CHANNEL_FRONT_CENTER;
24585         case MA_SND_CHMAP_LFE:  return MA_CHANNEL_LFE;
24586         case MA_SND_CHMAP_SL:   return MA_CHANNEL_SIDE_LEFT;
24587         case MA_SND_CHMAP_SR:   return MA_CHANNEL_SIDE_RIGHT;
24588         case MA_SND_CHMAP_RC:   return MA_CHANNEL_BACK_CENTER;
24589         case MA_SND_CHMAP_FLC:  return MA_CHANNEL_FRONT_LEFT_CENTER;
24590         case MA_SND_CHMAP_FRC:  return MA_CHANNEL_FRONT_RIGHT_CENTER;
24591         case MA_SND_CHMAP_RLC:  return 0;
24592         case MA_SND_CHMAP_RRC:  return 0;
24593         case MA_SND_CHMAP_FLW:  return 0;
24594         case MA_SND_CHMAP_FRW:  return 0;
24595         case MA_SND_CHMAP_FLH:  return 0;
24596         case MA_SND_CHMAP_FCH:  return 0;
24597         case MA_SND_CHMAP_FRH:  return 0;
24598         case MA_SND_CHMAP_TC:   return MA_CHANNEL_TOP_CENTER;
24599         case MA_SND_CHMAP_TFL:  return MA_CHANNEL_TOP_FRONT_LEFT;
24600         case MA_SND_CHMAP_TFR:  return MA_CHANNEL_TOP_FRONT_RIGHT;
24601         case MA_SND_CHMAP_TFC:  return MA_CHANNEL_TOP_FRONT_CENTER;
24602         case MA_SND_CHMAP_TRL:  return MA_CHANNEL_TOP_BACK_LEFT;
24603         case MA_SND_CHMAP_TRR:  return MA_CHANNEL_TOP_BACK_RIGHT;
24604         case MA_SND_CHMAP_TRC:  return MA_CHANNEL_TOP_BACK_CENTER;
24605         default: break;
24606     }
24607
24608     return 0;
24609 }
24610
24611 static ma_bool32 ma_is_common_device_name__alsa(const char* name)
24612 {
24613     size_t iName;
24614     for (iName = 0; iName < ma_countof(g_maCommonDeviceNamesALSA); ++iName) {
24615         if (ma_strcmp(name, g_maCommonDeviceNamesALSA[iName]) == 0) {
24616             return MA_TRUE;
24617         }
24618     }
24619
24620     return MA_FALSE;
24621 }
24622
24623
24624 static ma_bool32 ma_is_playback_device_blacklisted__alsa(const char* name)
24625 {
24626     size_t iName;
24627     for (iName = 0; iName < ma_countof(g_maBlacklistedPlaybackDeviceNamesALSA); ++iName) {
24628         if (ma_strcmp(name, g_maBlacklistedPlaybackDeviceNamesALSA[iName]) == 0) {
24629             return MA_TRUE;
24630         }
24631     }
24632
24633     return MA_FALSE;
24634 }
24635
24636 static ma_bool32 ma_is_capture_device_blacklisted__alsa(const char* name)
24637 {
24638     size_t iName;
24639     for (iName = 0; iName < ma_countof(g_maBlacklistedCaptureDeviceNamesALSA); ++iName) {
24640         if (ma_strcmp(name, g_maBlacklistedCaptureDeviceNamesALSA[iName]) == 0) {
24641             return MA_TRUE;
24642         }
24643     }
24644
24645     return MA_FALSE;
24646 }
24647
24648 static ma_bool32 ma_is_device_blacklisted__alsa(ma_device_type deviceType, const char* name)
24649 {
24650     if (deviceType == ma_device_type_playback) {
24651         return ma_is_playback_device_blacklisted__alsa(name);
24652     } else {
24653         return ma_is_capture_device_blacklisted__alsa(name);
24654     }
24655 }
24656
24657
24658 static const char* ma_find_char(const char* str, char c, int* index)
24659 {
24660     int i = 0;
24661     for (;;) {
24662         if (str[i] == '\0') {
24663             if (index) *index = -1;
24664             return NULL;
24665         }
24666
24667         if (str[i] == c) {
24668             if (index) *index = i;
24669             return str + i;
24670         }
24671
24672         i += 1;
24673     }
24674
24675     /* Should never get here, but treat it as though the character was not found to make me feel better inside. */
24676     if (index) *index = -1;
24677     return NULL;
24678 }
24679
24680 static ma_bool32 ma_is_device_name_in_hw_format__alsa(const char* hwid)
24681 {
24682     /* This function is just checking whether or not hwid is in "hw:%d,%d" format. */
24683
24684     int commaPos;
24685     const char* dev;
24686     int i;
24687
24688     if (hwid == NULL) {
24689         return MA_FALSE;
24690     }
24691
24692     if (hwid[0] != 'h' || hwid[1] != 'w' || hwid[2] != ':') {
24693         return MA_FALSE;
24694     }
24695
24696     hwid += 3;
24697
24698     dev = ma_find_char(hwid, ',', &commaPos);
24699     if (dev == NULL) {
24700         return MA_FALSE;
24701     } else {
24702         dev += 1;   /* Skip past the ",". */
24703     }
24704
24705     /* Check if the part between the ":" and the "," contains only numbers. If not, return false. */
24706     for (i = 0; i < commaPos; ++i) {
24707         if (hwid[i] < '0' || hwid[i] > '9') {
24708             return MA_FALSE;
24709         }
24710     }
24711
24712     /* Check if everything after the "," is numeric. If not, return false. */
24713     i = 0;
24714     while (dev[i] != '\0') {
24715         if (dev[i] < '0' || dev[i] > '9') {
24716             return MA_FALSE;
24717         }
24718         i += 1;
24719     }
24720
24721     return MA_TRUE;
24722 }
24723
24724 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. */
24725 {
24726     /* src should look something like this: "hw:CARD=I82801AAICH,DEV=0" */
24727
24728     int colonPos;
24729     int commaPos;
24730     char card[256];
24731     const char* dev;
24732     int cardIndex;
24733
24734     if (dst == NULL) {
24735         return -1;
24736     }
24737     if (dstSize < 7) {
24738         return -1;     /* Absolute minimum size of the output buffer is 7 bytes. */
24739     }
24740
24741     *dst = '\0';    /* Safety. */
24742     if (src == NULL) {
24743         return -1;
24744     }
24745
24746     /* If the input name is already in "hw:%d,%d" format, just return that verbatim. */
24747     if (ma_is_device_name_in_hw_format__alsa(src)) {
24748         return ma_strcpy_s(dst, dstSize, src);
24749     }
24750
24751     src = ma_find_char(src, ':', &colonPos);
24752     if (src == NULL) {
24753         return -1;  /* Couldn't find a colon */
24754     }
24755
24756     dev = ma_find_char(src, ',', &commaPos);
24757     if (dev == NULL) {
24758         dev = "0";
24759         ma_strncpy_s(card, sizeof(card), src+6, (size_t)-1);   /* +6 = ":CARD=" */
24760     } else {
24761         dev = dev + 5;  /* +5 = ",DEV=" */
24762         ma_strncpy_s(card, sizeof(card), src+6, commaPos-6);   /* +6 = ":CARD=" */
24763     }
24764
24765     cardIndex = ((ma_snd_card_get_index_proc)pContext->alsa.snd_card_get_index)(card);
24766     if (cardIndex < 0) {
24767         return -2;  /* Failed to retrieve the card index. */
24768     }
24769
24770
24771     /* Construction. */
24772     dst[0] = 'h'; dst[1] = 'w'; dst[2] = ':';
24773     if (ma_itoa_s(cardIndex, dst+3, dstSize-3, 10) != 0) {
24774         return -3;
24775     }
24776     if (ma_strcat_s(dst, dstSize, ",") != 0) {
24777         return -3;
24778     }
24779     if (ma_strcat_s(dst, dstSize, dev) != 0) {
24780         return -3;
24781     }
24782
24783     return 0;
24784 }
24785
24786 static ma_bool32 ma_does_id_exist_in_list__alsa(ma_device_id* pUniqueIDs, ma_uint32 count, const char* pHWID)
24787 {
24788     ma_uint32 i;
24789
24790     MA_ASSERT(pHWID != NULL);
24791
24792     for (i = 0; i < count; ++i) {
24793         if (ma_strcmp(pUniqueIDs[i].alsa, pHWID) == 0) {
24794             return MA_TRUE;
24795         }
24796     }
24797
24798     return MA_FALSE;
24799 }
24800
24801
24802 static ma_result ma_context_open_pcm__alsa(ma_context* pContext, ma_share_mode shareMode, ma_device_type deviceType, const ma_device_id* pDeviceID, int openMode, ma_snd_pcm_t** ppPCM)
24803 {
24804     ma_snd_pcm_t* pPCM;
24805     ma_snd_pcm_stream_t stream;
24806
24807     MA_ASSERT(pContext != NULL);
24808     MA_ASSERT(ppPCM != NULL);
24809
24810     *ppPCM = NULL;
24811     pPCM = NULL;
24812
24813     stream = (deviceType == ma_device_type_playback) ? MA_SND_PCM_STREAM_PLAYBACK : MA_SND_PCM_STREAM_CAPTURE;
24814
24815     if (pDeviceID == NULL) {
24816         ma_bool32 isDeviceOpen;
24817         size_t i;
24818
24819         /*
24820         We're opening the default device. I don't know if trying anything other than "default" is necessary, but it makes
24821         me feel better to try as hard as we can get to get _something_ working.
24822         */
24823         const char* defaultDeviceNames[] = {
24824             "default",
24825             NULL,
24826             NULL,
24827             NULL,
24828             NULL,
24829             NULL,
24830             NULL
24831         };
24832
24833         if (shareMode == ma_share_mode_exclusive) {
24834             defaultDeviceNames[1] = "hw";
24835             defaultDeviceNames[2] = "hw:0";
24836             defaultDeviceNames[3] = "hw:0,0";
24837         } else {
24838             if (deviceType == ma_device_type_playback) {
24839                 defaultDeviceNames[1] = "dmix";
24840                 defaultDeviceNames[2] = "dmix:0";
24841                 defaultDeviceNames[3] = "dmix:0,0";
24842             } else {
24843                 defaultDeviceNames[1] = "dsnoop";
24844                 defaultDeviceNames[2] = "dsnoop:0";
24845                 defaultDeviceNames[3] = "dsnoop:0,0";
24846             }
24847             defaultDeviceNames[4] = "hw";
24848             defaultDeviceNames[5] = "hw:0";
24849             defaultDeviceNames[6] = "hw:0,0";
24850         }
24851
24852         isDeviceOpen = MA_FALSE;
24853         for (i = 0; i < ma_countof(defaultDeviceNames); ++i) {
24854             if (defaultDeviceNames[i] != NULL && defaultDeviceNames[i][0] != '\0') {
24855                 if (((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, defaultDeviceNames[i], stream, openMode) == 0) {
24856                     isDeviceOpen = MA_TRUE;
24857                     break;
24858                 }
24859             }
24860         }
24861
24862         if (!isDeviceOpen) {
24863             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.");
24864             return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
24865         }
24866     } else {
24867         /*
24868         We're trying to open a specific device. There's a few things to consider here:
24869
24870         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
24871         an ID of this format is specified, it indicates to miniaudio that it can try different combinations of plugins ("hw", "dmix", etc.) until it
24872         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").
24873         */
24874
24875         /* May end up needing to make small adjustments to the ID, so make a copy. */
24876         ma_device_id deviceID = *pDeviceID;
24877         int resultALSA = -ENODEV;
24878
24879         if (deviceID.alsa[0] != ':') {
24880             /* The ID is not in ":0,0" format. Use the ID exactly as-is. */
24881             resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, deviceID.alsa, stream, openMode);
24882         } else {
24883             char hwid[256];
24884
24885             /* The ID is in ":0,0" format. Try different plugins depending on the shared mode. */
24886             if (deviceID.alsa[1] == '\0') {
24887                 deviceID.alsa[0] = '\0';  /* An ID of ":" should be converted to "". */
24888             }
24889
24890             if (shareMode == ma_share_mode_shared) {
24891                 if (deviceType == ma_device_type_playback) {
24892                     ma_strcpy_s(hwid, sizeof(hwid), "dmix");
24893                 } else {
24894                     ma_strcpy_s(hwid, sizeof(hwid), "dsnoop");
24895                 }
24896
24897                 if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) {
24898                     resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode);
24899                 }
24900             }
24901
24902             /* 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. */
24903             if (resultALSA != 0) {
24904                 ma_strcpy_s(hwid, sizeof(hwid), "hw");
24905                 if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) {
24906                     resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode);
24907                 }
24908             }
24909         }
24910
24911         if (resultALSA < 0) {
24912             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed.");
24913             return ma_result_from_errno(-resultALSA);
24914         }
24915     }
24916
24917     *ppPCM = pPCM;
24918     return MA_SUCCESS;
24919 }
24920
24921
24922 static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
24923 {
24924     int resultALSA;
24925     ma_bool32 cbResult = MA_TRUE;
24926     char** ppDeviceHints;
24927     ma_device_id* pUniqueIDs = NULL;
24928     ma_uint32 uniqueIDCount = 0;
24929     char** ppNextDeviceHint;
24930
24931     MA_ASSERT(pContext != NULL);
24932     MA_ASSERT(callback != NULL);
24933
24934     ma_mutex_lock(&pContext->alsa.internalDeviceEnumLock);
24935
24936     resultALSA = ((ma_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints);
24937     if (resultALSA < 0) {
24938         ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock);
24939         return ma_result_from_errno(-resultALSA);
24940     }
24941
24942     ppNextDeviceHint = ppDeviceHints;
24943     while (*ppNextDeviceHint != NULL) {
24944         char* NAME = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME");
24945         char* DESC = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC");
24946         char* IOID = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID");
24947         ma_device_type deviceType = ma_device_type_playback;
24948         ma_bool32 stopEnumeration = MA_FALSE;
24949         char hwid[sizeof(pUniqueIDs->alsa)];
24950         ma_device_info deviceInfo;
24951
24952         if ((IOID == NULL || ma_strcmp(IOID, "Output") == 0)) {
24953             deviceType = ma_device_type_playback;
24954         }
24955         if ((IOID != NULL && ma_strcmp(IOID, "Input" ) == 0)) {
24956             deviceType = ma_device_type_capture;
24957         }
24958
24959         if (NAME != NULL) {
24960             if (pContext->alsa.useVerboseDeviceEnumeration) {
24961                 /* Verbose mode. Use the name exactly as-is. */
24962                 ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
24963             } else {
24964                 /* Simplified mode. Use ":%d,%d" format. */
24965                 if (ma_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) {
24966                     /*
24967                     At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the
24968                     plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device
24969                     initialization time and is used as an indicator to try and use the most appropriate plugin depending on the
24970                     device type and sharing mode.
24971                     */
24972                     char* dst = hwid;
24973                     char* src = hwid+2;
24974                     while ((*dst++ = *src++));
24975                 } else {
24976                     /* Conversion to "hw:%d,%d" failed. Just use the name as-is. */
24977                     ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
24978                 }
24979
24980                 if (ma_does_id_exist_in_list__alsa(pUniqueIDs, uniqueIDCount, hwid)) {
24981                     goto next_device;   /* The device has already been enumerated. Move on to the next one. */
24982                 } else {
24983                     /* The device has not yet been enumerated. Make sure it's added to our list so that it's not enumerated again. */
24984                     size_t newCapacity = sizeof(*pUniqueIDs) * (uniqueIDCount + 1);
24985                     ma_device_id* pNewUniqueIDs = (ma_device_id*)ma_realloc(pUniqueIDs, newCapacity, &pContext->allocationCallbacks);
24986                     if (pNewUniqueIDs == NULL) {
24987                         goto next_device;   /* Failed to allocate memory. */
24988                     }
24989
24990                     pUniqueIDs = pNewUniqueIDs;
24991                     MA_COPY_MEMORY(pUniqueIDs[uniqueIDCount].alsa, hwid, sizeof(hwid));
24992                     uniqueIDCount += 1;
24993                 }
24994             }
24995         } else {
24996             MA_ZERO_MEMORY(hwid, sizeof(hwid));
24997         }
24998
24999         MA_ZERO_OBJECT(&deviceInfo);
25000         ma_strncpy_s(deviceInfo.id.alsa, sizeof(deviceInfo.id.alsa), hwid, (size_t)-1);
25001
25002         /*
25003         There's no good way to determine whether or not a device is the default on Linux. We're just going to do something simple and
25004         just use the name of "default" as the indicator.
25005         */
25006         if (ma_strcmp(deviceInfo.id.alsa, "default") == 0) {
25007             deviceInfo.isDefault = MA_TRUE;
25008         }
25009
25010
25011         /*
25012         DESC is the friendly name. We treat this slightly differently depending on whether or not we are using verbose
25013         device enumeration. In verbose mode we want to take the entire description so that the end-user can distinguish
25014         between the subdevices of each card/dev pair. In simplified mode, however, we only want the first part of the
25015         description.
25016
25017         The value in DESC seems to be split into two lines, with the first line being the name of the device and the
25018         second line being a description of the device. I don't like having the description be across two lines because
25019         it makes formatting ugly and annoying. I'm therefore deciding to put it all on a single line with the second line
25020         being put into parentheses. In simplified mode I'm just stripping the second line entirely.
25021         */
25022         if (DESC != NULL) {
25023             int lfPos;
25024             const char* line2 = ma_find_char(DESC, '\n', &lfPos);
25025             if (line2 != NULL) {
25026                 line2 += 1; /* Skip past the new-line character. */
25027
25028                 if (pContext->alsa.useVerboseDeviceEnumeration) {
25029                     /* Verbose mode. Put the second line in brackets. */
25030                     ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos);
25031                     ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), " (");
25032                     ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), line2);
25033                     ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), ")");
25034                 } else {
25035                     /* Simplified mode. Strip the second line entirely. */
25036                     ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos);
25037                 }
25038             } else {
25039                 /* There's no second line. Just copy the whole description. */
25040                 ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, (size_t)-1);
25041             }
25042         }
25043
25044         if (!ma_is_device_blacklisted__alsa(deviceType, NAME)) {
25045             cbResult = callback(pContext, deviceType, &deviceInfo, pUserData);
25046         }
25047
25048         /*
25049         Some devices are both playback and capture, but they are only enumerated by ALSA once. We need to fire the callback
25050         again for the other device type in this case. We do this for known devices and where the IOID hint is NULL, which
25051         means both Input and Output.
25052         */
25053         if (cbResult) {
25054             if (ma_is_common_device_name__alsa(NAME) || IOID == NULL) {
25055                 if (deviceType == ma_device_type_playback) {
25056                     if (!ma_is_capture_device_blacklisted__alsa(NAME)) {
25057                         cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
25058                     }
25059                 } else {
25060                     if (!ma_is_playback_device_blacklisted__alsa(NAME)) {
25061                         cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
25062                     }
25063                 }
25064             }
25065         }
25066
25067         if (cbResult == MA_FALSE) {
25068             stopEnumeration = MA_TRUE;
25069         }
25070
25071     next_device:
25072         free(NAME);
25073         free(DESC);
25074         free(IOID);
25075         ppNextDeviceHint += 1;
25076
25077         /* We need to stop enumeration if the callback returned false. */
25078         if (stopEnumeration) {
25079             break;
25080         }
25081     }
25082
25083     ma_free(pUniqueIDs, &pContext->allocationCallbacks);
25084     ((ma_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints);
25085
25086     ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock);
25087
25088     return MA_SUCCESS;
25089 }
25090
25091
25092 typedef struct
25093 {
25094     ma_device_type deviceType;
25095     const ma_device_id* pDeviceID;
25096     ma_share_mode shareMode;
25097     ma_device_info* pDeviceInfo;
25098     ma_bool32 foundDevice;
25099 } ma_context_get_device_info_enum_callback_data__alsa;
25100
25101 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)
25102 {
25103     ma_context_get_device_info_enum_callback_data__alsa* pData = (ma_context_get_device_info_enum_callback_data__alsa*)pUserData;
25104     MA_ASSERT(pData != NULL);
25105
25106     (void)pContext;
25107
25108     if (pData->pDeviceID == NULL && ma_strcmp(pDeviceInfo->id.alsa, "default") == 0) {
25109         ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1);
25110         pData->foundDevice = MA_TRUE;
25111     } else {
25112         if (pData->deviceType == deviceType && (pData->pDeviceID != NULL && ma_strcmp(pData->pDeviceID->alsa, pDeviceInfo->id.alsa) == 0)) {
25113             ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1);
25114             pData->foundDevice = MA_TRUE;
25115         }
25116     }
25117
25118     /* Keep enumerating until we have found the device. */
25119     return !pData->foundDevice;
25120 }
25121
25122 static void ma_context_test_rate_and_add_native_data_format__alsa(ma_context* pContext, ma_snd_pcm_t* pPCM, ma_snd_pcm_hw_params_t* pHWParams, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 flags, ma_device_info* pDeviceInfo)
25123 {
25124     MA_ASSERT(pPCM        != NULL);
25125     MA_ASSERT(pHWParams   != NULL);
25126     MA_ASSERT(pDeviceInfo != NULL);
25127
25128     if (pDeviceInfo->nativeDataFormatCount < ma_countof(pDeviceInfo->nativeDataFormats) && ((ma_snd_pcm_hw_params_test_rate_proc)pContext->alsa.snd_pcm_hw_params_test_rate)(pPCM, pHWParams, sampleRate, 0) == 0) {
25129         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = format;
25130         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
25131         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate;
25132         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = flags;
25133         pDeviceInfo->nativeDataFormatCount += 1;
25134     }
25135 }
25136
25137 static void ma_context_iterate_rates_and_add_native_data_format__alsa(ma_context* pContext, ma_snd_pcm_t* pPCM, ma_snd_pcm_hw_params_t* pHWParams, ma_format format, ma_uint32 channels, ma_uint32 flags, ma_device_info* pDeviceInfo)
25138 {
25139     ma_uint32 iSampleRate;
25140     unsigned int minSampleRate;
25141     unsigned int maxSampleRate;
25142     int sampleRateDir;  /* Not used. Just passed into snd_pcm_hw_params_get_rate_min/max(). */
25143
25144     /* There could be a range. */
25145     ((ma_snd_pcm_hw_params_get_rate_min_proc)pContext->alsa.snd_pcm_hw_params_get_rate_min)(pHWParams, &minSampleRate, &sampleRateDir);
25146     ((ma_snd_pcm_hw_params_get_rate_max_proc)pContext->alsa.snd_pcm_hw_params_get_rate_max)(pHWParams, &maxSampleRate, &sampleRateDir);
25147
25148     /* Make sure our sample rates are clamped to sane values. Stupid devices like "pulse" will reports rates like "1" which is ridiculus. */
25149     minSampleRate = ma_clamp(minSampleRate, (unsigned int)ma_standard_sample_rate_min, (unsigned int)ma_standard_sample_rate_max);
25150     maxSampleRate = ma_clamp(maxSampleRate, (unsigned int)ma_standard_sample_rate_min, (unsigned int)ma_standard_sample_rate_max);
25151
25152     for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); iSampleRate += 1) {
25153         ma_uint32 standardSampleRate = g_maStandardSampleRatePriorities[iSampleRate];
25154
25155         if (standardSampleRate >= minSampleRate && standardSampleRate <= maxSampleRate) {
25156             ma_context_test_rate_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, standardSampleRate, flags, pDeviceInfo);
25157         }
25158     }
25159
25160     /* Now make sure our min and max rates are included just in case they aren't in the range of our standard rates. */
25161     if (!ma_is_standard_sample_rate(minSampleRate)) {
25162         ma_context_test_rate_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, minSampleRate, flags, pDeviceInfo);
25163     }
25164
25165     if (!ma_is_standard_sample_rate(maxSampleRate) && maxSampleRate != minSampleRate) {
25166         ma_context_test_rate_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, maxSampleRate, flags, pDeviceInfo);
25167     }
25168 }
25169
25170 static ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
25171 {
25172     ma_context_get_device_info_enum_callback_data__alsa data;
25173     ma_result result;
25174     int resultALSA;
25175     ma_snd_pcm_t* pPCM;
25176     ma_snd_pcm_hw_params_t* pHWParams;
25177     ma_uint32 iFormat;
25178     ma_uint32 iChannel;
25179
25180     MA_ASSERT(pContext != NULL);
25181
25182     /* We just enumerate to find basic information about the device. */
25183     data.deviceType  = deviceType;
25184     data.pDeviceID   = pDeviceID;
25185     data.pDeviceInfo = pDeviceInfo;
25186     data.foundDevice = MA_FALSE;
25187     result = ma_context_enumerate_devices__alsa(pContext, ma_context_get_device_info_enum_callback__alsa, &data);
25188     if (result != MA_SUCCESS) {
25189         return result;
25190     }
25191
25192     if (!data.foundDevice) {
25193         return MA_NO_DEVICE;
25194     }
25195
25196     if (ma_strcmp(pDeviceInfo->id.alsa, "default") == 0) {
25197         pDeviceInfo->isDefault = MA_TRUE;
25198     }
25199
25200     /* For detailed info we need to open the device. */
25201     result = ma_context_open_pcm__alsa(pContext, ma_share_mode_shared, deviceType, pDeviceID, 0, &pPCM);
25202     if (result != MA_SUCCESS) {
25203         return result;
25204     }
25205
25206     /* We need to initialize a HW parameters object in order to know what formats are supported. */
25207     pHWParams = (ma_snd_pcm_hw_params_t*)ma_calloc(((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)(), &pContext->allocationCallbacks);
25208     if (pHWParams == NULL) {
25209         ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM);
25210         return MA_OUT_OF_MEMORY;
25211     }
25212
25213     resultALSA = ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
25214     if (resultALSA < 0) {
25215         ma_free(pHWParams, &pContext->allocationCallbacks);
25216         ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM);
25217         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.");
25218         return ma_result_from_errno(-resultALSA);
25219     }
25220
25221     /*
25222     Some ALSA devices can support many permutations of formats, channels and rates. We only support
25223     a fixed number of permutations which means we need to employ some strategies to ensure the best
25224     combinations are returned. An example is the "pulse" device which can do it's own data conversion
25225     in software and as a result can support any combination of format, channels and rate.
25226
25227     We want to ensure the the first data formats are the best. We have a list of favored sample
25228     formats and sample rates, so these will be the basis of our iteration.
25229     */
25230
25231     /* Formats. We just iterate over our standard formats and test them, making sure we reset the configuration space each iteration. */
25232     for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); iFormat += 1) {
25233         ma_format format = g_maFormatPriorities[iFormat];
25234
25235         /*
25236         For each format we need to make sure we reset the configuration space so we don't return
25237         channel counts and rates that aren't compatible with a format.
25238         */
25239         ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
25240
25241         /* Test the format first. If this fails it means the format is not supported and we can skip it. */
25242         if (((ma_snd_pcm_hw_params_test_format_proc)pContext->alsa.snd_pcm_hw_params_test_format)(pPCM, pHWParams, ma_convert_ma_format_to_alsa_format(format)) == 0) {
25243             /* The format is supported. */
25244             unsigned int minChannels;
25245             unsigned int maxChannels;
25246
25247             /*
25248             The configuration space needs to be restricted to this format so we can get an accurate
25249             picture of which sample rates and channel counts are support with this format.
25250             */
25251             ((ma_snd_pcm_hw_params_set_format_proc)pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, ma_convert_ma_format_to_alsa_format(format));
25252
25253             /* Now we need to check for supported channels. */
25254             ((ma_snd_pcm_hw_params_get_channels_min_proc)pContext->alsa.snd_pcm_hw_params_get_channels_min)(pHWParams, &minChannels);
25255             ((ma_snd_pcm_hw_params_get_channels_max_proc)pContext->alsa.snd_pcm_hw_params_get_channels_max)(pHWParams, &maxChannels);
25256
25257             if (minChannels > MA_MAX_CHANNELS) {
25258                 continue;   /* Too many channels. */
25259             }
25260             if (maxChannels < MA_MIN_CHANNELS) {
25261                 continue;   /* Not enough channels. */
25262             }
25263
25264             /*
25265             Make sure the channel count is clamped. This is mainly intended for the max channels
25266             because some devices can report an unbound maximum.
25267             */
25268             minChannels = ma_clamp(minChannels, MA_MIN_CHANNELS, MA_MAX_CHANNELS);
25269             maxChannels = ma_clamp(maxChannels, MA_MIN_CHANNELS, MA_MAX_CHANNELS);
25270
25271             if (minChannels == MA_MIN_CHANNELS && maxChannels == MA_MAX_CHANNELS) {
25272                 /* The device supports all channels. Don't iterate over every single one. Instead just set the channels to 0 which means all channels are supported. */
25273                 ma_context_iterate_rates_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, 0, 0, pDeviceInfo);    /* Intentionally setting the channel count to 0 as that means all channels are supported. */
25274             } else {
25275                 /* The device only supports a specific set of channels. We need to iterate over all of them. */
25276                 for (iChannel = minChannels; iChannel <= maxChannels; iChannel += 1) {
25277                     /* Test the channel before applying it to the configuration space. */
25278                     unsigned int channels = iChannel;
25279
25280                     /* Make sure our channel range is reset before testing again or else we'll always fail the test. */
25281                     ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
25282                     ((ma_snd_pcm_hw_params_set_format_proc)pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, ma_convert_ma_format_to_alsa_format(format));
25283
25284                     if (((ma_snd_pcm_hw_params_test_channels_proc)pContext->alsa.snd_pcm_hw_params_test_channels)(pPCM, pHWParams, channels) == 0) {
25285                         /* The channel count is supported. */
25286
25287                         /* The configuration space now needs to be restricted to the channel count before extracting the sample rate. */
25288                         ((ma_snd_pcm_hw_params_set_channels_proc)pContext->alsa.snd_pcm_hw_params_set_channels)(pPCM, pHWParams, channels);
25289
25290                         /* Only after the configuration space has been restricted to the specific channel count should we iterate over our sample rates. */
25291                         ma_context_iterate_rates_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, 0, pDeviceInfo);
25292                     } else {
25293                         /* The channel count is not supported. Skip. */
25294                     }
25295                 }
25296             }
25297         } else {
25298             /* The format is not supported. Skip. */
25299         }
25300     }
25301
25302     ma_free(pHWParams, &pContext->allocationCallbacks);
25303
25304     ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM);
25305     return MA_SUCCESS;
25306 }
25307
25308 static ma_result ma_device_uninit__alsa(ma_device* pDevice)
25309 {
25310     MA_ASSERT(pDevice != NULL);
25311
25312     if ((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) {
25313         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
25314         close(pDevice->alsa.wakeupfdCapture);
25315         ma_free(pDevice->alsa.pPollDescriptorsCapture, &pDevice->pContext->allocationCallbacks);
25316     }
25317
25318     if ((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) {
25319         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
25320         close(pDevice->alsa.wakeupfdPlayback);
25321         ma_free(pDevice->alsa.pPollDescriptorsPlayback, &pDevice->pContext->allocationCallbacks);
25322     }
25323
25324     return MA_SUCCESS;
25325 }
25326
25327 static ma_result ma_device_init_by_type__alsa(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType)
25328 {
25329     ma_result result;
25330     int resultALSA;
25331     ma_snd_pcm_t* pPCM;
25332     ma_bool32 isUsingMMap;
25333     ma_snd_pcm_format_t formatALSA;
25334     ma_format internalFormat;
25335     ma_uint32 internalChannels;
25336     ma_uint32 internalSampleRate;
25337     ma_channel internalChannelMap[MA_MAX_CHANNELS];
25338     ma_uint32 internalPeriodSizeInFrames;
25339     ma_uint32 internalPeriods;
25340     int openMode;
25341     ma_snd_pcm_hw_params_t* pHWParams;
25342     ma_snd_pcm_sw_params_t* pSWParams;
25343     ma_snd_pcm_uframes_t bufferBoundary;
25344     int pollDescriptorCount;
25345     struct pollfd* pPollDescriptors;
25346     int wakeupfd;
25347
25348     MA_ASSERT(pConfig != NULL);
25349     MA_ASSERT(deviceType != ma_device_type_duplex); /* This function should only be called for playback _or_ capture, never duplex. */
25350     MA_ASSERT(pDevice != NULL);
25351
25352     formatALSA = ma_convert_ma_format_to_alsa_format(pDescriptor->format);
25353
25354     openMode = 0;
25355     if (pConfig->alsa.noAutoResample) {
25356         openMode |= MA_SND_PCM_NO_AUTO_RESAMPLE;
25357     }
25358     if (pConfig->alsa.noAutoChannels) {
25359         openMode |= MA_SND_PCM_NO_AUTO_CHANNELS;
25360     }
25361     if (pConfig->alsa.noAutoFormat) {
25362         openMode |= MA_SND_PCM_NO_AUTO_FORMAT;
25363     }
25364
25365     result = ma_context_open_pcm__alsa(pDevice->pContext, pDescriptor->shareMode, deviceType, pDescriptor->pDeviceID, openMode, &pPCM);
25366     if (result != MA_SUCCESS) {
25367         return result;
25368     }
25369
25370
25371     /* Hardware parameters. */
25372     pHWParams = (ma_snd_pcm_hw_params_t*)ma_calloc(((ma_snd_pcm_hw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_hw_params_sizeof)(), &pDevice->pContext->allocationCallbacks);
25373     if (pHWParams == NULL) {
25374         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25375         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for hardware parameters.");
25376         return MA_OUT_OF_MEMORY;
25377     }
25378
25379     resultALSA = ((ma_snd_pcm_hw_params_any_proc)pDevice->pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
25380     if (resultALSA < 0) {
25381         ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
25382         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25383         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.");
25384         return ma_result_from_errno(-resultALSA);
25385     }
25386
25387     /* MMAP Mode. Try using interleaved MMAP access. If this fails, fall back to standard readi/writei. */
25388     isUsingMMap = MA_FALSE;
25389 #if 0   /* NOTE: MMAP mode temporarily disabled. */
25390     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. */
25391         if (!pConfig->alsa.noMMap && ma_device__is_async(pDevice)) {
25392             if (((ma_snd_pcm_hw_params_set_access_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_MMAP_INTERLEAVED) == 0) {
25393                 pDevice->alsa.isUsingMMap = MA_TRUE;
25394             }
25395         }
25396     }
25397 #endif
25398
25399     if (!isUsingMMap) {
25400         resultALSA = ((ma_snd_pcm_hw_params_set_access_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_access)(pPCM, pHWParams, MA_SND_PCM_ACCESS_RW_INTERLEAVED);
25401         if (resultALSA < 0) {
25402             ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
25403             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25404             ma_log_post(ma_device_get_log(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.");
25405             return ma_result_from_errno(-resultALSA);
25406         }
25407     }
25408
25409     /*
25410     Most important properties first. The documentation for OSS (yes, I know this is ALSA!) recommends format, channels, then sample rate. I can't
25411     find any documentation for ALSA specifically, so I'm going to copy the recommendation for OSS.
25412     */
25413
25414     /* Format. */
25415     {
25416         /*
25417         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
25418         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.
25419         */
25420         if (formatALSA == MA_SND_PCM_FORMAT_UNKNOWN || ((ma_snd_pcm_hw_params_test_format_proc)pDevice->pContext->alsa.snd_pcm_hw_params_test_format)(pPCM, pHWParams, formatALSA) != 0) {
25421             /* We're either requesting the native format or the specified format is not supported. */
25422             size_t iFormat;
25423
25424             formatALSA = MA_SND_PCM_FORMAT_UNKNOWN;
25425             for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); ++iFormat) {
25426                 if (((ma_snd_pcm_hw_params_test_format_proc)pDevice->pContext->alsa.snd_pcm_hw_params_test_format)(pPCM, pHWParams, ma_convert_ma_format_to_alsa_format(g_maFormatPriorities[iFormat])) == 0) {
25427                     formatALSA = ma_convert_ma_format_to_alsa_format(g_maFormatPriorities[iFormat]);
25428                     break;
25429                 }
25430             }
25431
25432             if (formatALSA == MA_SND_PCM_FORMAT_UNKNOWN) {
25433                 ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
25434                 ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25435                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. The device does not support any miniaudio formats.");
25436                 return MA_FORMAT_NOT_SUPPORTED;
25437             }
25438         }
25439
25440         resultALSA = ((ma_snd_pcm_hw_params_set_format_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, formatALSA);
25441         if (resultALSA < 0) {
25442             ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
25443             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25444             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed.");
25445             return ma_result_from_errno(-resultALSA);
25446         }
25447
25448         internalFormat = ma_format_from_alsa(formatALSA);
25449         if (internalFormat == ma_format_unknown) {
25450             ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
25451             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25452             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] The chosen format is not supported by miniaudio.");
25453             return MA_FORMAT_NOT_SUPPORTED;
25454         }
25455     }
25456
25457     /* Channels. */
25458     {
25459         unsigned int channels = pDescriptor->channels;
25460         if (channels == 0) {
25461             channels = MA_DEFAULT_CHANNELS;
25462         }
25463
25464         resultALSA = ((ma_snd_pcm_hw_params_set_channels_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_channels_near)(pPCM, pHWParams, &channels);
25465         if (resultALSA < 0) {
25466             ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
25467             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25468             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed.");
25469             return ma_result_from_errno(-resultALSA);
25470         }
25471
25472         internalChannels = (ma_uint32)channels;
25473     }
25474
25475     /* Sample Rate */
25476     {
25477         unsigned int sampleRate;
25478
25479         /*
25480         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
25481         problems with some device configurations when used in conjunction with MMAP access mode. To fix this problem we need to disable
25482         resampling.
25483
25484         To reproduce this problem, open the "plug:dmix" device, and set the sample rate to 44100. Internally, it looks like dmix uses a
25485         sample rate of 48000. The hardware parameters will get set correctly with no errors, but it looks like the 44100 -> 48000 resampling
25486         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
25487         faster rate.
25488
25489         miniaudio has built-in support for sample rate conversion (albeit low quality at the moment), so disabling resampling should be fine
25490         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
25491         good quality until I get a chance to improve the quality of miniaudio's software sample rate conversion.
25492
25493         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
25494         this error with. In the future, we may want to restrict the disabling of resampling to only known bad plugins.
25495         */
25496         ((ma_snd_pcm_hw_params_set_rate_resample_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_rate_resample)(pPCM, pHWParams, 0);
25497
25498         sampleRate = pDescriptor->sampleRate;
25499         if (sampleRate == 0) {
25500             sampleRate = MA_DEFAULT_SAMPLE_RATE;
25501         }
25502
25503         resultALSA = ((ma_snd_pcm_hw_params_set_rate_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_rate_near)(pPCM, pHWParams, &sampleRate, 0);
25504         if (resultALSA < 0) {
25505             ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
25506             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25507             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed.");
25508             return ma_result_from_errno(-resultALSA);
25509         }
25510
25511         internalSampleRate = (ma_uint32)sampleRate;
25512     }
25513
25514     /* Periods. */
25515     {
25516         ma_uint32 periods = pDescriptor->periodCount;
25517
25518         resultALSA = ((ma_snd_pcm_hw_params_set_periods_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_periods_near)(pPCM, pHWParams, &periods, NULL);
25519         if (resultALSA < 0) {
25520             ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
25521             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25522             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed.");
25523             return ma_result_from_errno(-resultALSA);
25524         }
25525
25526         internalPeriods = periods;
25527     }
25528
25529     /* Buffer Size */
25530     {
25531         ma_snd_pcm_uframes_t actualBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, internalSampleRate, pConfig->performanceProfile) * internalPeriods;
25532
25533         resultALSA = ((ma_snd_pcm_hw_params_set_buffer_size_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_buffer_size_near)(pPCM, pHWParams, &actualBufferSizeInFrames);
25534         if (resultALSA < 0) {
25535             ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
25536             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25537             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed.");
25538             return ma_result_from_errno(-resultALSA);
25539         }
25540
25541         internalPeriodSizeInFrames = actualBufferSizeInFrames / internalPeriods;
25542     }
25543
25544     /* Apply hardware parameters. */
25545     resultALSA = ((ma_snd_pcm_hw_params_proc)pDevice->pContext->alsa.snd_pcm_hw_params)(pPCM, pHWParams);
25546     if (resultALSA < 0) {
25547         ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
25548         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25549         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed.");
25550         return ma_result_from_errno(-resultALSA);
25551     }
25552
25553     ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
25554     pHWParams = NULL;
25555
25556
25557     /* Software parameters. */
25558     pSWParams = (ma_snd_pcm_sw_params_t*)ma_calloc(((ma_snd_pcm_sw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_sw_params_sizeof)(), &pDevice->pContext->allocationCallbacks);
25559     if (pSWParams == NULL) {
25560         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25561         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for software parameters.");
25562         return MA_OUT_OF_MEMORY;
25563     }
25564
25565     resultALSA = ((ma_snd_pcm_sw_params_current_proc)pDevice->pContext->alsa.snd_pcm_sw_params_current)(pPCM, pSWParams);
25566     if (resultALSA < 0) {
25567         ma_free(pSWParams, &pDevice->pContext->allocationCallbacks);
25568         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25569         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed.");
25570         return ma_result_from_errno(-resultALSA);
25571     }
25572
25573     resultALSA = ((ma_snd_pcm_sw_params_set_avail_min_proc)pDevice->pContext->alsa.snd_pcm_sw_params_set_avail_min)(pPCM, pSWParams, ma_prev_power_of_2(internalPeriodSizeInFrames));
25574     if (resultALSA < 0) {
25575         ma_free(pSWParams, &pDevice->pContext->allocationCallbacks);
25576         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25577         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_sw_params_set_avail_min() failed.");
25578         return ma_result_from_errno(-resultALSA);
25579     }
25580
25581     resultALSA = ((ma_snd_pcm_sw_params_get_boundary_proc)pDevice->pContext->alsa.snd_pcm_sw_params_get_boundary)(pSWParams, &bufferBoundary);
25582     if (resultALSA < 0) {
25583         bufferBoundary = internalPeriodSizeInFrames * internalPeriods;
25584     }
25585
25586     if (deviceType == ma_device_type_playback && !isUsingMMap) {   /* Only playback devices in writei/readi mode need a start threshold. */
25587         /*
25588         Subtle detail here with the start threshold. When in playback-only mode (no full-duplex) we can set the start threshold to
25589         the size of a period. But for full-duplex we need to set it such that it is at least two periods.
25590         */
25591         resultALSA = ((ma_snd_pcm_sw_params_set_start_threshold_proc)pDevice->pContext->alsa.snd_pcm_sw_params_set_start_threshold)(pPCM, pSWParams, internalPeriodSizeInFrames*2);
25592         if (resultALSA < 0) {
25593             ma_free(pSWParams, &pDevice->pContext->allocationCallbacks);
25594             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25595             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.");
25596             return ma_result_from_errno(-resultALSA);
25597         }
25598
25599         resultALSA = ((ma_snd_pcm_sw_params_set_stop_threshold_proc)pDevice->pContext->alsa.snd_pcm_sw_params_set_stop_threshold)(pPCM, pSWParams, bufferBoundary);
25600         if (resultALSA < 0) { /* Set to boundary to loop instead of stop in the event of an xrun. */
25601             ma_free(pSWParams, &pDevice->pContext->allocationCallbacks);
25602             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25603             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set stop threshold for playback device. snd_pcm_sw_params_set_stop_threshold() failed.");
25604             return ma_result_from_errno(-resultALSA);
25605         }
25606     }
25607
25608     resultALSA = ((ma_snd_pcm_sw_params_proc)pDevice->pContext->alsa.snd_pcm_sw_params)(pPCM, pSWParams);
25609     if (resultALSA < 0) {
25610         ma_free(pSWParams, &pDevice->pContext->allocationCallbacks);
25611         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25612         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed.");
25613         return ma_result_from_errno(-resultALSA);
25614     }
25615
25616     ma_free(pSWParams, &pDevice->pContext->allocationCallbacks);
25617     pSWParams = NULL;
25618
25619
25620     /* 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. */
25621     {
25622         ma_snd_pcm_chmap_t* pChmap = ((ma_snd_pcm_get_chmap_proc)pDevice->pContext->alsa.snd_pcm_get_chmap)(pPCM);
25623         if (pChmap != NULL) {
25624             ma_uint32 iChannel;
25625
25626             /* 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(). */
25627             if (pChmap->channels >= internalChannels) {
25628                 /* Drop excess channels. */
25629                 for (iChannel = 0; iChannel < internalChannels; ++iChannel) {
25630                     internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]);
25631                 }
25632             } else {
25633                 ma_uint32 i;
25634
25635                 /*
25636                 Excess channels use defaults. Do an initial fill with defaults, overwrite the first pChmap->channels, validate to ensure there are no duplicate
25637                 channels. If validation fails, fall back to defaults.
25638                 */
25639                 ma_bool32 isValid = MA_TRUE;
25640
25641                 /* Fill with defaults. */
25642                 ma_channel_map_init_standard(ma_standard_channel_map_alsa, internalChannelMap, ma_countof(internalChannelMap), internalChannels);
25643
25644                 /* Overwrite first pChmap->channels channels. */
25645                 for (iChannel = 0; iChannel < pChmap->channels; ++iChannel) {
25646                     internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]);
25647                 }
25648
25649                 /* Validate. */
25650                 for (i = 0; i < internalChannels && isValid; ++i) {
25651                     ma_uint32 j;
25652                     for (j = i+1; j < internalChannels; ++j) {
25653                         if (internalChannelMap[i] == internalChannelMap[j]) {
25654                             isValid = MA_FALSE;
25655                             break;
25656                         }
25657                     }
25658                 }
25659
25660                 /* If our channel map is invalid, fall back to defaults. */
25661                 if (!isValid) {
25662                     ma_channel_map_init_standard(ma_standard_channel_map_alsa, internalChannelMap, ma_countof(internalChannelMap), internalChannels);
25663                 }
25664             }
25665
25666             free(pChmap);
25667             pChmap = NULL;
25668         } else {
25669             /* Could not retrieve the channel map. Fall back to a hard-coded assumption. */
25670             ma_channel_map_init_standard(ma_standard_channel_map_alsa, internalChannelMap, ma_countof(internalChannelMap), internalChannels);
25671         }
25672     }
25673
25674
25675     /*
25676     We need to retrieve the poll descriptors so we can use poll() to wait for data to become
25677     available for reading or writing. There's no well defined maximum for this so we're just going
25678     to allocate this on the heap.
25679     */
25680     pollDescriptorCount = ((ma_snd_pcm_poll_descriptors_count_proc)pDevice->pContext->alsa.snd_pcm_poll_descriptors_count)(pPCM);
25681     if (pollDescriptorCount <= 0) {
25682         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25683         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to retrieve poll descriptors count.");
25684         return MA_ERROR;
25685     }
25686
25687     pPollDescriptors = (struct pollfd*)ma_malloc(sizeof(*pPollDescriptors) * (pollDescriptorCount + 1), &pDevice->pContext->allocationCallbacks);   /* +1 because we want room for the wakeup descriptor. */
25688     if (pPollDescriptors == NULL) {
25689         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25690         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to allocate memory for poll descriptors.");
25691         return MA_OUT_OF_MEMORY;
25692     }
25693
25694     /*
25695     We need an eventfd to wakeup from poll() and avoid a deadlock in situations where the driver
25696     never returns from writei() and readi(). This has been observed with the "pulse" device.
25697     */
25698     wakeupfd = eventfd(0, 0);
25699     if (wakeupfd < 0) {
25700         ma_free(pPollDescriptors, &pDevice->pContext->allocationCallbacks);
25701         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25702         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to create eventfd for poll wakeup.");
25703         return ma_result_from_errno(errno);
25704     }
25705
25706     /* We'll place the wakeup fd at the start of the buffer. */
25707     pPollDescriptors[0].fd      = wakeupfd;
25708     pPollDescriptors[0].events  = POLLIN;    /* We only care about waiting to read from the wakeup file descriptor. */
25709     pPollDescriptors[0].revents = 0;
25710
25711     /* We can now extract the PCM poll descriptors which we place after the wakeup descriptor. */
25712     pollDescriptorCount = ((ma_snd_pcm_poll_descriptors_proc)pDevice->pContext->alsa.snd_pcm_poll_descriptors)(pPCM, pPollDescriptors + 1, pollDescriptorCount);    /* +1 because we want to place these descriptors after the wakeup descriptor. */
25713     if (pollDescriptorCount <= 0) {
25714         close(wakeupfd);
25715         ma_free(pPollDescriptors, &pDevice->pContext->allocationCallbacks);
25716         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25717         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to retrieve poll descriptors.");
25718         return MA_ERROR;
25719     }
25720
25721     if (deviceType == ma_device_type_capture) {
25722         pDevice->alsa.pollDescriptorCountCapture = pollDescriptorCount;
25723         pDevice->alsa.pPollDescriptorsCapture = pPollDescriptors;
25724         pDevice->alsa.wakeupfdCapture = wakeupfd;
25725     } else {
25726         pDevice->alsa.pollDescriptorCountPlayback = pollDescriptorCount;
25727         pDevice->alsa.pPollDescriptorsPlayback = pPollDescriptors;
25728         pDevice->alsa.wakeupfdPlayback = wakeupfd;
25729     }
25730
25731
25732     /* We're done. Prepare the device. */
25733     resultALSA = ((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)(pPCM);
25734     if (resultALSA < 0) {
25735         close(wakeupfd);
25736         ma_free(pPollDescriptors, &pDevice->pContext->allocationCallbacks);
25737         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
25738         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to prepare device.");
25739         return ma_result_from_errno(-resultALSA);
25740     }
25741
25742
25743     if (deviceType == ma_device_type_capture) {
25744         pDevice->alsa.pPCMCapture         = (ma_ptr)pPCM;
25745         pDevice->alsa.isUsingMMapCapture  = isUsingMMap;
25746     } else {
25747         pDevice->alsa.pPCMPlayback        = (ma_ptr)pPCM;
25748         pDevice->alsa.isUsingMMapPlayback = isUsingMMap;
25749     }
25750
25751     pDescriptor->format             = internalFormat;
25752     pDescriptor->channels           = internalChannels;
25753     pDescriptor->sampleRate         = internalSampleRate;
25754     ma_channel_map_copy(pDescriptor->channelMap, internalChannelMap, ma_min(internalChannels, MA_MAX_CHANNELS));
25755     pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames;
25756     pDescriptor->periodCount        = internalPeriods;
25757
25758     return MA_SUCCESS;
25759 }
25760
25761 static ma_result ma_device_init__alsa(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
25762 {
25763     MA_ASSERT(pDevice != NULL);
25764
25765     MA_ZERO_OBJECT(&pDevice->alsa);
25766
25767     if (pConfig->deviceType == ma_device_type_loopback) {
25768         return MA_DEVICE_TYPE_NOT_SUPPORTED;
25769     }
25770
25771     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
25772         ma_result result = ma_device_init_by_type__alsa(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
25773         if (result != MA_SUCCESS) {
25774             return result;
25775         }
25776     }
25777
25778     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
25779         ma_result result = ma_device_init_by_type__alsa(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
25780         if (result != MA_SUCCESS) {
25781             return result;
25782         }
25783     }
25784
25785     return MA_SUCCESS;
25786 }
25787
25788 static ma_result ma_device_start__alsa(ma_device* pDevice)
25789 {
25790     int resultALSA;
25791
25792     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
25793         resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
25794         if (resultALSA < 0) {
25795             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start capture device.");
25796             return ma_result_from_errno(-resultALSA);
25797         }
25798     }
25799
25800     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
25801         /* Don't need to do anything for playback because it'll be started automatically when enough data has been written. */
25802     }
25803
25804     return MA_SUCCESS;
25805 }
25806
25807 static ma_result ma_device_stop__alsa(ma_device* pDevice)
25808 {
25809     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
25810         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device... ");
25811         ((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
25812         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n");
25813
25814         /* We need to prepare the device again, otherwise we won't be able to restart the device. */
25815         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device... ");
25816         if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) < 0) {
25817             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed\n");
25818         } else {
25819             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n");
25820         }
25821     }
25822
25823     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
25824         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping playback device... ");
25825         ((ma_snd_pcm_drop_proc)pDevice->pContext->alsa.snd_pcm_drop)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
25826         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n");
25827
25828         /* We need to prepare the device again, otherwise we won't be able to restart the device. */
25829         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing playback device... ");
25830         if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) < 0) {
25831             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed\n");
25832         } else {
25833             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n");
25834         }
25835     }
25836
25837     return MA_SUCCESS;
25838 }
25839
25840 static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, struct pollfd* pPollDescriptors, int pollDescriptorCount, short requiredEvent)
25841 {
25842     for (;;) {
25843         unsigned short revents;
25844         int resultALSA;
25845         int resultPoll = poll(pPollDescriptors, pollDescriptorCount, -1);
25846         if (resultPoll < 0) {
25847             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] poll() failed.");
25848             return ma_result_from_errno(errno);
25849         }
25850
25851         /*
25852         Before checking the ALSA poll descriptor flag we need to check if the wakeup descriptor
25853         has had it's POLLIN flag set. If so, we need to actually read the data and then exit
25854         function. The wakeup descriptor will be the first item in the descriptors buffer.
25855         */
25856         if ((pPollDescriptors[0].revents & POLLIN) != 0) {
25857             ma_uint64 t;
25858             int resultRead = read(pPollDescriptors[0].fd, &t, sizeof(t));    /* <-- Important that we read here so that the next write() does not block. */
25859             if (resultRead < 0) {
25860                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] read() failed.");
25861                 return ma_result_from_errno(errno);
25862             }
25863
25864             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] POLLIN set for wakeupfd\n");
25865             return MA_DEVICE_NOT_STARTED;
25866         }
25867
25868         /*
25869         Getting here means that some data should be able to be read. We need to use ALSA to
25870         translate the revents flags for us.
25871         */
25872         resultALSA = ((ma_snd_pcm_poll_descriptors_revents_proc)pDevice->pContext->alsa.snd_pcm_poll_descriptors_revents)(pPCM, pPollDescriptors + 1, pollDescriptorCount - 1, &revents);   /* +1, -1 to ignore the wakeup descriptor. */
25873         if (resultALSA < 0) {
25874             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_poll_descriptors_revents() failed.");
25875             return ma_result_from_errno(-resultALSA);
25876         }
25877
25878         if ((revents & POLLERR) != 0) {
25879             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] POLLERR detected.");
25880             return ma_result_from_errno(errno);
25881         }
25882
25883         if ((revents & requiredEvent) == requiredEvent) {
25884             break;  /* We're done. Data available for reading or writing. */
25885         }
25886     }
25887
25888     return MA_SUCCESS;
25889 }
25890
25891 static ma_result ma_device_wait_read__alsa(ma_device* pDevice)
25892 {
25893     return ma_device_wait__alsa(pDevice, (ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, (struct pollfd*)pDevice->alsa.pPollDescriptorsCapture, pDevice->alsa.pollDescriptorCountCapture + 1, POLLIN); /* +1 to account for the wakeup descriptor. */
25894 }
25895
25896 static ma_result ma_device_wait_write__alsa(ma_device* pDevice)
25897 {
25898     return ma_device_wait__alsa(pDevice, (ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, (struct pollfd*)pDevice->alsa.pPollDescriptorsPlayback, pDevice->alsa.pollDescriptorCountPlayback + 1, POLLOUT); /* +1 to account for the wakeup descriptor. */
25899 }
25900
25901 static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead)
25902 {
25903     ma_snd_pcm_sframes_t resultALSA = 0;
25904
25905     MA_ASSERT(pDevice != NULL);
25906     MA_ASSERT(pFramesOut != NULL);
25907
25908     if (pFramesRead != NULL) {
25909         *pFramesRead = 0;
25910     }
25911
25912     while (ma_device_get_state(pDevice) == ma_device_state_started) {
25913         ma_result result;
25914
25915         /* The first thing to do is wait for data to become available for reading. This will return an error code if the device has been stopped. */
25916         result = ma_device_wait_read__alsa(pDevice);
25917         if (result != MA_SUCCESS) {
25918             return result;
25919         }
25920
25921         /* Getting here means we should have data available. */
25922         resultALSA = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, pFramesOut, frameCount);
25923         if (resultALSA >= 0) {
25924             break;  /* Success. */
25925         } else {
25926             if (resultALSA == -EAGAIN) {
25927                 /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EGAIN (read)\n");*/
25928                 continue;   /* Try again. */
25929             } else if (resultALSA == -EPIPE) {
25930                 ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (read)\n");
25931
25932                 /* Overrun. Recover and try again. If this fails we need to return an error. */
25933                 resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, resultALSA, MA_TRUE);
25934                 if (resultALSA < 0) {
25935                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after overrun.");
25936                     return ma_result_from_errno((int)-resultALSA);
25937                 }
25938
25939                 resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
25940                 if (resultALSA < 0) {
25941                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.");
25942                     return ma_result_from_errno((int)-resultALSA);
25943                 }
25944
25945                 continue;   /* Try reading again. */
25946             }
25947         }
25948     }
25949
25950     if (pFramesRead != NULL) {
25951         *pFramesRead = resultALSA;
25952     }
25953
25954     return MA_SUCCESS;
25955 }
25956
25957 static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
25958 {
25959     ma_snd_pcm_sframes_t resultALSA = 0;
25960
25961     MA_ASSERT(pDevice != NULL);
25962     MA_ASSERT(pFrames != NULL);
25963
25964     if (pFramesWritten != NULL) {
25965         *pFramesWritten = 0;
25966     }
25967
25968     while (ma_device_get_state(pDevice) == ma_device_state_started) {
25969         ma_result result;
25970
25971         /* The first thing to do is wait for space to become available for writing. This will return an error code if the device has been stopped. */
25972         result = ma_device_wait_write__alsa(pDevice);
25973         if (result != MA_SUCCESS) {
25974             return result;
25975         }
25976
25977         resultALSA = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, pFrames, frameCount);
25978         if (resultALSA >= 0) {
25979             break;  /* Success. */
25980         } else {
25981             if (resultALSA == -EAGAIN) {
25982                 /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EGAIN (write)\n");*/
25983                 continue;   /* Try again. */
25984             } else if (resultALSA == -EPIPE) {
25985                 ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "EPIPE (write)\n");
25986
25987                 /* Underrun. Recover and try again. If this fails we need to return an error. */
25988                 resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, resultALSA, MA_TRUE);    /* MA_TRUE=silent (don't print anything on error). */
25989                 if (resultALSA < 0) {
25990                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after underrun.");
25991                     return ma_result_from_errno((int)-resultALSA);
25992                 }
25993
25994                 /*
25995                 In my testing I have had a situation where writei() does not automatically restart the device even though I've set it
25996                 up as such in the software parameters. What will happen is writei() will block indefinitely even though the number of
25997                 frames is well beyond the auto-start threshold. To work around this I've needed to add an explicit start here. Not sure
25998                 if this is me just being stupid and not recovering the device properly, but this definitely feels like something isn't
25999                 quite right here.
26000                 */
26001                 resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
26002                 if (resultALSA < 0) {
26003                     ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.");
26004                     return ma_result_from_errno((int)-resultALSA);
26005                 }
26006
26007                 continue;   /* Try writing again. */
26008             }
26009         }
26010     }
26011
26012     if (pFramesWritten != NULL) {
26013         *pFramesWritten = resultALSA;
26014     }
26015
26016     return MA_SUCCESS;
26017 }
26018
26019 static ma_result ma_device_data_loop_wakeup__alsa(ma_device* pDevice)
26020 {
26021     ma_uint64 t = 1;
26022     int resultWrite = 0;
26023
26024     MA_ASSERT(pDevice != NULL);
26025
26026     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Waking up... ");
26027
26028     /* Write to an eventfd to trigger a wakeup from poll() and abort any reading or writing. */
26029     if (pDevice->alsa.pPollDescriptorsCapture != NULL) {
26030         resultWrite = write(pDevice->alsa.wakeupfdCapture, &t, sizeof(t));
26031     }
26032     if (pDevice->alsa.pPollDescriptorsPlayback != NULL) {
26033         resultWrite = write(pDevice->alsa.wakeupfdPlayback, &t, sizeof(t));
26034     }
26035
26036     if (resultWrite < 0) {
26037         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] write() failed.");
26038         return ma_result_from_errno(errno);
26039     }
26040
26041     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Done\n");
26042
26043     return MA_SUCCESS;
26044 }
26045
26046 static ma_result ma_context_uninit__alsa(ma_context* pContext)
26047 {
26048     MA_ASSERT(pContext != NULL);
26049     MA_ASSERT(pContext->backend == ma_backend_alsa);
26050
26051     /* Clean up memory for memory leak checkers. */
26052     ((ma_snd_config_update_free_global_proc)pContext->alsa.snd_config_update_free_global)();
26053
26054 #ifndef MA_NO_RUNTIME_LINKING
26055     ma_dlclose(pContext, pContext->alsa.asoundSO);
26056 #endif
26057
26058     ma_mutex_uninit(&pContext->alsa.internalDeviceEnumLock);
26059
26060     return MA_SUCCESS;
26061 }
26062
26063 static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
26064 {
26065     ma_result result;
26066 #ifndef MA_NO_RUNTIME_LINKING
26067     const char* libasoundNames[] = {
26068         "libasound.so.2",
26069         "libasound.so"
26070     };
26071     size_t i;
26072
26073     for (i = 0; i < ma_countof(libasoundNames); ++i) {
26074         pContext->alsa.asoundSO = ma_dlopen(pContext, libasoundNames[i]);
26075         if (pContext->alsa.asoundSO != NULL) {
26076             break;
26077         }
26078     }
26079
26080     if (pContext->alsa.asoundSO == NULL) {
26081         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[ALSA] Failed to open shared object.\n");
26082         return MA_NO_BACKEND;
26083     }
26084
26085     pContext->alsa.snd_pcm_open                           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_open");
26086     pContext->alsa.snd_pcm_close                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_close");
26087     pContext->alsa.snd_pcm_hw_params_sizeof               = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_sizeof");
26088     pContext->alsa.snd_pcm_hw_params_any                  = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_any");
26089     pContext->alsa.snd_pcm_hw_params_set_format           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format");
26090     pContext->alsa.snd_pcm_hw_params_set_format_first     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format_first");
26091     pContext->alsa.snd_pcm_hw_params_get_format_mask      = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format_mask");
26092     pContext->alsa.snd_pcm_hw_params_set_channels         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels");
26093     pContext->alsa.snd_pcm_hw_params_set_channels_near    = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_near");
26094     pContext->alsa.snd_pcm_hw_params_set_channels_minmax  = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_minmax");
26095     pContext->alsa.snd_pcm_hw_params_set_rate_resample    = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_resample");
26096     pContext->alsa.snd_pcm_hw_params_set_rate             = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate");
26097     pContext->alsa.snd_pcm_hw_params_set_rate_near        = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_near");
26098     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");
26099     pContext->alsa.snd_pcm_hw_params_set_periods_near     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_periods_near");
26100     pContext->alsa.snd_pcm_hw_params_set_access           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_access");
26101     pContext->alsa.snd_pcm_hw_params_get_format           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format");
26102     pContext->alsa.snd_pcm_hw_params_get_channels         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels");
26103     pContext->alsa.snd_pcm_hw_params_get_channels_min     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_min");
26104     pContext->alsa.snd_pcm_hw_params_get_channels_max     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_max");
26105     pContext->alsa.snd_pcm_hw_params_get_rate             = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate");
26106     pContext->alsa.snd_pcm_hw_params_get_rate_min         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_min");
26107     pContext->alsa.snd_pcm_hw_params_get_rate_max         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_max");
26108     pContext->alsa.snd_pcm_hw_params_get_buffer_size      = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_buffer_size");
26109     pContext->alsa.snd_pcm_hw_params_get_periods          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_periods");
26110     pContext->alsa.snd_pcm_hw_params_get_access           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_access");
26111     pContext->alsa.snd_pcm_hw_params_test_format          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_test_format");
26112     pContext->alsa.snd_pcm_hw_params_test_channels        = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_test_channels");
26113     pContext->alsa.snd_pcm_hw_params_test_rate            = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_test_rate");
26114     pContext->alsa.snd_pcm_hw_params                      = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params");
26115     pContext->alsa.snd_pcm_sw_params_sizeof               = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_sizeof");
26116     pContext->alsa.snd_pcm_sw_params_current              = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_current");
26117     pContext->alsa.snd_pcm_sw_params_get_boundary         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_get_boundary");
26118     pContext->alsa.snd_pcm_sw_params_set_avail_min        = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_avail_min");
26119     pContext->alsa.snd_pcm_sw_params_set_start_threshold  = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_start_threshold");
26120     pContext->alsa.snd_pcm_sw_params_set_stop_threshold   = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_stop_threshold");
26121     pContext->alsa.snd_pcm_sw_params                      = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params");
26122     pContext->alsa.snd_pcm_format_mask_sizeof             = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_sizeof");
26123     pContext->alsa.snd_pcm_format_mask_test               = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_test");
26124     pContext->alsa.snd_pcm_get_chmap                      = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_get_chmap");
26125     pContext->alsa.snd_pcm_state                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_state");
26126     pContext->alsa.snd_pcm_prepare                        = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_prepare");
26127     pContext->alsa.snd_pcm_start                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_start");
26128     pContext->alsa.snd_pcm_drop                           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drop");
26129     pContext->alsa.snd_pcm_drain                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drain");
26130     pContext->alsa.snd_pcm_reset                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_reset");
26131     pContext->alsa.snd_device_name_hint                   = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_hint");
26132     pContext->alsa.snd_device_name_get_hint               = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_get_hint");
26133     pContext->alsa.snd_card_get_index                     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_card_get_index");
26134     pContext->alsa.snd_device_name_free_hint              = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_free_hint");
26135     pContext->alsa.snd_pcm_mmap_begin                     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_begin");
26136     pContext->alsa.snd_pcm_mmap_commit                    = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_commit");
26137     pContext->alsa.snd_pcm_recover                        = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_recover");
26138     pContext->alsa.snd_pcm_readi                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_readi");
26139     pContext->alsa.snd_pcm_writei                         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_writei");
26140     pContext->alsa.snd_pcm_avail                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail");
26141     pContext->alsa.snd_pcm_avail_update                   = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail_update");
26142     pContext->alsa.snd_pcm_wait                           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_wait");
26143     pContext->alsa.snd_pcm_nonblock                       = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_nonblock");
26144     pContext->alsa.snd_pcm_info                           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info");
26145     pContext->alsa.snd_pcm_info_sizeof                    = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_sizeof");
26146     pContext->alsa.snd_pcm_info_get_name                  = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_get_name");
26147     pContext->alsa.snd_pcm_poll_descriptors               = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_poll_descriptors");
26148     pContext->alsa.snd_pcm_poll_descriptors_count         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_poll_descriptors_count");
26149     pContext->alsa.snd_pcm_poll_descriptors_revents       = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_poll_descriptors_revents");
26150     pContext->alsa.snd_config_update_free_global          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_config_update_free_global");
26151 #else
26152     /* The system below is just for type safety. */
26153     ma_snd_pcm_open_proc                           _snd_pcm_open                           = snd_pcm_open;
26154     ma_snd_pcm_close_proc                          _snd_pcm_close                          = snd_pcm_close;
26155     ma_snd_pcm_hw_params_sizeof_proc               _snd_pcm_hw_params_sizeof               = snd_pcm_hw_params_sizeof;
26156     ma_snd_pcm_hw_params_any_proc                  _snd_pcm_hw_params_any                  = snd_pcm_hw_params_any;
26157     ma_snd_pcm_hw_params_set_format_proc           _snd_pcm_hw_params_set_format           = snd_pcm_hw_params_set_format;
26158     ma_snd_pcm_hw_params_set_format_first_proc     _snd_pcm_hw_params_set_format_first     = snd_pcm_hw_params_set_format_first;
26159     ma_snd_pcm_hw_params_get_format_mask_proc      _snd_pcm_hw_params_get_format_mask      = snd_pcm_hw_params_get_format_mask;
26160     ma_snd_pcm_hw_params_set_channels_proc         _snd_pcm_hw_params_set_channels         = snd_pcm_hw_params_set_channels;
26161     ma_snd_pcm_hw_params_set_channels_near_proc    _snd_pcm_hw_params_set_channels_near    = snd_pcm_hw_params_set_channels_near;
26162     ma_snd_pcm_hw_params_set_rate_resample_proc    _snd_pcm_hw_params_set_rate_resample    = snd_pcm_hw_params_set_rate_resample;
26163     ma_snd_pcm_hw_params_set_rate_near             _snd_pcm_hw_params_set_rate             = snd_pcm_hw_params_set_rate;
26164     ma_snd_pcm_hw_params_set_rate_near_proc        _snd_pcm_hw_params_set_rate_near        = snd_pcm_hw_params_set_rate_near;
26165     ma_snd_pcm_hw_params_set_rate_minmax_proc      _snd_pcm_hw_params_set_rate_minmax      = snd_pcm_hw_params_set_rate_minmax;
26166     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;
26167     ma_snd_pcm_hw_params_set_periods_near_proc     _snd_pcm_hw_params_set_periods_near     = snd_pcm_hw_params_set_periods_near;
26168     ma_snd_pcm_hw_params_set_access_proc           _snd_pcm_hw_params_set_access           = snd_pcm_hw_params_set_access;
26169     ma_snd_pcm_hw_params_get_format_proc           _snd_pcm_hw_params_get_format           = snd_pcm_hw_params_get_format;
26170     ma_snd_pcm_hw_params_get_channels_proc         _snd_pcm_hw_params_get_channels         = snd_pcm_hw_params_get_channels;
26171     ma_snd_pcm_hw_params_get_channels_min_proc     _snd_pcm_hw_params_get_channels_min     = snd_pcm_hw_params_get_channels_min;
26172     ma_snd_pcm_hw_params_get_channels_max_proc     _snd_pcm_hw_params_get_channels_max     = snd_pcm_hw_params_get_channels_max;
26173     ma_snd_pcm_hw_params_get_rate_proc             _snd_pcm_hw_params_get_rate             = snd_pcm_hw_params_get_rate;
26174     ma_snd_pcm_hw_params_get_rate_min_proc         _snd_pcm_hw_params_get_rate_min         = snd_pcm_hw_params_get_rate_min;
26175     ma_snd_pcm_hw_params_get_rate_max_proc         _snd_pcm_hw_params_get_rate_max         = snd_pcm_hw_params_get_rate_max;
26176     ma_snd_pcm_hw_params_get_buffer_size_proc      _snd_pcm_hw_params_get_buffer_size      = snd_pcm_hw_params_get_buffer_size;
26177     ma_snd_pcm_hw_params_get_periods_proc          _snd_pcm_hw_params_get_periods          = snd_pcm_hw_params_get_periods;
26178     ma_snd_pcm_hw_params_get_access_proc           _snd_pcm_hw_params_get_access           = snd_pcm_hw_params_get_access;
26179     ma_snd_pcm_hw_params_test_format_proc          _snd_pcm_hw_params_test_format          = snd_pcm_hw_params_test_format;
26180     ma_snd_pcm_hw_params_test_channels_proc        _snd_pcm_hw_params_test_channels        = snd_pcm_hw_params_test_channels;
26181     ma_snd_pcm_hw_params_test_rate_proc            _snd_pcm_hw_params_test_rate            = snd_pcm_hw_params_test_rate;
26182     ma_snd_pcm_hw_params_proc                      _snd_pcm_hw_params                      = snd_pcm_hw_params;
26183     ma_snd_pcm_sw_params_sizeof_proc               _snd_pcm_sw_params_sizeof               = snd_pcm_sw_params_sizeof;
26184     ma_snd_pcm_sw_params_current_proc              _snd_pcm_sw_params_current              = snd_pcm_sw_params_current;
26185     ma_snd_pcm_sw_params_get_boundary_proc         _snd_pcm_sw_params_get_boundary         = snd_pcm_sw_params_get_boundary;
26186     ma_snd_pcm_sw_params_set_avail_min_proc        _snd_pcm_sw_params_set_avail_min        = snd_pcm_sw_params_set_avail_min;
26187     ma_snd_pcm_sw_params_set_start_threshold_proc  _snd_pcm_sw_params_set_start_threshold  = snd_pcm_sw_params_set_start_threshold;
26188     ma_snd_pcm_sw_params_set_stop_threshold_proc   _snd_pcm_sw_params_set_stop_threshold   = snd_pcm_sw_params_set_stop_threshold;
26189     ma_snd_pcm_sw_params_proc                      _snd_pcm_sw_params                      = snd_pcm_sw_params;
26190     ma_snd_pcm_format_mask_sizeof_proc             _snd_pcm_format_mask_sizeof             = snd_pcm_format_mask_sizeof;
26191     ma_snd_pcm_format_mask_test_proc               _snd_pcm_format_mask_test               = snd_pcm_format_mask_test;
26192     ma_snd_pcm_get_chmap_proc                      _snd_pcm_get_chmap                      = snd_pcm_get_chmap;
26193     ma_snd_pcm_state_proc                          _snd_pcm_state                          = snd_pcm_state;
26194     ma_snd_pcm_prepare_proc                        _snd_pcm_prepare                        = snd_pcm_prepare;
26195     ma_snd_pcm_start_proc                          _snd_pcm_start                          = snd_pcm_start;
26196     ma_snd_pcm_drop_proc                           _snd_pcm_drop                           = snd_pcm_drop;
26197     ma_snd_pcm_drain_proc                          _snd_pcm_drain                          = snd_pcm_drain;
26198     ma_snd_pcm_reset_proc                          _snd_pcm_reset                          = snd_pcm_reset;
26199     ma_snd_device_name_hint_proc                   _snd_device_name_hint                   = snd_device_name_hint;
26200     ma_snd_device_name_get_hint_proc               _snd_device_name_get_hint               = snd_device_name_get_hint;
26201     ma_snd_card_get_index_proc                     _snd_card_get_index                     = snd_card_get_index;
26202     ma_snd_device_name_free_hint_proc              _snd_device_name_free_hint              = snd_device_name_free_hint;
26203     ma_snd_pcm_mmap_begin_proc                     _snd_pcm_mmap_begin                     = snd_pcm_mmap_begin;
26204     ma_snd_pcm_mmap_commit_proc                    _snd_pcm_mmap_commit                    = snd_pcm_mmap_commit;
26205     ma_snd_pcm_recover_proc                        _snd_pcm_recover                        = snd_pcm_recover;
26206     ma_snd_pcm_readi_proc                          _snd_pcm_readi                          = snd_pcm_readi;
26207     ma_snd_pcm_writei_proc                         _snd_pcm_writei                         = snd_pcm_writei;
26208     ma_snd_pcm_avail_proc                          _snd_pcm_avail                          = snd_pcm_avail;
26209     ma_snd_pcm_avail_update_proc                   _snd_pcm_avail_update                   = snd_pcm_avail_update;
26210     ma_snd_pcm_wait_proc                           _snd_pcm_wait                           = snd_pcm_wait;
26211     ma_snd_pcm_nonblock_proc                       _snd_pcm_nonblock                       = snd_pcm_nonblock;
26212     ma_snd_pcm_info_proc                           _snd_pcm_info                           = snd_pcm_info;
26213     ma_snd_pcm_info_sizeof_proc                    _snd_pcm_info_sizeof                    = snd_pcm_info_sizeof;
26214     ma_snd_pcm_info_get_name_proc                  _snd_pcm_info_get_name                  = snd_pcm_info_get_name;
26215     ma_snd_pcm_poll_descriptors                    _snd_pcm_poll_descriptors               = snd_pcm_poll_descriptors;
26216     ma_snd_pcm_poll_descriptors_count              _snd_pcm_poll_descriptors_count         = snd_pcm_poll_descriptors_count;
26217     ma_snd_pcm_poll_descriptors_revents            _snd_pcm_poll_descriptors_revents       = snd_pcm_poll_descriptors_revents;
26218     ma_snd_config_update_free_global_proc          _snd_config_update_free_global          = snd_config_update_free_global;
26219
26220     pContext->alsa.snd_pcm_open                           = (ma_proc)_snd_pcm_open;
26221     pContext->alsa.snd_pcm_close                          = (ma_proc)_snd_pcm_close;
26222     pContext->alsa.snd_pcm_hw_params_sizeof               = (ma_proc)_snd_pcm_hw_params_sizeof;
26223     pContext->alsa.snd_pcm_hw_params_any                  = (ma_proc)_snd_pcm_hw_params_any;
26224     pContext->alsa.snd_pcm_hw_params_set_format           = (ma_proc)_snd_pcm_hw_params_set_format;
26225     pContext->alsa.snd_pcm_hw_params_set_format_first     = (ma_proc)_snd_pcm_hw_params_set_format_first;
26226     pContext->alsa.snd_pcm_hw_params_get_format_mask      = (ma_proc)_snd_pcm_hw_params_get_format_mask;
26227     pContext->alsa.snd_pcm_hw_params_set_channels         = (ma_proc)_snd_pcm_hw_params_set_channels;
26228     pContext->alsa.snd_pcm_hw_params_set_channels_near    = (ma_proc)_snd_pcm_hw_params_set_channels_near;
26229     pContext->alsa.snd_pcm_hw_params_set_channels_minmax  = (ma_proc)_snd_pcm_hw_params_set_channels_minmax;
26230     pContext->alsa.snd_pcm_hw_params_set_rate_resample    = (ma_proc)_snd_pcm_hw_params_set_rate_resample;
26231     pContext->alsa.snd_pcm_hw_params_set_rate             = (ma_proc)_snd_pcm_hw_params_set_rate;
26232     pContext->alsa.snd_pcm_hw_params_set_rate_near        = (ma_proc)_snd_pcm_hw_params_set_rate_near;
26233     pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)_snd_pcm_hw_params_set_buffer_size_near;
26234     pContext->alsa.snd_pcm_hw_params_set_periods_near     = (ma_proc)_snd_pcm_hw_params_set_periods_near;
26235     pContext->alsa.snd_pcm_hw_params_set_access           = (ma_proc)_snd_pcm_hw_params_set_access;
26236     pContext->alsa.snd_pcm_hw_params_get_format           = (ma_proc)_snd_pcm_hw_params_get_format;
26237     pContext->alsa.snd_pcm_hw_params_get_channels         = (ma_proc)_snd_pcm_hw_params_get_channels;
26238     pContext->alsa.snd_pcm_hw_params_get_channels_min     = (ma_proc)_snd_pcm_hw_params_get_channels_min;
26239     pContext->alsa.snd_pcm_hw_params_get_channels_max     = (ma_proc)_snd_pcm_hw_params_get_channels_max;
26240     pContext->alsa.snd_pcm_hw_params_get_rate             = (ma_proc)_snd_pcm_hw_params_get_rate;
26241     pContext->alsa.snd_pcm_hw_params_get_rate_min         = (ma_proc)_snd_pcm_hw_params_get_rate_min;
26242     pContext->alsa.snd_pcm_hw_params_get_rate_max         = (ma_proc)_snd_pcm_hw_params_get_rate_max;
26243     pContext->alsa.snd_pcm_hw_params_get_buffer_size      = (ma_proc)_snd_pcm_hw_params_get_buffer_size;
26244     pContext->alsa.snd_pcm_hw_params_get_periods          = (ma_proc)_snd_pcm_hw_params_get_periods;
26245     pContext->alsa.snd_pcm_hw_params_get_access           = (ma_proc)_snd_pcm_hw_params_get_access;
26246     pContext->alsa.snd_pcm_hw_params_test_format          = (ma_proc)_snd_pcm_hw_params_test_format;
26247     pContext->alsa.snd_pcm_hw_params_test_channels        = (ma_proc)_snd_pcm_hw_params_test_channels;
26248     pContext->alsa.snd_pcm_hw_params_test_rate            = (ma_proc)_snd_pcm_hw_params_test_rate;
26249     pContext->alsa.snd_pcm_hw_params                      = (ma_proc)_snd_pcm_hw_params;
26250     pContext->alsa.snd_pcm_sw_params_sizeof               = (ma_proc)_snd_pcm_sw_params_sizeof;
26251     pContext->alsa.snd_pcm_sw_params_current              = (ma_proc)_snd_pcm_sw_params_current;
26252     pContext->alsa.snd_pcm_sw_params_get_boundary         = (ma_proc)_snd_pcm_sw_params_get_boundary;
26253     pContext->alsa.snd_pcm_sw_params_set_avail_min        = (ma_proc)_snd_pcm_sw_params_set_avail_min;
26254     pContext->alsa.snd_pcm_sw_params_set_start_threshold  = (ma_proc)_snd_pcm_sw_params_set_start_threshold;
26255     pContext->alsa.snd_pcm_sw_params_set_stop_threshold   = (ma_proc)_snd_pcm_sw_params_set_stop_threshold;
26256     pContext->alsa.snd_pcm_sw_params                      = (ma_proc)_snd_pcm_sw_params;
26257     pContext->alsa.snd_pcm_format_mask_sizeof             = (ma_proc)_snd_pcm_format_mask_sizeof;
26258     pContext->alsa.snd_pcm_format_mask_test               = (ma_proc)_snd_pcm_format_mask_test;
26259     pContext->alsa.snd_pcm_get_chmap                      = (ma_proc)_snd_pcm_get_chmap;
26260     pContext->alsa.snd_pcm_state                          = (ma_proc)_snd_pcm_state;
26261     pContext->alsa.snd_pcm_prepare                        = (ma_proc)_snd_pcm_prepare;
26262     pContext->alsa.snd_pcm_start                          = (ma_proc)_snd_pcm_start;
26263     pContext->alsa.snd_pcm_drop                           = (ma_proc)_snd_pcm_drop;
26264     pContext->alsa.snd_pcm_drain                          = (ma_proc)_snd_pcm_drain;
26265     pContext->alsa.snd_pcm_reset                          = (ma_proc)_snd_pcm_reset;
26266     pContext->alsa.snd_device_name_hint                   = (ma_proc)_snd_device_name_hint;
26267     pContext->alsa.snd_device_name_get_hint               = (ma_proc)_snd_device_name_get_hint;
26268     pContext->alsa.snd_card_get_index                     = (ma_proc)_snd_card_get_index;
26269     pContext->alsa.snd_device_name_free_hint              = (ma_proc)_snd_device_name_free_hint;
26270     pContext->alsa.snd_pcm_mmap_begin                     = (ma_proc)_snd_pcm_mmap_begin;
26271     pContext->alsa.snd_pcm_mmap_commit                    = (ma_proc)_snd_pcm_mmap_commit;
26272     pContext->alsa.snd_pcm_recover                        = (ma_proc)_snd_pcm_recover;
26273     pContext->alsa.snd_pcm_readi                          = (ma_proc)_snd_pcm_readi;
26274     pContext->alsa.snd_pcm_writei                         = (ma_proc)_snd_pcm_writei;
26275     pContext->alsa.snd_pcm_avail                          = (ma_proc)_snd_pcm_avail;
26276     pContext->alsa.snd_pcm_avail_update                   = (ma_proc)_snd_pcm_avail_update;
26277     pContext->alsa.snd_pcm_wait                           = (ma_proc)_snd_pcm_wait;
26278     pContext->alsa.snd_pcm_nonblock                       = (ma_proc)_snd_pcm_nonblock;
26279     pContext->alsa.snd_pcm_info                           = (ma_proc)_snd_pcm_info;
26280     pContext->alsa.snd_pcm_info_sizeof                    = (ma_proc)_snd_pcm_info_sizeof;
26281     pContext->alsa.snd_pcm_info_get_name                  = (ma_proc)_snd_pcm_info_get_name;
26282     pContext->alsa.snd_pcm_poll_descriptors               = (ma_proc)_snd_pcm_poll_descriptors;
26283     pContext->alsa.snd_pcm_poll_descriptors_count         = (ma_proc)_snd_pcm_poll_descriptors_count;
26284     pContext->alsa.snd_pcm_poll_descriptors_revents       = (ma_proc)_snd_pcm_poll_descriptors_revents;
26285     pContext->alsa.snd_config_update_free_global          = (ma_proc)_snd_config_update_free_global;
26286 #endif
26287
26288     pContext->alsa.useVerboseDeviceEnumeration = pConfig->alsa.useVerboseDeviceEnumeration;
26289
26290     result = ma_mutex_init(&pContext->alsa.internalDeviceEnumLock);
26291     if (result != MA_SUCCESS) {
26292         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] WARNING: Failed to initialize mutex for internal device enumeration.");
26293         return result;
26294     }
26295
26296     pCallbacks->onContextInit             = ma_context_init__alsa;
26297     pCallbacks->onContextUninit           = ma_context_uninit__alsa;
26298     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__alsa;
26299     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__alsa;
26300     pCallbacks->onDeviceInit              = ma_device_init__alsa;
26301     pCallbacks->onDeviceUninit            = ma_device_uninit__alsa;
26302     pCallbacks->onDeviceStart             = ma_device_start__alsa;
26303     pCallbacks->onDeviceStop              = ma_device_stop__alsa;
26304     pCallbacks->onDeviceRead              = ma_device_read__alsa;
26305     pCallbacks->onDeviceWrite             = ma_device_write__alsa;
26306     pCallbacks->onDeviceDataLoop          = NULL;
26307     pCallbacks->onDeviceDataLoopWakeup    = ma_device_data_loop_wakeup__alsa;
26308
26309     return MA_SUCCESS;
26310 }
26311 #endif  /* ALSA */
26312
26313
26314
26315 /******************************************************************************
26316
26317 PulseAudio Backend
26318
26319 ******************************************************************************/
26320 #ifdef MA_HAS_PULSEAUDIO
26321 /*
26322 The PulseAudio API, along with Apple's Core Audio, is the worst of the maintream audio APIs. This is a brief description of what's going on
26323 in the PulseAudio backend. I apologize if this gets a bit ranty for your liking - you might want to skip this discussion.
26324
26325 PulseAudio has something they call the "Simple API", which unfortunately isn't suitable for miniaudio. I've not seen anywhere where it
26326 allows you to enumerate over devices, nor does it seem to support the ability to stop and start streams. Looking at the documentation, it
26327 appears as though the stream is constantly running and you prevent sound from being emitted or captured by simply not calling the read or
26328 write functions. This is not a professional solution as it would be much better to *actually* stop the underlying stream. Perhaps the
26329 simple API has some smarts to do this automatically, but I'm not sure. Another limitation with the simple API is that it seems inefficient
26330 when you want to have multiple streams to a single context. For these reasons, miniaudio is not using the simple API.
26331
26332 Since we're not using the simple API, we're left with the asynchronous API as our only other option. And boy, is this where it starts to
26333 get fun, and I don't mean that in a good way...
26334
26335 The problems start with the very name of the API - "asynchronous". Yes, this is an asynchronous oriented API which means your commands
26336 don't immediately take effect. You instead need to issue your commands, and then wait for them to complete. The waiting mechanism is
26337 enabled through the use of a "main loop". In the asychronous API you cannot get away from the main loop, and the main loop is where almost
26338 all of PulseAudio's problems stem from.
26339
26340 When you first initialize PulseAudio you need an object referred to as "main loop". You can implement this yourself by defining your own
26341 vtable, but it's much easier to just use one of the built-in main loop implementations. There's two generic implementations called
26342 pa_mainloop and pa_threaded_mainloop, and another implementation specific to GLib called pa_glib_mainloop. We're using pa_threaded_mainloop
26343 because it simplifies management of the worker thread. The idea of the main loop object is pretty self explanatory - you're supposed to use
26344 it to implement a worker thread which runs in a loop. The main loop is where operations are actually executed.
26345
26346 To initialize the main loop, you just use `pa_threaded_mainloop_new()`. This is the first function you'll call. You can then get a pointer
26347 to the vtable with `pa_threaded_mainloop_get_api()` (the main loop vtable is called `pa_mainloop_api`). Again, you can bypass the threaded
26348 main loop object entirely and just implement `pa_mainloop_api` directly, but there's no need for it unless you're doing something extremely
26349 specialized such as if you want to integrate it into your application's existing main loop infrastructure.
26350
26351 (EDIT 2021-01-26: miniaudio is no longer using `pa_threaded_mainloop` due to this issue: https://github.com/mackron/miniaudio/issues/262.
26352 It is now using `pa_mainloop` which turns out to be a simpler solution anyway. The rest of this rant still applies, however.)
26353
26354 Once you have your main loop vtable (the `pa_mainloop_api` object) you can create the PulseAudio context. This is very similar to
26355 miniaudio's context and they map to each other quite well. You have one context to many streams, which is basically the same as miniaudio's
26356 one `ma_context` to many `ma_device`s. Here's where it starts to get annoying, however. When you first create the PulseAudio context, which
26357 is done with `pa_context_new()`, it's not actually connected to anything. When you connect, you call `pa_context_connect()`. However, if
26358 you remember, PulseAudio is an asynchronous API. That means you cannot just assume the context is connected after `pa_context_context()`
26359 has returned. You instead need to wait for it to connect. To do this, you need to either wait for a callback to get fired, which you can
26360 set with `pa_context_set_state_callback()`, or you can continuously poll the context's state. Either way, you need to run this in a loop.
26361 All objects from here out are created from the context, and, I believe, you can't be creating these objects until the context is connected.
26362 This waiting loop is therefore unavoidable. In order for the waiting to ever complete, however, the main loop needs to be running. Before
26363 attempting to connect the context, the main loop needs to be started with `pa_threaded_mainloop_start()`.
26364
26365 The reason for this asynchronous design is to support cases where you're connecting to a remote server, say through a local network or an
26366 internet connection. However, the *VAST* majority of cases don't involve this at all - they just connect to a local "server" running on the
26367 host machine. The fact that this would be the default rather than making `pa_context_connect()` synchronous tends to boggle the mind.
26368
26369 Once the context has been created and connected you can start creating a stream. A PulseAudio stream is analogous to miniaudio's device.
26370 The initialization of a stream is fairly standard - you configure some attributes (analogous to miniaudio's device config) and then call
26371 `pa_stream_new()` to actually create it. Here is where we start to get into "operations". When configuring the stream, you can get
26372 information about the source (such as sample format, sample rate, etc.), however it's not synchronous. Instead, a `pa_operation` object
26373 is returned from `pa_context_get_source_info_by_name()` (capture) or `pa_context_get_sink_info_by_name()` (playback). Then, you need to
26374 run a loop (again!) to wait for the operation to complete which you can determine via a callback or polling, just like we did with the
26375 context. Then, as an added bonus, you need to decrement the reference counter of the `pa_operation` object to ensure memory is cleaned up.
26376 All of that just to retrieve basic information about a device!
26377
26378 Once the basic information about the device has been retrieved, miniaudio can now create the stream with `ma_stream_new()`. Like the
26379 context, this needs to be connected. But we need to be careful here, because we're now about to introduce one of the most horrific design
26380 choices in PulseAudio.
26381
26382 PulseAudio allows you to specify a callback that is fired when data can be written to or read from a stream. The language is important here
26383 because PulseAudio takes it literally, specifically the "can be". You would think these callbacks would be appropriate as the place for
26384 writing and reading data to and from the stream, and that would be right, except when it's not. When you initialize the stream, you can
26385 set a flag that tells PulseAudio to not start the stream automatically. This is required because miniaudio does not auto-start devices
26386 straight after initialization - you need to call `ma_device_start()` manually. The problem is that even when this flag is specified,
26387 PulseAudio will immediately fire it's write or read callback. This is *technically* correct (based on the wording in the documentation)
26388 because indeed, data *can* be written at this point. The problem is that it's not *practical*. It makes sense that the write/read callback
26389 would be where a program will want to write or read data to or from the stream, but when it's called before the application has even
26390 requested that the stream be started, it's just not practical because the program probably isn't ready for any kind of data delivery at
26391 that point (it may still need to load files or whatnot). Instead, this callback should only be fired when the application requests the
26392 stream be started which is how it works with literally *every* other callback-based audio API. Since miniaudio forbids firing of the data
26393 callback until the device has been started (as it should be with *all* callback based APIs), logic needs to be added to ensure miniaudio
26394 doesn't just blindly fire the application-defined data callback from within the PulseAudio callback before the stream has actually been
26395 started. The device state is used for this - if the state is anything other than `ma_device_state_starting` or `ma_device_state_started`, the main data
26396 callback is not fired.
26397
26398 This, unfortunately, is not the end of the problems with the PulseAudio write callback. Any normal callback based audio API will
26399 continuously fire the callback at regular intervals based on the size of the internal buffer. This will only ever be fired when the device
26400 is running, and will be fired regardless of whether or not the user actually wrote anything to the device/stream. This not the case in
26401 PulseAudio. In PulseAudio, the data callback will *only* be called if you wrote something to it previously. That means, if you don't call
26402 `pa_stream_write()`, the callback will not get fired. On the surface you wouldn't think this would matter because you should be always
26403 writing data, and if you don't have anything to write, just write silence. That's fine until you want to drain the stream. You see, if
26404 you're continuously writing data to the stream, the stream will never get drained! That means in order to drain the stream, you need to
26405 *not* write data to it! But remember, when you don't write data to the stream, the callback won't get fired again! Why is draining
26406 important? Because that's how we've defined stopping to work in miniaudio. In miniaudio, stopping the device requires it to be drained
26407 before returning from ma_device_stop(). So we've stopped the device, which requires us to drain, but draining requires us to *not* write
26408 data to the stream (or else it won't ever complete draining), but not writing to the stream means the callback won't get fired again!
26409
26410 This becomes a problem when stopping and then restarting the device. When the device is stopped, it's drained, which requires us to *not*
26411 write anything to the stream. But then, since we didn't write anything to it, the write callback will *never* get called again if we just
26412 resume the stream naively. This means that starting the stream requires us to write data to the stream from outside the callback. This
26413 disconnect is something PulseAudio has got seriously wrong - there should only ever be a single source of data delivery, that being the
26414 callback. (I have tried using `pa_stream_flush()` to trigger the write callback to fire, but this just doesn't work for some reason.)
26415
26416 Once you've created the stream, you need to connect it which involves the whole waiting procedure. This is the same process as the context,
26417 only this time you'll poll for the state with `pa_stream_get_status()`. The starting and stopping of a streaming is referred to as
26418 "corking" in PulseAudio. The analogy is corking a barrel. To start the stream, you uncork it, to stop it you cork it. Personally I think
26419 it's silly - why would you not just call it "starting" and "stopping" like any other normal audio API? Anyway, the act of corking is, you
26420 guessed it, asynchronous. This means you'll need our waiting loop as usual. Again, why this asynchronous design is the default is
26421 absolutely beyond me. Would it really be that hard to just make it run synchronously?
26422
26423 Teardown is pretty simple (what?!). It's just a matter of calling the relevant `_unref()` function on each object in reverse order that
26424 they were initialized in.
26425
26426 That's about it from the PulseAudio side. A bit ranty, I know, but they really need to fix that main loop and callback system. They're
26427 embarrassingly unpractical. The main loop thing is an easy fix - have synchronous versions of all APIs. If an application wants these to
26428 run asynchronously, they can execute them in a separate thread themselves. The desire to run these asynchronously is such a niche
26429 requirement - it makes no sense to make it the default. The stream write callback needs to be change, or an alternative provided, that is
26430 constantly fired, regardless of whether or not `pa_stream_write()` has been called, and it needs to take a pointer to a buffer as a
26431 parameter which the program just writes to directly rather than having to call `pa_stream_writable_size()` and `pa_stream_write()`. These
26432 changes alone will change PulseAudio from one of the worst audio APIs to one of the best.
26433 */
26434
26435
26436 /*
26437 It is assumed pulseaudio.h is available when linking at compile time. When linking at compile time, we use the declarations in the header
26438 to check for type safety. We cannot do this when linking at run time because the header might not be available.
26439 */
26440 #ifdef MA_NO_RUNTIME_LINKING
26441
26442 /* pulseaudio.h marks some functions with "inline" which isn't always supported. Need to emulate it. */
26443 #if !defined(__cplusplus)
26444     #if defined(__STRICT_ANSI__)
26445         #if !defined(inline)
26446             #define inline __inline__ __attribute__((always_inline))
26447             #define MA_INLINE_DEFINED
26448         #endif
26449     #endif
26450 #endif
26451 #include <pulse/pulseaudio.h>
26452 #if defined(MA_INLINE_DEFINED)
26453     #undef inline
26454     #undef MA_INLINE_DEFINED
26455 #endif
26456
26457 #define MA_PA_OK                                       PA_OK
26458 #define MA_PA_ERR_ACCESS                               PA_ERR_ACCESS
26459 #define MA_PA_ERR_INVALID                              PA_ERR_INVALID
26460 #define MA_PA_ERR_NOENTITY                             PA_ERR_NOENTITY
26461 #define MA_PA_ERR_NOTSUPPORTED                         PA_ERR_NOTSUPPORTED
26462
26463 #define MA_PA_CHANNELS_MAX                             PA_CHANNELS_MAX
26464 #define MA_PA_RATE_MAX                                 PA_RATE_MAX
26465
26466 typedef pa_context_flags_t ma_pa_context_flags_t;
26467 #define MA_PA_CONTEXT_NOFLAGS                          PA_CONTEXT_NOFLAGS
26468 #define MA_PA_CONTEXT_NOAUTOSPAWN                      PA_CONTEXT_NOAUTOSPAWN
26469 #define MA_PA_CONTEXT_NOFAIL                           PA_CONTEXT_NOFAIL
26470
26471 typedef pa_stream_flags_t ma_pa_stream_flags_t;
26472 #define MA_PA_STREAM_NOFLAGS                           PA_STREAM_NOFLAGS
26473 #define MA_PA_STREAM_START_CORKED                      PA_STREAM_START_CORKED
26474 #define MA_PA_STREAM_INTERPOLATE_TIMING                PA_STREAM_INTERPOLATE_TIMING
26475 #define MA_PA_STREAM_NOT_MONOTONIC                     PA_STREAM_NOT_MONOTONIC
26476 #define MA_PA_STREAM_AUTO_TIMING_UPDATE                PA_STREAM_AUTO_TIMING_UPDATE
26477 #define MA_PA_STREAM_NO_REMAP_CHANNELS                 PA_STREAM_NO_REMAP_CHANNELS
26478 #define MA_PA_STREAM_NO_REMIX_CHANNELS                 PA_STREAM_NO_REMIX_CHANNELS
26479 #define MA_PA_STREAM_FIX_FORMAT                        PA_STREAM_FIX_FORMAT
26480 #define MA_PA_STREAM_FIX_RATE                          PA_STREAM_FIX_RATE
26481 #define MA_PA_STREAM_FIX_CHANNELS                      PA_STREAM_FIX_CHANNELS
26482 #define MA_PA_STREAM_DONT_MOVE                         PA_STREAM_DONT_MOVE
26483 #define MA_PA_STREAM_VARIABLE_RATE                     PA_STREAM_VARIABLE_RATE
26484 #define MA_PA_STREAM_PEAK_DETECT                       PA_STREAM_PEAK_DETECT
26485 #define MA_PA_STREAM_START_MUTED                       PA_STREAM_START_MUTED
26486 #define MA_PA_STREAM_ADJUST_LATENCY                    PA_STREAM_ADJUST_LATENCY
26487 #define MA_PA_STREAM_EARLY_REQUESTS                    PA_STREAM_EARLY_REQUESTS
26488 #define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND         PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND
26489 #define MA_PA_STREAM_START_UNMUTED                     PA_STREAM_START_UNMUTED
26490 #define MA_PA_STREAM_FAIL_ON_SUSPEND                   PA_STREAM_FAIL_ON_SUSPEND
26491 #define MA_PA_STREAM_RELATIVE_VOLUME                   PA_STREAM_RELATIVE_VOLUME
26492 #define MA_PA_STREAM_PASSTHROUGH                       PA_STREAM_PASSTHROUGH
26493
26494 typedef pa_sink_flags_t ma_pa_sink_flags_t;
26495 #define MA_PA_SINK_NOFLAGS                             PA_SINK_NOFLAGS
26496 #define MA_PA_SINK_HW_VOLUME_CTRL                      PA_SINK_HW_VOLUME_CTRL
26497 #define MA_PA_SINK_LATENCY                             PA_SINK_LATENCY
26498 #define MA_PA_SINK_HARDWARE                            PA_SINK_HARDWARE
26499 #define MA_PA_SINK_NETWORK                             PA_SINK_NETWORK
26500 #define MA_PA_SINK_HW_MUTE_CTRL                        PA_SINK_HW_MUTE_CTRL
26501 #define MA_PA_SINK_DECIBEL_VOLUME                      PA_SINK_DECIBEL_VOLUME
26502 #define MA_PA_SINK_FLAT_VOLUME                         PA_SINK_FLAT_VOLUME
26503 #define MA_PA_SINK_DYNAMIC_LATENCY                     PA_SINK_DYNAMIC_LATENCY
26504 #define MA_PA_SINK_SET_FORMATS                         PA_SINK_SET_FORMATS
26505
26506 typedef pa_source_flags_t ma_pa_source_flags_t;
26507 #define MA_PA_SOURCE_NOFLAGS                           PA_SOURCE_NOFLAGS
26508 #define MA_PA_SOURCE_HW_VOLUME_CTRL                    PA_SOURCE_HW_VOLUME_CTRL
26509 #define MA_PA_SOURCE_LATENCY                           PA_SOURCE_LATENCY
26510 #define MA_PA_SOURCE_HARDWARE                          PA_SOURCE_HARDWARE
26511 #define MA_PA_SOURCE_NETWORK                           PA_SOURCE_NETWORK
26512 #define MA_PA_SOURCE_HW_MUTE_CTRL                      PA_SOURCE_HW_MUTE_CTRL
26513 #define MA_PA_SOURCE_DECIBEL_VOLUME                    PA_SOURCE_DECIBEL_VOLUME
26514 #define MA_PA_SOURCE_DYNAMIC_LATENCY                   PA_SOURCE_DYNAMIC_LATENCY
26515 #define MA_PA_SOURCE_FLAT_VOLUME                       PA_SOURCE_FLAT_VOLUME
26516
26517 typedef pa_context_state_t ma_pa_context_state_t;
26518 #define MA_PA_CONTEXT_UNCONNECTED                      PA_CONTEXT_UNCONNECTED
26519 #define MA_PA_CONTEXT_CONNECTING                       PA_CONTEXT_CONNECTING
26520 #define MA_PA_CONTEXT_AUTHORIZING                      PA_CONTEXT_AUTHORIZING
26521 #define MA_PA_CONTEXT_SETTING_NAME                     PA_CONTEXT_SETTING_NAME
26522 #define MA_PA_CONTEXT_READY                            PA_CONTEXT_READY
26523 #define MA_PA_CONTEXT_FAILED                           PA_CONTEXT_FAILED
26524 #define MA_PA_CONTEXT_TERMINATED                       PA_CONTEXT_TERMINATED
26525
26526 typedef pa_stream_state_t ma_pa_stream_state_t;
26527 #define MA_PA_STREAM_UNCONNECTED                       PA_STREAM_UNCONNECTED
26528 #define MA_PA_STREAM_CREATING                          PA_STREAM_CREATING
26529 #define MA_PA_STREAM_READY                             PA_STREAM_READY
26530 #define MA_PA_STREAM_FAILED                            PA_STREAM_FAILED
26531 #define MA_PA_STREAM_TERMINATED                        PA_STREAM_TERMINATED
26532
26533 typedef pa_operation_state_t ma_pa_operation_state_t;
26534 #define MA_PA_OPERATION_RUNNING                        PA_OPERATION_RUNNING
26535 #define MA_PA_OPERATION_DONE                           PA_OPERATION_DONE
26536 #define MA_PA_OPERATION_CANCELLED                      PA_OPERATION_CANCELLED
26537
26538 typedef pa_sink_state_t ma_pa_sink_state_t;
26539 #define MA_PA_SINK_INVALID_STATE                       PA_SINK_INVALID_STATE
26540 #define MA_PA_SINK_RUNNING                             PA_SINK_RUNNING
26541 #define MA_PA_SINK_IDLE                                PA_SINK_IDLE
26542 #define MA_PA_SINK_SUSPENDED                           PA_SINK_SUSPENDED
26543
26544 typedef pa_source_state_t ma_pa_source_state_t;
26545 #define MA_PA_SOURCE_INVALID_STATE                     PA_SOURCE_INVALID_STATE
26546 #define MA_PA_SOURCE_RUNNING                           PA_SOURCE_RUNNING
26547 #define MA_PA_SOURCE_IDLE                              PA_SOURCE_IDLE
26548 #define MA_PA_SOURCE_SUSPENDED                         PA_SOURCE_SUSPENDED
26549
26550 typedef pa_seek_mode_t ma_pa_seek_mode_t;
26551 #define MA_PA_SEEK_RELATIVE                            PA_SEEK_RELATIVE
26552 #define MA_PA_SEEK_ABSOLUTE                            PA_SEEK_ABSOLUTE
26553 #define MA_PA_SEEK_RELATIVE_ON_READ                    PA_SEEK_RELATIVE_ON_READ
26554 #define MA_PA_SEEK_RELATIVE_END                        PA_SEEK_RELATIVE_END
26555
26556 typedef pa_channel_position_t ma_pa_channel_position_t;
26557 #define MA_PA_CHANNEL_POSITION_INVALID                 PA_CHANNEL_POSITION_INVALID
26558 #define MA_PA_CHANNEL_POSITION_MONO                    PA_CHANNEL_POSITION_MONO
26559 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT              PA_CHANNEL_POSITION_FRONT_LEFT
26560 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT             PA_CHANNEL_POSITION_FRONT_RIGHT
26561 #define MA_PA_CHANNEL_POSITION_FRONT_CENTER            PA_CHANNEL_POSITION_FRONT_CENTER
26562 #define MA_PA_CHANNEL_POSITION_REAR_CENTER             PA_CHANNEL_POSITION_REAR_CENTER
26563 #define MA_PA_CHANNEL_POSITION_REAR_LEFT               PA_CHANNEL_POSITION_REAR_LEFT
26564 #define MA_PA_CHANNEL_POSITION_REAR_RIGHT              PA_CHANNEL_POSITION_REAR_RIGHT
26565 #define MA_PA_CHANNEL_POSITION_LFE                     PA_CHANNEL_POSITION_LFE
26566 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER    PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
26567 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER   PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
26568 #define MA_PA_CHANNEL_POSITION_SIDE_LEFT               PA_CHANNEL_POSITION_SIDE_LEFT
26569 #define MA_PA_CHANNEL_POSITION_SIDE_RIGHT              PA_CHANNEL_POSITION_SIDE_RIGHT
26570 #define MA_PA_CHANNEL_POSITION_AUX0                    PA_CHANNEL_POSITION_AUX0
26571 #define MA_PA_CHANNEL_POSITION_AUX1                    PA_CHANNEL_POSITION_AUX1
26572 #define MA_PA_CHANNEL_POSITION_AUX2                    PA_CHANNEL_POSITION_AUX2
26573 #define MA_PA_CHANNEL_POSITION_AUX3                    PA_CHANNEL_POSITION_AUX3
26574 #define MA_PA_CHANNEL_POSITION_AUX4                    PA_CHANNEL_POSITION_AUX4
26575 #define MA_PA_CHANNEL_POSITION_AUX5                    PA_CHANNEL_POSITION_AUX5
26576 #define MA_PA_CHANNEL_POSITION_AUX6                    PA_CHANNEL_POSITION_AUX6
26577 #define MA_PA_CHANNEL_POSITION_AUX7                    PA_CHANNEL_POSITION_AUX7
26578 #define MA_PA_CHANNEL_POSITION_AUX8                    PA_CHANNEL_POSITION_AUX8
26579 #define MA_PA_CHANNEL_POSITION_AUX9                    PA_CHANNEL_POSITION_AUX9
26580 #define MA_PA_CHANNEL_POSITION_AUX10                   PA_CHANNEL_POSITION_AUX10
26581 #define MA_PA_CHANNEL_POSITION_AUX11                   PA_CHANNEL_POSITION_AUX11
26582 #define MA_PA_CHANNEL_POSITION_AUX12                   PA_CHANNEL_POSITION_AUX12
26583 #define MA_PA_CHANNEL_POSITION_AUX13                   PA_CHANNEL_POSITION_AUX13
26584 #define MA_PA_CHANNEL_POSITION_AUX14                   PA_CHANNEL_POSITION_AUX14
26585 #define MA_PA_CHANNEL_POSITION_AUX15                   PA_CHANNEL_POSITION_AUX15
26586 #define MA_PA_CHANNEL_POSITION_AUX16                   PA_CHANNEL_POSITION_AUX16
26587 #define MA_PA_CHANNEL_POSITION_AUX17                   PA_CHANNEL_POSITION_AUX17
26588 #define MA_PA_CHANNEL_POSITION_AUX18                   PA_CHANNEL_POSITION_AUX18
26589 #define MA_PA_CHANNEL_POSITION_AUX19                   PA_CHANNEL_POSITION_AUX19
26590 #define MA_PA_CHANNEL_POSITION_AUX20                   PA_CHANNEL_POSITION_AUX20
26591 #define MA_PA_CHANNEL_POSITION_AUX21                   PA_CHANNEL_POSITION_AUX21
26592 #define MA_PA_CHANNEL_POSITION_AUX22                   PA_CHANNEL_POSITION_AUX22
26593 #define MA_PA_CHANNEL_POSITION_AUX23                   PA_CHANNEL_POSITION_AUX23
26594 #define MA_PA_CHANNEL_POSITION_AUX24                   PA_CHANNEL_POSITION_AUX24
26595 #define MA_PA_CHANNEL_POSITION_AUX25                   PA_CHANNEL_POSITION_AUX25
26596 #define MA_PA_CHANNEL_POSITION_AUX26                   PA_CHANNEL_POSITION_AUX26
26597 #define MA_PA_CHANNEL_POSITION_AUX27                   PA_CHANNEL_POSITION_AUX27
26598 #define MA_PA_CHANNEL_POSITION_AUX28                   PA_CHANNEL_POSITION_AUX28
26599 #define MA_PA_CHANNEL_POSITION_AUX29                   PA_CHANNEL_POSITION_AUX29
26600 #define MA_PA_CHANNEL_POSITION_AUX30                   PA_CHANNEL_POSITION_AUX30
26601 #define MA_PA_CHANNEL_POSITION_AUX31                   PA_CHANNEL_POSITION_AUX31
26602 #define MA_PA_CHANNEL_POSITION_TOP_CENTER              PA_CHANNEL_POSITION_TOP_CENTER
26603 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT          PA_CHANNEL_POSITION_TOP_FRONT_LEFT
26604 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT         PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
26605 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER        PA_CHANNEL_POSITION_TOP_FRONT_CENTER
26606 #define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT           PA_CHANNEL_POSITION_TOP_REAR_LEFT
26607 #define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT          PA_CHANNEL_POSITION_TOP_REAR_RIGHT
26608 #define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER         PA_CHANNEL_POSITION_TOP_REAR_CENTER
26609 #define MA_PA_CHANNEL_POSITION_LEFT                    PA_CHANNEL_POSITION_LEFT
26610 #define MA_PA_CHANNEL_POSITION_RIGHT                   PA_CHANNEL_POSITION_RIGHT
26611 #define MA_PA_CHANNEL_POSITION_CENTER                  PA_CHANNEL_POSITION_CENTER
26612 #define MA_PA_CHANNEL_POSITION_SUBWOOFER               PA_CHANNEL_POSITION_SUBWOOFER
26613
26614 typedef pa_channel_map_def_t ma_pa_channel_map_def_t;
26615 #define MA_PA_CHANNEL_MAP_AIFF                         PA_CHANNEL_MAP_AIFF
26616 #define MA_PA_CHANNEL_MAP_ALSA                         PA_CHANNEL_MAP_ALSA
26617 #define MA_PA_CHANNEL_MAP_AUX                          PA_CHANNEL_MAP_AUX
26618 #define MA_PA_CHANNEL_MAP_WAVEEX                       PA_CHANNEL_MAP_WAVEEX
26619 #define MA_PA_CHANNEL_MAP_OSS                          PA_CHANNEL_MAP_OSS
26620 #define MA_PA_CHANNEL_MAP_DEFAULT                      PA_CHANNEL_MAP_DEFAULT
26621
26622 typedef pa_sample_format_t ma_pa_sample_format_t;
26623 #define MA_PA_SAMPLE_INVALID                           PA_SAMPLE_INVALID
26624 #define MA_PA_SAMPLE_U8                                PA_SAMPLE_U8
26625 #define MA_PA_SAMPLE_ALAW                              PA_SAMPLE_ALAW
26626 #define MA_PA_SAMPLE_ULAW                              PA_SAMPLE_ULAW
26627 #define MA_PA_SAMPLE_S16LE                             PA_SAMPLE_S16LE
26628 #define MA_PA_SAMPLE_S16BE                             PA_SAMPLE_S16BE
26629 #define MA_PA_SAMPLE_FLOAT32LE                         PA_SAMPLE_FLOAT32LE
26630 #define MA_PA_SAMPLE_FLOAT32BE                         PA_SAMPLE_FLOAT32BE
26631 #define MA_PA_SAMPLE_S32LE                             PA_SAMPLE_S32LE
26632 #define MA_PA_SAMPLE_S32BE                             PA_SAMPLE_S32BE
26633 #define MA_PA_SAMPLE_S24LE                             PA_SAMPLE_S24LE
26634 #define MA_PA_SAMPLE_S24BE                             PA_SAMPLE_S24BE
26635 #define MA_PA_SAMPLE_S24_32LE                          PA_SAMPLE_S24_32LE
26636 #define MA_PA_SAMPLE_S24_32BE                          PA_SAMPLE_S24_32BE
26637
26638 typedef pa_mainloop             ma_pa_mainloop;
26639 typedef pa_threaded_mainloop    ma_pa_threaded_mainloop;
26640 typedef pa_mainloop_api         ma_pa_mainloop_api;
26641 typedef pa_context              ma_pa_context;
26642 typedef pa_operation            ma_pa_operation;
26643 typedef pa_stream               ma_pa_stream;
26644 typedef pa_spawn_api            ma_pa_spawn_api;
26645 typedef pa_buffer_attr          ma_pa_buffer_attr;
26646 typedef pa_channel_map          ma_pa_channel_map;
26647 typedef pa_cvolume              ma_pa_cvolume;
26648 typedef pa_sample_spec          ma_pa_sample_spec;
26649 typedef pa_sink_info            ma_pa_sink_info;
26650 typedef pa_source_info          ma_pa_source_info;
26651
26652 typedef pa_context_notify_cb_t  ma_pa_context_notify_cb_t;
26653 typedef pa_sink_info_cb_t       ma_pa_sink_info_cb_t;
26654 typedef pa_source_info_cb_t     ma_pa_source_info_cb_t;
26655 typedef pa_stream_success_cb_t  ma_pa_stream_success_cb_t;
26656 typedef pa_stream_request_cb_t  ma_pa_stream_request_cb_t;
26657 typedef pa_stream_notify_cb_t   ma_pa_stream_notify_cb_t;
26658 typedef pa_free_cb_t            ma_pa_free_cb_t;
26659 #else
26660 #define MA_PA_OK                                       0
26661 #define MA_PA_ERR_ACCESS                               1
26662 #define MA_PA_ERR_INVALID                              2
26663 #define MA_PA_ERR_NOENTITY                             5
26664 #define MA_PA_ERR_NOTSUPPORTED                         19
26665
26666 #define MA_PA_CHANNELS_MAX                             32
26667 #define MA_PA_RATE_MAX                                 384000
26668
26669 typedef int ma_pa_context_flags_t;
26670 #define MA_PA_CONTEXT_NOFLAGS                          0x00000000
26671 #define MA_PA_CONTEXT_NOAUTOSPAWN                      0x00000001
26672 #define MA_PA_CONTEXT_NOFAIL                           0x00000002
26673
26674 typedef int ma_pa_stream_flags_t;
26675 #define MA_PA_STREAM_NOFLAGS                           0x00000000
26676 #define MA_PA_STREAM_START_CORKED                      0x00000001
26677 #define MA_PA_STREAM_INTERPOLATE_TIMING                0x00000002
26678 #define MA_PA_STREAM_NOT_MONOTONIC                     0x00000004
26679 #define MA_PA_STREAM_AUTO_TIMING_UPDATE                0x00000008
26680 #define MA_PA_STREAM_NO_REMAP_CHANNELS                 0x00000010
26681 #define MA_PA_STREAM_NO_REMIX_CHANNELS                 0x00000020
26682 #define MA_PA_STREAM_FIX_FORMAT                        0x00000040
26683 #define MA_PA_STREAM_FIX_RATE                          0x00000080
26684 #define MA_PA_STREAM_FIX_CHANNELS                      0x00000100
26685 #define MA_PA_STREAM_DONT_MOVE                         0x00000200
26686 #define MA_PA_STREAM_VARIABLE_RATE                     0x00000400
26687 #define MA_PA_STREAM_PEAK_DETECT                       0x00000800
26688 #define MA_PA_STREAM_START_MUTED                       0x00001000
26689 #define MA_PA_STREAM_ADJUST_LATENCY                    0x00002000
26690 #define MA_PA_STREAM_EARLY_REQUESTS                    0x00004000
26691 #define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND         0x00008000
26692 #define MA_PA_STREAM_START_UNMUTED                     0x00010000
26693 #define MA_PA_STREAM_FAIL_ON_SUSPEND                   0x00020000
26694 #define MA_PA_STREAM_RELATIVE_VOLUME                   0x00040000
26695 #define MA_PA_STREAM_PASSTHROUGH                       0x00080000
26696
26697 typedef int ma_pa_sink_flags_t;
26698 #define MA_PA_SINK_NOFLAGS                             0x00000000
26699 #define MA_PA_SINK_HW_VOLUME_CTRL                      0x00000001
26700 #define MA_PA_SINK_LATENCY                             0x00000002
26701 #define MA_PA_SINK_HARDWARE                            0x00000004
26702 #define MA_PA_SINK_NETWORK                             0x00000008
26703 #define MA_PA_SINK_HW_MUTE_CTRL                        0x00000010
26704 #define MA_PA_SINK_DECIBEL_VOLUME                      0x00000020
26705 #define MA_PA_SINK_FLAT_VOLUME                         0x00000040
26706 #define MA_PA_SINK_DYNAMIC_LATENCY                     0x00000080
26707 #define MA_PA_SINK_SET_FORMATS                         0x00000100
26708
26709 typedef int ma_pa_source_flags_t;
26710 #define MA_PA_SOURCE_NOFLAGS                           0x00000000
26711 #define MA_PA_SOURCE_HW_VOLUME_CTRL                    0x00000001
26712 #define MA_PA_SOURCE_LATENCY                           0x00000002
26713 #define MA_PA_SOURCE_HARDWARE                          0x00000004
26714 #define MA_PA_SOURCE_NETWORK                           0x00000008
26715 #define MA_PA_SOURCE_HW_MUTE_CTRL                      0x00000010
26716 #define MA_PA_SOURCE_DECIBEL_VOLUME                    0x00000020
26717 #define MA_PA_SOURCE_DYNAMIC_LATENCY                   0x00000040
26718 #define MA_PA_SOURCE_FLAT_VOLUME                       0x00000080
26719
26720 typedef int ma_pa_context_state_t;
26721 #define MA_PA_CONTEXT_UNCONNECTED                      0
26722 #define MA_PA_CONTEXT_CONNECTING                       1
26723 #define MA_PA_CONTEXT_AUTHORIZING                      2
26724 #define MA_PA_CONTEXT_SETTING_NAME                     3
26725 #define MA_PA_CONTEXT_READY                            4
26726 #define MA_PA_CONTEXT_FAILED                           5
26727 #define MA_PA_CONTEXT_TERMINATED                       6
26728
26729 typedef int ma_pa_stream_state_t;
26730 #define MA_PA_STREAM_UNCONNECTED                       0
26731 #define MA_PA_STREAM_CREATING                          1
26732 #define MA_PA_STREAM_READY                             2
26733 #define MA_PA_STREAM_FAILED                            3
26734 #define MA_PA_STREAM_TERMINATED                        4
26735
26736 typedef int ma_pa_operation_state_t;
26737 #define MA_PA_OPERATION_RUNNING                        0
26738 #define MA_PA_OPERATION_DONE                           1
26739 #define MA_PA_OPERATION_CANCELLED                      2
26740
26741 typedef int ma_pa_sink_state_t;
26742 #define MA_PA_SINK_INVALID_STATE                       -1
26743 #define MA_PA_SINK_RUNNING                             0
26744 #define MA_PA_SINK_IDLE                                1
26745 #define MA_PA_SINK_SUSPENDED                           2
26746
26747 typedef int ma_pa_source_state_t;
26748 #define MA_PA_SOURCE_INVALID_STATE                     -1
26749 #define MA_PA_SOURCE_RUNNING                           0
26750 #define MA_PA_SOURCE_IDLE                              1
26751 #define MA_PA_SOURCE_SUSPENDED                         2
26752
26753 typedef int ma_pa_seek_mode_t;
26754 #define MA_PA_SEEK_RELATIVE                            0
26755 #define MA_PA_SEEK_ABSOLUTE                            1
26756 #define MA_PA_SEEK_RELATIVE_ON_READ                    2
26757 #define MA_PA_SEEK_RELATIVE_END                        3
26758
26759 typedef int ma_pa_channel_position_t;
26760 #define MA_PA_CHANNEL_POSITION_INVALID                 -1
26761 #define MA_PA_CHANNEL_POSITION_MONO                    0
26762 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT              1
26763 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT             2
26764 #define MA_PA_CHANNEL_POSITION_FRONT_CENTER            3
26765 #define MA_PA_CHANNEL_POSITION_REAR_CENTER             4
26766 #define MA_PA_CHANNEL_POSITION_REAR_LEFT               5
26767 #define MA_PA_CHANNEL_POSITION_REAR_RIGHT              6
26768 #define MA_PA_CHANNEL_POSITION_LFE                     7
26769 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER    8
26770 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER   9
26771 #define MA_PA_CHANNEL_POSITION_SIDE_LEFT               10
26772 #define MA_PA_CHANNEL_POSITION_SIDE_RIGHT              11
26773 #define MA_PA_CHANNEL_POSITION_AUX0                    12
26774 #define MA_PA_CHANNEL_POSITION_AUX1                    13
26775 #define MA_PA_CHANNEL_POSITION_AUX2                    14
26776 #define MA_PA_CHANNEL_POSITION_AUX3                    15
26777 #define MA_PA_CHANNEL_POSITION_AUX4                    16
26778 #define MA_PA_CHANNEL_POSITION_AUX5                    17
26779 #define MA_PA_CHANNEL_POSITION_AUX6                    18
26780 #define MA_PA_CHANNEL_POSITION_AUX7                    19
26781 #define MA_PA_CHANNEL_POSITION_AUX8                    20
26782 #define MA_PA_CHANNEL_POSITION_AUX9                    21
26783 #define MA_PA_CHANNEL_POSITION_AUX10                   22
26784 #define MA_PA_CHANNEL_POSITION_AUX11                   23
26785 #define MA_PA_CHANNEL_POSITION_AUX12                   24
26786 #define MA_PA_CHANNEL_POSITION_AUX13                   25
26787 #define MA_PA_CHANNEL_POSITION_AUX14                   26
26788 #define MA_PA_CHANNEL_POSITION_AUX15                   27
26789 #define MA_PA_CHANNEL_POSITION_AUX16                   28
26790 #define MA_PA_CHANNEL_POSITION_AUX17                   29
26791 #define MA_PA_CHANNEL_POSITION_AUX18                   30
26792 #define MA_PA_CHANNEL_POSITION_AUX19                   31
26793 #define MA_PA_CHANNEL_POSITION_AUX20                   32
26794 #define MA_PA_CHANNEL_POSITION_AUX21                   33
26795 #define MA_PA_CHANNEL_POSITION_AUX22                   34
26796 #define MA_PA_CHANNEL_POSITION_AUX23                   35
26797 #define MA_PA_CHANNEL_POSITION_AUX24                   36
26798 #define MA_PA_CHANNEL_POSITION_AUX25                   37
26799 #define MA_PA_CHANNEL_POSITION_AUX26                   38
26800 #define MA_PA_CHANNEL_POSITION_AUX27                   39
26801 #define MA_PA_CHANNEL_POSITION_AUX28                   40
26802 #define MA_PA_CHANNEL_POSITION_AUX29                   41
26803 #define MA_PA_CHANNEL_POSITION_AUX30                   42
26804 #define MA_PA_CHANNEL_POSITION_AUX31                   43
26805 #define MA_PA_CHANNEL_POSITION_TOP_CENTER              44
26806 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT          45
26807 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT         46
26808 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER        47
26809 #define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT           48
26810 #define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT          49
26811 #define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER         50
26812 #define MA_PA_CHANNEL_POSITION_LEFT                    MA_PA_CHANNEL_POSITION_FRONT_LEFT
26813 #define MA_PA_CHANNEL_POSITION_RIGHT                   MA_PA_CHANNEL_POSITION_FRONT_RIGHT
26814 #define MA_PA_CHANNEL_POSITION_CENTER                  MA_PA_CHANNEL_POSITION_FRONT_CENTER
26815 #define MA_PA_CHANNEL_POSITION_SUBWOOFER               MA_PA_CHANNEL_POSITION_LFE
26816
26817 typedef int ma_pa_channel_map_def_t;
26818 #define MA_PA_CHANNEL_MAP_AIFF                         0
26819 #define MA_PA_CHANNEL_MAP_ALSA                         1
26820 #define MA_PA_CHANNEL_MAP_AUX                          2
26821 #define MA_PA_CHANNEL_MAP_WAVEEX                       3
26822 #define MA_PA_CHANNEL_MAP_OSS                          4
26823 #define MA_PA_CHANNEL_MAP_DEFAULT                      MA_PA_CHANNEL_MAP_AIFF
26824
26825 typedef int ma_pa_sample_format_t;
26826 #define MA_PA_SAMPLE_INVALID                           -1
26827 #define MA_PA_SAMPLE_U8                                0
26828 #define MA_PA_SAMPLE_ALAW                              1
26829 #define MA_PA_SAMPLE_ULAW                              2
26830 #define MA_PA_SAMPLE_S16LE                             3
26831 #define MA_PA_SAMPLE_S16BE                             4
26832 #define MA_PA_SAMPLE_FLOAT32LE                         5
26833 #define MA_PA_SAMPLE_FLOAT32BE                         6
26834 #define MA_PA_SAMPLE_S32LE                             7
26835 #define MA_PA_SAMPLE_S32BE                             8
26836 #define MA_PA_SAMPLE_S24LE                             9
26837 #define MA_PA_SAMPLE_S24BE                             10
26838 #define MA_PA_SAMPLE_S24_32LE                          11
26839 #define MA_PA_SAMPLE_S24_32BE                          12
26840
26841 typedef struct ma_pa_mainloop           ma_pa_mainloop;
26842 typedef struct ma_pa_threaded_mainloop  ma_pa_threaded_mainloop;
26843 typedef struct ma_pa_mainloop_api       ma_pa_mainloop_api;
26844 typedef struct ma_pa_context            ma_pa_context;
26845 typedef struct ma_pa_operation          ma_pa_operation;
26846 typedef struct ma_pa_stream             ma_pa_stream;
26847 typedef struct ma_pa_spawn_api          ma_pa_spawn_api;
26848
26849 typedef struct
26850 {
26851     ma_uint32 maxlength;
26852     ma_uint32 tlength;
26853     ma_uint32 prebuf;
26854     ma_uint32 minreq;
26855     ma_uint32 fragsize;
26856 } ma_pa_buffer_attr;
26857
26858 typedef struct
26859 {
26860     ma_uint8 channels;
26861     ma_pa_channel_position_t map[MA_PA_CHANNELS_MAX];
26862 } ma_pa_channel_map;
26863
26864 typedef struct
26865 {
26866     ma_uint8 channels;
26867     ma_uint32 values[MA_PA_CHANNELS_MAX];
26868 } ma_pa_cvolume;
26869
26870 typedef struct
26871 {
26872     ma_pa_sample_format_t format;
26873     ma_uint32 rate;
26874     ma_uint8 channels;
26875 } ma_pa_sample_spec;
26876
26877 typedef struct
26878 {
26879     const char* name;
26880     ma_uint32 index;
26881     const char* description;
26882     ma_pa_sample_spec sample_spec;
26883     ma_pa_channel_map channel_map;
26884     ma_uint32 owner_module;
26885     ma_pa_cvolume volume;
26886     int mute;
26887     ma_uint32 monitor_source;
26888     const char* monitor_source_name;
26889     ma_uint64 latency;
26890     const char* driver;
26891     ma_pa_sink_flags_t flags;
26892     void* proplist;
26893     ma_uint64 configured_latency;
26894     ma_uint32 base_volume;
26895     ma_pa_sink_state_t state;
26896     ma_uint32 n_volume_steps;
26897     ma_uint32 card;
26898     ma_uint32 n_ports;
26899     void** ports;
26900     void* active_port;
26901     ma_uint8 n_formats;
26902     void** formats;
26903 } ma_pa_sink_info;
26904
26905 typedef struct
26906 {
26907     const char *name;
26908     ma_uint32 index;
26909     const char *description;
26910     ma_pa_sample_spec sample_spec;
26911     ma_pa_channel_map channel_map;
26912     ma_uint32 owner_module;
26913     ma_pa_cvolume volume;
26914     int mute;
26915     ma_uint32 monitor_of_sink;
26916     const char *monitor_of_sink_name;
26917     ma_uint64 latency;
26918     const char *driver;
26919     ma_pa_source_flags_t flags;
26920     void* proplist;
26921     ma_uint64 configured_latency;
26922     ma_uint32 base_volume;
26923     ma_pa_source_state_t state;
26924     ma_uint32 n_volume_steps;
26925     ma_uint32 card;
26926     ma_uint32 n_ports;
26927     void** ports;
26928     void* active_port;
26929     ma_uint8 n_formats;
26930     void** formats;
26931 } ma_pa_source_info;
26932
26933 typedef void (* ma_pa_context_notify_cb_t)(ma_pa_context* c, void* userdata);
26934 typedef void (* ma_pa_sink_info_cb_t)     (ma_pa_context* c, const ma_pa_sink_info* i, int eol, void* userdata);
26935 typedef void (* ma_pa_source_info_cb_t)   (ma_pa_context* c, const ma_pa_source_info* i, int eol, void* userdata);
26936 typedef void (* ma_pa_stream_success_cb_t)(ma_pa_stream* s, int success, void* userdata);
26937 typedef void (* ma_pa_stream_request_cb_t)(ma_pa_stream* s, size_t nbytes, void* userdata);
26938 typedef void (* ma_pa_stream_notify_cb_t) (ma_pa_stream* s, void* userdata);
26939 typedef void (* ma_pa_free_cb_t)          (void* p);
26940 #endif
26941
26942
26943 typedef ma_pa_mainloop*          (* ma_pa_mainloop_new_proc)                   (void);
26944 typedef void                     (* ma_pa_mainloop_free_proc)                  (ma_pa_mainloop* m);
26945 typedef void                     (* ma_pa_mainloop_quit_proc)                  (ma_pa_mainloop* m, int retval);
26946 typedef ma_pa_mainloop_api*      (* ma_pa_mainloop_get_api_proc)               (ma_pa_mainloop* m);
26947 typedef int                      (* ma_pa_mainloop_iterate_proc)               (ma_pa_mainloop* m, int block, int* retval);
26948 typedef void                     (* ma_pa_mainloop_wakeup_proc)                (ma_pa_mainloop* m);
26949 typedef ma_pa_threaded_mainloop* (* ma_pa_threaded_mainloop_new_proc)          (void);
26950 typedef void                     (* ma_pa_threaded_mainloop_free_proc)         (ma_pa_threaded_mainloop* m);
26951 typedef int                      (* ma_pa_threaded_mainloop_start_proc)        (ma_pa_threaded_mainloop* m);
26952 typedef void                     (* ma_pa_threaded_mainloop_stop_proc)         (ma_pa_threaded_mainloop* m);
26953 typedef void                     (* ma_pa_threaded_mainloop_lock_proc)         (ma_pa_threaded_mainloop* m);
26954 typedef void                     (* ma_pa_threaded_mainloop_unlock_proc)       (ma_pa_threaded_mainloop* m);
26955 typedef void                     (* ma_pa_threaded_mainloop_wait_proc)         (ma_pa_threaded_mainloop* m);
26956 typedef void                     (* ma_pa_threaded_mainloop_signal_proc)       (ma_pa_threaded_mainloop* m, int wait_for_accept);
26957 typedef void                     (* ma_pa_threaded_mainloop_accept_proc)       (ma_pa_threaded_mainloop* m);
26958 typedef int                      (* ma_pa_threaded_mainloop_get_retval_proc)   (ma_pa_threaded_mainloop* m);
26959 typedef ma_pa_mainloop_api*      (* ma_pa_threaded_mainloop_get_api_proc)      (ma_pa_threaded_mainloop* m);
26960 typedef int                      (* ma_pa_threaded_mainloop_in_thread_proc)    (ma_pa_threaded_mainloop* m);
26961 typedef void                     (* ma_pa_threaded_mainloop_set_name_proc)     (ma_pa_threaded_mainloop* m, const char* name);
26962 typedef ma_pa_context*           (* ma_pa_context_new_proc)                    (ma_pa_mainloop_api* mainloop, const char* name);
26963 typedef void                     (* ma_pa_context_unref_proc)                  (ma_pa_context* c);
26964 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);
26965 typedef void                     (* ma_pa_context_disconnect_proc)             (ma_pa_context* c);
26966 typedef void                     (* ma_pa_context_set_state_callback_proc)     (ma_pa_context* c, ma_pa_context_notify_cb_t cb, void* userdata);
26967 typedef ma_pa_context_state_t    (* ma_pa_context_get_state_proc)              (ma_pa_context* c);
26968 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);
26969 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);
26970 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);
26971 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);
26972 typedef void                     (* ma_pa_operation_unref_proc)                (ma_pa_operation* o);
26973 typedef ma_pa_operation_state_t  (* ma_pa_operation_get_state_proc)            (ma_pa_operation* o);
26974 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);
26975 typedef int                      (* ma_pa_channel_map_valid_proc)              (const ma_pa_channel_map* m);
26976 typedef int                      (* ma_pa_channel_map_compatible_proc)         (const ma_pa_channel_map* m, const ma_pa_sample_spec* ss);
26977 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);
26978 typedef void                     (* ma_pa_stream_unref_proc)                   (ma_pa_stream* s);
26979 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);
26980 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);
26981 typedef int                      (* ma_pa_stream_disconnect_proc)              (ma_pa_stream* s);
26982 typedef ma_pa_stream_state_t     (* ma_pa_stream_get_state_proc)               (ma_pa_stream* s);
26983 typedef const ma_pa_sample_spec* (* ma_pa_stream_get_sample_spec_proc)         (ma_pa_stream* s);
26984 typedef const ma_pa_channel_map* (* ma_pa_stream_get_channel_map_proc)         (ma_pa_stream* s);
26985 typedef const ma_pa_buffer_attr* (* ma_pa_stream_get_buffer_attr_proc)         (ma_pa_stream* s);
26986 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);
26987 typedef const char*              (* ma_pa_stream_get_device_name_proc)         (ma_pa_stream* s);
26988 typedef void                     (* ma_pa_stream_set_write_callback_proc)      (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata);
26989 typedef void                     (* ma_pa_stream_set_read_callback_proc)       (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata);
26990 typedef void                     (* ma_pa_stream_set_suspended_callback_proc)  (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata);
26991 typedef void                     (* ma_pa_stream_set_moved_callback_proc)      (ma_pa_stream* s, ma_pa_stream_notify_cb_t cb, void* userdata);
26992 typedef int                      (* ma_pa_stream_is_suspended_proc)            (const ma_pa_stream* s);
26993 typedef ma_pa_operation*         (* ma_pa_stream_flush_proc)                   (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata);
26994 typedef ma_pa_operation*         (* ma_pa_stream_drain_proc)                   (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata);
26995 typedef int                      (* ma_pa_stream_is_corked_proc)               (ma_pa_stream* s);
26996 typedef ma_pa_operation*         (* ma_pa_stream_cork_proc)                    (ma_pa_stream* s, int b, ma_pa_stream_success_cb_t cb, void* userdata);
26997 typedef ma_pa_operation*         (* ma_pa_stream_trigger_proc)                 (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata);
26998 typedef int                      (* ma_pa_stream_begin_write_proc)             (ma_pa_stream* s, void** data, size_t* nbytes);
26999 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);
27000 typedef int                      (* ma_pa_stream_peek_proc)                    (ma_pa_stream* s, const void** data, size_t* nbytes);
27001 typedef int                      (* ma_pa_stream_drop_proc)                    (ma_pa_stream* s);
27002 typedef size_t                   (* ma_pa_stream_writable_size_proc)           (ma_pa_stream* s);
27003 typedef size_t                   (* ma_pa_stream_readable_size_proc)           (ma_pa_stream* s);
27004
27005 typedef struct
27006 {
27007     ma_uint32 count;
27008     ma_uint32 capacity;
27009     ma_device_info* pInfo;
27010 } ma_pulse_device_enum_data;
27011
27012 static ma_result ma_result_from_pulse(int result)
27013 {
27014     if (result < 0) {
27015         return MA_ERROR;
27016     }
27017
27018     switch (result) {
27019         case MA_PA_OK:           return MA_SUCCESS;
27020         case MA_PA_ERR_ACCESS:   return MA_ACCESS_DENIED;
27021         case MA_PA_ERR_INVALID:  return MA_INVALID_ARGS;
27022         case MA_PA_ERR_NOENTITY: return MA_NO_DEVICE;
27023         default:                 return MA_ERROR;
27024     }
27025 }
27026
27027 #if 0
27028 static ma_pa_sample_format_t ma_format_to_pulse(ma_format format)
27029 {
27030     if (ma_is_little_endian()) {
27031         switch (format) {
27032             case ma_format_s16: return MA_PA_SAMPLE_S16LE;
27033             case ma_format_s24: return MA_PA_SAMPLE_S24LE;
27034             case ma_format_s32: return MA_PA_SAMPLE_S32LE;
27035             case ma_format_f32: return MA_PA_SAMPLE_FLOAT32LE;
27036             default: break;
27037         }
27038     } else {
27039         switch (format) {
27040             case ma_format_s16: return MA_PA_SAMPLE_S16BE;
27041             case ma_format_s24: return MA_PA_SAMPLE_S24BE;
27042             case ma_format_s32: return MA_PA_SAMPLE_S32BE;
27043             case ma_format_f32: return MA_PA_SAMPLE_FLOAT32BE;
27044             default: break;
27045         }
27046     }
27047
27048     /* Endian agnostic. */
27049     switch (format) {
27050         case ma_format_u8: return MA_PA_SAMPLE_U8;
27051         default: return MA_PA_SAMPLE_INVALID;
27052     }
27053 }
27054 #endif
27055
27056 static ma_format ma_format_from_pulse(ma_pa_sample_format_t format)
27057 {
27058     if (ma_is_little_endian()) {
27059         switch (format) {
27060             case MA_PA_SAMPLE_S16LE:     return ma_format_s16;
27061             case MA_PA_SAMPLE_S24LE:     return ma_format_s24;
27062             case MA_PA_SAMPLE_S32LE:     return ma_format_s32;
27063             case MA_PA_SAMPLE_FLOAT32LE: return ma_format_f32;
27064             default: break;
27065         }
27066     } else {
27067         switch (format) {
27068             case MA_PA_SAMPLE_S16BE:     return ma_format_s16;
27069             case MA_PA_SAMPLE_S24BE:     return ma_format_s24;
27070             case MA_PA_SAMPLE_S32BE:     return ma_format_s32;
27071             case MA_PA_SAMPLE_FLOAT32BE: return ma_format_f32;
27072             default: break;
27073         }
27074     }
27075
27076     /* Endian agnostic. */
27077     switch (format) {
27078         case MA_PA_SAMPLE_U8: return ma_format_u8;
27079         default: return ma_format_unknown;
27080     }
27081 }
27082
27083 static ma_channel ma_channel_position_from_pulse(ma_pa_channel_position_t position)
27084 {
27085     switch (position)
27086     {
27087         case MA_PA_CHANNEL_POSITION_INVALID:               return MA_CHANNEL_NONE;
27088         case MA_PA_CHANNEL_POSITION_MONO:                  return MA_CHANNEL_MONO;
27089         case MA_PA_CHANNEL_POSITION_FRONT_LEFT:            return MA_CHANNEL_FRONT_LEFT;
27090         case MA_PA_CHANNEL_POSITION_FRONT_RIGHT:           return MA_CHANNEL_FRONT_RIGHT;
27091         case MA_PA_CHANNEL_POSITION_FRONT_CENTER:          return MA_CHANNEL_FRONT_CENTER;
27092         case MA_PA_CHANNEL_POSITION_REAR_CENTER:           return MA_CHANNEL_BACK_CENTER;
27093         case MA_PA_CHANNEL_POSITION_REAR_LEFT:             return MA_CHANNEL_BACK_LEFT;
27094         case MA_PA_CHANNEL_POSITION_REAR_RIGHT:            return MA_CHANNEL_BACK_RIGHT;
27095         case MA_PA_CHANNEL_POSITION_LFE:                   return MA_CHANNEL_LFE;
27096         case MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:  return MA_CHANNEL_FRONT_LEFT_CENTER;
27097         case MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER;
27098         case MA_PA_CHANNEL_POSITION_SIDE_LEFT:             return MA_CHANNEL_SIDE_LEFT;
27099         case MA_PA_CHANNEL_POSITION_SIDE_RIGHT:            return MA_CHANNEL_SIDE_RIGHT;
27100         case MA_PA_CHANNEL_POSITION_AUX0:                  return MA_CHANNEL_AUX_0;
27101         case MA_PA_CHANNEL_POSITION_AUX1:                  return MA_CHANNEL_AUX_1;
27102         case MA_PA_CHANNEL_POSITION_AUX2:                  return MA_CHANNEL_AUX_2;
27103         case MA_PA_CHANNEL_POSITION_AUX3:                  return MA_CHANNEL_AUX_3;
27104         case MA_PA_CHANNEL_POSITION_AUX4:                  return MA_CHANNEL_AUX_4;
27105         case MA_PA_CHANNEL_POSITION_AUX5:                  return MA_CHANNEL_AUX_5;
27106         case MA_PA_CHANNEL_POSITION_AUX6:                  return MA_CHANNEL_AUX_6;
27107         case MA_PA_CHANNEL_POSITION_AUX7:                  return MA_CHANNEL_AUX_7;
27108         case MA_PA_CHANNEL_POSITION_AUX8:                  return MA_CHANNEL_AUX_8;
27109         case MA_PA_CHANNEL_POSITION_AUX9:                  return MA_CHANNEL_AUX_9;
27110         case MA_PA_CHANNEL_POSITION_AUX10:                 return MA_CHANNEL_AUX_10;
27111         case MA_PA_CHANNEL_POSITION_AUX11:                 return MA_CHANNEL_AUX_11;
27112         case MA_PA_CHANNEL_POSITION_AUX12:                 return MA_CHANNEL_AUX_12;
27113         case MA_PA_CHANNEL_POSITION_AUX13:                 return MA_CHANNEL_AUX_13;
27114         case MA_PA_CHANNEL_POSITION_AUX14:                 return MA_CHANNEL_AUX_14;
27115         case MA_PA_CHANNEL_POSITION_AUX15:                 return MA_CHANNEL_AUX_15;
27116         case MA_PA_CHANNEL_POSITION_AUX16:                 return MA_CHANNEL_AUX_16;
27117         case MA_PA_CHANNEL_POSITION_AUX17:                 return MA_CHANNEL_AUX_17;
27118         case MA_PA_CHANNEL_POSITION_AUX18:                 return MA_CHANNEL_AUX_18;
27119         case MA_PA_CHANNEL_POSITION_AUX19:                 return MA_CHANNEL_AUX_19;
27120         case MA_PA_CHANNEL_POSITION_AUX20:                 return MA_CHANNEL_AUX_20;
27121         case MA_PA_CHANNEL_POSITION_AUX21:                 return MA_CHANNEL_AUX_21;
27122         case MA_PA_CHANNEL_POSITION_AUX22:                 return MA_CHANNEL_AUX_22;
27123         case MA_PA_CHANNEL_POSITION_AUX23:                 return MA_CHANNEL_AUX_23;
27124         case MA_PA_CHANNEL_POSITION_AUX24:                 return MA_CHANNEL_AUX_24;
27125         case MA_PA_CHANNEL_POSITION_AUX25:                 return MA_CHANNEL_AUX_25;
27126         case MA_PA_CHANNEL_POSITION_AUX26:                 return MA_CHANNEL_AUX_26;
27127         case MA_PA_CHANNEL_POSITION_AUX27:                 return MA_CHANNEL_AUX_27;
27128         case MA_PA_CHANNEL_POSITION_AUX28:                 return MA_CHANNEL_AUX_28;
27129         case MA_PA_CHANNEL_POSITION_AUX29:                 return MA_CHANNEL_AUX_29;
27130         case MA_PA_CHANNEL_POSITION_AUX30:                 return MA_CHANNEL_AUX_30;
27131         case MA_PA_CHANNEL_POSITION_AUX31:                 return MA_CHANNEL_AUX_31;
27132         case MA_PA_CHANNEL_POSITION_TOP_CENTER:            return MA_CHANNEL_TOP_CENTER;
27133         case MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT:        return MA_CHANNEL_TOP_FRONT_LEFT;
27134         case MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:       return MA_CHANNEL_TOP_FRONT_RIGHT;
27135         case MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER:      return MA_CHANNEL_TOP_FRONT_CENTER;
27136         case MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT:         return MA_CHANNEL_TOP_BACK_LEFT;
27137         case MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT:        return MA_CHANNEL_TOP_BACK_RIGHT;
27138         case MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER:       return MA_CHANNEL_TOP_BACK_CENTER;
27139         default: return MA_CHANNEL_NONE;
27140     }
27141 }
27142
27143 #if 0
27144 static ma_pa_channel_position_t ma_channel_position_to_pulse(ma_channel position)
27145 {
27146     switch (position)
27147     {
27148         case MA_CHANNEL_NONE:               return MA_PA_CHANNEL_POSITION_INVALID;
27149         case MA_CHANNEL_FRONT_LEFT:         return MA_PA_CHANNEL_POSITION_FRONT_LEFT;
27150         case MA_CHANNEL_FRONT_RIGHT:        return MA_PA_CHANNEL_POSITION_FRONT_RIGHT;
27151         case MA_CHANNEL_FRONT_CENTER:       return MA_PA_CHANNEL_POSITION_FRONT_CENTER;
27152         case MA_CHANNEL_LFE:                return MA_PA_CHANNEL_POSITION_LFE;
27153         case MA_CHANNEL_BACK_LEFT:          return MA_PA_CHANNEL_POSITION_REAR_LEFT;
27154         case MA_CHANNEL_BACK_RIGHT:         return MA_PA_CHANNEL_POSITION_REAR_RIGHT;
27155         case MA_CHANNEL_FRONT_LEFT_CENTER:  return MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
27156         case MA_CHANNEL_FRONT_RIGHT_CENTER: return MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
27157         case MA_CHANNEL_BACK_CENTER:        return MA_PA_CHANNEL_POSITION_REAR_CENTER;
27158         case MA_CHANNEL_SIDE_LEFT:          return MA_PA_CHANNEL_POSITION_SIDE_LEFT;
27159         case MA_CHANNEL_SIDE_RIGHT:         return MA_PA_CHANNEL_POSITION_SIDE_RIGHT;
27160         case MA_CHANNEL_TOP_CENTER:         return MA_PA_CHANNEL_POSITION_TOP_CENTER;
27161         case MA_CHANNEL_TOP_FRONT_LEFT:     return MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
27162         case MA_CHANNEL_TOP_FRONT_CENTER:   return MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
27163         case MA_CHANNEL_TOP_FRONT_RIGHT:    return MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
27164         case MA_CHANNEL_TOP_BACK_LEFT:      return MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT;
27165         case MA_CHANNEL_TOP_BACK_CENTER:    return MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER;
27166         case MA_CHANNEL_TOP_BACK_RIGHT:     return MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
27167         case MA_CHANNEL_19:                 return MA_PA_CHANNEL_POSITION_AUX18;
27168         case MA_CHANNEL_20:                 return MA_PA_CHANNEL_POSITION_AUX19;
27169         case MA_CHANNEL_21:                 return MA_PA_CHANNEL_POSITION_AUX20;
27170         case MA_CHANNEL_22:                 return MA_PA_CHANNEL_POSITION_AUX21;
27171         case MA_CHANNEL_23:                 return MA_PA_CHANNEL_POSITION_AUX22;
27172         case MA_CHANNEL_24:                 return MA_PA_CHANNEL_POSITION_AUX23;
27173         case MA_CHANNEL_25:                 return MA_PA_CHANNEL_POSITION_AUX24;
27174         case MA_CHANNEL_26:                 return MA_PA_CHANNEL_POSITION_AUX25;
27175         case MA_CHANNEL_27:                 return MA_PA_CHANNEL_POSITION_AUX26;
27176         case MA_CHANNEL_28:                 return MA_PA_CHANNEL_POSITION_AUX27;
27177         case MA_CHANNEL_29:                 return MA_PA_CHANNEL_POSITION_AUX28;
27178         case MA_CHANNEL_30:                 return MA_PA_CHANNEL_POSITION_AUX29;
27179         case MA_CHANNEL_31:                 return MA_PA_CHANNEL_POSITION_AUX30;
27180         case MA_CHANNEL_32:                 return MA_PA_CHANNEL_POSITION_AUX31;
27181         default: return (ma_pa_channel_position_t)position;
27182     }
27183 }
27184 #endif
27185
27186 static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_pa_operation* pOP)
27187 {
27188     int resultPA;
27189     ma_pa_operation_state_t state;
27190
27191     MA_ASSERT(pContext != NULL);
27192     MA_ASSERT(pOP != NULL);
27193
27194     for (;;) {
27195         state = ((ma_pa_operation_get_state_proc)pContext->pulse.pa_operation_get_state)(pOP);
27196         if (state != MA_PA_OPERATION_RUNNING) {
27197             break;  /* Done. */
27198         }
27199
27200         resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL);
27201         if (resultPA < 0) {
27202             return ma_result_from_pulse(resultPA);
27203         }
27204     }
27205
27206     return MA_SUCCESS;
27207 }
27208
27209 static ma_result ma_wait_for_operation_and_unref__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_pa_operation* pOP)
27210 {
27211     ma_result result;
27212
27213     if (pOP == NULL) {
27214         return MA_INVALID_ARGS;
27215     }
27216
27217     result = ma_wait_for_operation__pulse(pContext, pMainLoop, pOP);
27218     ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
27219
27220     return result;
27221 }
27222
27223 static ma_result ma_wait_for_pa_context_to_connect__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_ptr pPulseContext)
27224 {
27225     int resultPA;
27226     ma_pa_context_state_t state;
27227
27228     for (;;) {
27229         state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)((ma_pa_context*)pPulseContext);
27230         if (state == MA_PA_CONTEXT_READY) {
27231             break;  /* Done. */
27232         }
27233
27234         if (state == MA_PA_CONTEXT_FAILED || state == MA_PA_CONTEXT_TERMINATED) {
27235             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio context.");
27236             return MA_ERROR;
27237         }
27238
27239         resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL);
27240         if (resultPA < 0) {
27241             return ma_result_from_pulse(resultPA);
27242         }
27243     }
27244
27245     /* Should never get here. */
27246     return MA_SUCCESS;
27247 }
27248
27249 static ma_result ma_wait_for_pa_stream_to_connect__pulse(ma_context* pContext, ma_ptr pMainLoop, ma_ptr pStream)
27250 {
27251     int resultPA;
27252     ma_pa_stream_state_t state;
27253
27254     for (;;) {
27255         state = ((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)((ma_pa_stream*)pStream);
27256         if (state == MA_PA_STREAM_READY) {
27257             break;  /* Done. */
27258         }
27259
27260         if (state == MA_PA_STREAM_FAILED || state == MA_PA_STREAM_TERMINATED) {
27261             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio stream.");
27262             return MA_ERROR;
27263         }
27264
27265         resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pMainLoop, 1, NULL);
27266         if (resultPA < 0) {
27267             return ma_result_from_pulse(resultPA);
27268         }
27269     }
27270
27271     return MA_SUCCESS;
27272 }
27273
27274
27275 static ma_result ma_init_pa_mainloop_and_pa_context__pulse(ma_context* pContext, const char* pApplicationName, const char* pServerName, ma_bool32 tryAutoSpawn, ma_ptr* ppMainLoop, ma_ptr* ppPulseContext)
27276 {
27277     ma_result result;
27278     ma_ptr pMainLoop;
27279     ma_ptr pPulseContext;
27280
27281     MA_ASSERT(ppMainLoop     != NULL);
27282     MA_ASSERT(ppPulseContext != NULL);
27283
27284     /* The PulseAudio context maps well to miniaudio's notion of a context. The pa_context object will be initialized as part of the ma_context. */
27285     pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)();
27286     if (pMainLoop == NULL) {
27287         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create mainloop.");
27288         return MA_FAILED_TO_INIT_BACKEND;
27289     }
27290
27291     pPulseContext = ((ma_pa_context_new_proc)pContext->pulse.pa_context_new)(((ma_pa_mainloop_get_api_proc)pContext->pulse.pa_mainloop_get_api)((ma_pa_mainloop*)pMainLoop), pApplicationName);
27292     if (pPulseContext == NULL) {
27293         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio context.");
27294         ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop));
27295         return MA_FAILED_TO_INIT_BACKEND;
27296     }
27297
27298     /* Now we need to connect to the context. Everything is asynchronous so we need to wait for it to connect before returning. */
27299     result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pPulseContext, pServerName, (tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL));
27300     if (result != MA_SUCCESS) {
27301         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context.");
27302         ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop));
27303         return result;
27304     }
27305
27306     /* Since ma_context_init() runs synchronously we need to wait for the PulseAudio context to connect before we return. */
27307     result = ma_wait_for_pa_context_to_connect__pulse(pContext, pMainLoop, pPulseContext);
27308     if (result != MA_SUCCESS) {
27309         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[PulseAudio] Waiting for connection failed.");
27310         ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pMainLoop));
27311         return result;
27312     }
27313
27314     *ppMainLoop     = pMainLoop;
27315     *ppPulseContext = pPulseContext;
27316
27317     return MA_SUCCESS;
27318 }
27319
27320
27321 static void ma_device_sink_info_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData)
27322 {
27323     ma_pa_sink_info* pInfoOut;
27324
27325     if (endOfList > 0) {
27326         return;
27327     }
27328
27329     pInfoOut = (ma_pa_sink_info*)pUserData;
27330     MA_ASSERT(pInfoOut != NULL);
27331
27332     *pInfoOut = *pInfo;
27333
27334     (void)pPulseContext; /* Unused. */
27335 }
27336
27337 static void ma_device_source_info_callback(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData)
27338 {
27339     ma_pa_source_info* pInfoOut;
27340
27341     if (endOfList > 0) {
27342         return;
27343     }
27344
27345     pInfoOut = (ma_pa_source_info*)pUserData;
27346     MA_ASSERT(pInfoOut != NULL);
27347
27348     *pInfoOut = *pInfo;
27349
27350     (void)pPulseContext; /* Unused. */
27351 }
27352
27353 #if 0
27354 static void ma_device_sink_name_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData)
27355 {
27356     ma_device* pDevice;
27357
27358     if (endOfList > 0) {
27359         return;
27360     }
27361
27362     pDevice = (ma_device*)pUserData;
27363     MA_ASSERT(pDevice != NULL);
27364
27365     ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), pInfo->description, (size_t)-1);
27366
27367     (void)pPulseContext; /* Unused. */
27368 }
27369
27370 static void ma_device_source_name_callback(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData)
27371 {
27372     ma_device* pDevice;
27373
27374     if (endOfList > 0) {
27375         return;
27376     }
27377
27378     pDevice = (ma_device*)pUserData;
27379     MA_ASSERT(pDevice != NULL);
27380
27381     ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), pInfo->description, (size_t)-1);
27382
27383     (void)pPulseContext; /* Unused. */
27384 }
27385 #endif
27386
27387 static ma_result ma_context_get_sink_info__pulse(ma_context* pContext, const char* pDeviceName, ma_pa_sink_info* pSinkInfo)
27388 {
27389     ma_pa_operation* pOP;
27390
27391     pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pContext->pulse.pPulseContext, pDeviceName, ma_device_sink_info_callback, pSinkInfo);
27392     if (pOP == NULL) {
27393         return MA_ERROR;
27394     }
27395
27396     return ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP);
27397 }
27398
27399 static ma_result ma_context_get_source_info__pulse(ma_context* pContext, const char* pDeviceName, ma_pa_source_info* pSourceInfo)
27400 {
27401     ma_pa_operation* pOP;
27402
27403     pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pContext->pulse.pPulseContext, pDeviceName, ma_device_source_info_callback, pSourceInfo);
27404     if (pOP == NULL) {
27405         return MA_ERROR;
27406     }
27407
27408     return ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP);
27409 }
27410
27411 static ma_result ma_context_get_default_device_index__pulse(ma_context* pContext, ma_device_type deviceType, ma_uint32* pIndex)
27412 {
27413     ma_result result;
27414
27415     MA_ASSERT(pContext != NULL);
27416     MA_ASSERT(pIndex   != NULL);
27417
27418     if (pIndex != NULL) {
27419         *pIndex = (ma_uint32)-1;
27420     }
27421
27422     if (deviceType == ma_device_type_playback) {
27423         ma_pa_sink_info sinkInfo;
27424         result = ma_context_get_sink_info__pulse(pContext, NULL, &sinkInfo);
27425         if (result != MA_SUCCESS) {
27426             return result;
27427         }
27428
27429         if (pIndex != NULL) {
27430             *pIndex = sinkInfo.index;
27431         }
27432     }
27433
27434     if (deviceType == ma_device_type_capture) {
27435         ma_pa_source_info sourceInfo;
27436         result = ma_context_get_source_info__pulse(pContext, NULL, &sourceInfo);
27437         if (result != MA_SUCCESS) {
27438             return result;
27439         }
27440
27441         if (pIndex != NULL) {
27442             *pIndex = sourceInfo.index;
27443         }
27444     }
27445
27446     return MA_SUCCESS;
27447 }
27448
27449
27450 typedef struct
27451 {
27452     ma_context* pContext;
27453     ma_enum_devices_callback_proc callback;
27454     void* pUserData;
27455     ma_bool32 isTerminated;
27456     ma_uint32 defaultDeviceIndexPlayback;
27457     ma_uint32 defaultDeviceIndexCapture;
27458 } ma_context_enumerate_devices_callback_data__pulse;
27459
27460 static void ma_context_enumerate_devices_sink_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_sink_info* pSinkInfo, int endOfList, void* pUserData)
27461 {
27462     ma_context_enumerate_devices_callback_data__pulse* pData = (ma_context_enumerate_devices_callback_data__pulse*)pUserData;
27463     ma_device_info deviceInfo;
27464
27465     MA_ASSERT(pData != NULL);
27466
27467     if (endOfList || pData->isTerminated) {
27468         return;
27469     }
27470
27471     MA_ZERO_OBJECT(&deviceInfo);
27472
27473     /* The name from PulseAudio is the ID for miniaudio. */
27474     if (pSinkInfo->name != NULL) {
27475         ma_strncpy_s(deviceInfo.id.pulse, sizeof(deviceInfo.id.pulse), pSinkInfo->name, (size_t)-1);
27476     }
27477
27478     /* The description from PulseAudio is the name for miniaudio. */
27479     if (pSinkInfo->description != NULL) {
27480         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), pSinkInfo->description, (size_t)-1);
27481     }
27482
27483     if (pSinkInfo->index == pData->defaultDeviceIndexPlayback) {
27484         deviceInfo.isDefault = MA_TRUE;
27485     }
27486
27487     pData->isTerminated = !pData->callback(pData->pContext, ma_device_type_playback, &deviceInfo, pData->pUserData);
27488
27489     (void)pPulseContext; /* Unused. */
27490 }
27491
27492 static void ma_context_enumerate_devices_source_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_source_info* pSourceInfo, int endOfList, void* pUserData)
27493 {
27494     ma_context_enumerate_devices_callback_data__pulse* pData = (ma_context_enumerate_devices_callback_data__pulse*)pUserData;
27495     ma_device_info deviceInfo;
27496
27497     MA_ASSERT(pData != NULL);
27498
27499     if (endOfList || pData->isTerminated) {
27500         return;
27501     }
27502
27503     MA_ZERO_OBJECT(&deviceInfo);
27504
27505     /* The name from PulseAudio is the ID for miniaudio. */
27506     if (pSourceInfo->name != NULL) {
27507         ma_strncpy_s(deviceInfo.id.pulse, sizeof(deviceInfo.id.pulse), pSourceInfo->name, (size_t)-1);
27508     }
27509
27510     /* The description from PulseAudio is the name for miniaudio. */
27511     if (pSourceInfo->description != NULL) {
27512         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), pSourceInfo->description, (size_t)-1);
27513     }
27514
27515     if (pSourceInfo->index == pData->defaultDeviceIndexCapture) {
27516         deviceInfo.isDefault = MA_TRUE;
27517     }
27518
27519     pData->isTerminated = !pData->callback(pData->pContext, ma_device_type_capture, &deviceInfo, pData->pUserData);
27520
27521     (void)pPulseContext; /* Unused. */
27522 }
27523
27524 static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
27525 {
27526     ma_result result = MA_SUCCESS;
27527     ma_context_enumerate_devices_callback_data__pulse callbackData;
27528     ma_pa_operation* pOP = NULL;
27529
27530     MA_ASSERT(pContext != NULL);
27531     MA_ASSERT(callback != NULL);
27532
27533     callbackData.pContext = pContext;
27534     callbackData.callback = callback;
27535     callbackData.pUserData = pUserData;
27536     callbackData.isTerminated = MA_FALSE;
27537     callbackData.defaultDeviceIndexPlayback = (ma_uint32)-1;
27538     callbackData.defaultDeviceIndexCapture  = (ma_uint32)-1;
27539
27540     /* We need to get the index of the default devices. */
27541     ma_context_get_default_device_index__pulse(pContext, ma_device_type_playback, &callbackData.defaultDeviceIndexPlayback);
27542     ma_context_get_default_device_index__pulse(pContext, ma_device_type_capture,  &callbackData.defaultDeviceIndexCapture);
27543
27544     /* Playback. */
27545     if (!callbackData.isTerminated) {
27546         pOP = ((ma_pa_context_get_sink_info_list_proc)pContext->pulse.pa_context_get_sink_info_list)((ma_pa_context*)(pContext->pulse.pPulseContext), ma_context_enumerate_devices_sink_callback__pulse, &callbackData);
27547         if (pOP == NULL) {
27548             result = MA_ERROR;
27549             goto done;
27550         }
27551
27552         result = ma_wait_for_operation__pulse(pContext, pContext->pulse.pMainLoop, pOP);
27553         ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
27554
27555         if (result != MA_SUCCESS) {
27556             goto done;
27557         }
27558     }
27559
27560
27561     /* Capture. */
27562     if (!callbackData.isTerminated) {
27563         pOP = ((ma_pa_context_get_source_info_list_proc)pContext->pulse.pa_context_get_source_info_list)((ma_pa_context*)(pContext->pulse.pPulseContext), ma_context_enumerate_devices_source_callback__pulse, &callbackData);
27564         if (pOP == NULL) {
27565             result = MA_ERROR;
27566             goto done;
27567         }
27568
27569         result = ma_wait_for_operation__pulse(pContext, pContext->pulse.pMainLoop, pOP);
27570         ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
27571
27572         if (result != MA_SUCCESS) {
27573             goto done;
27574         }
27575     }
27576
27577 done:
27578     return result;
27579 }
27580
27581
27582 typedef struct
27583 {
27584     ma_device_info* pDeviceInfo;
27585     ma_uint32 defaultDeviceIndex;
27586     ma_bool32 foundDevice;
27587 } ma_context_get_device_info_callback_data__pulse;
27588
27589 static void ma_context_get_device_info_sink_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData)
27590 {
27591     ma_context_get_device_info_callback_data__pulse* pData = (ma_context_get_device_info_callback_data__pulse*)pUserData;
27592
27593     if (endOfList > 0) {
27594         return;
27595     }
27596
27597     MA_ASSERT(pData != NULL);
27598     pData->foundDevice = MA_TRUE;
27599
27600     if (pInfo->name != NULL) {
27601         ma_strncpy_s(pData->pDeviceInfo->id.pulse, sizeof(pData->pDeviceInfo->id.pulse), pInfo->name, (size_t)-1);
27602     }
27603
27604     if (pInfo->description != NULL) {
27605         ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pInfo->description, (size_t)-1);
27606     }
27607
27608     /*
27609     We're just reporting a single data format here. I think technically PulseAudio might support
27610     all formats, but I don't trust that PulseAudio will do *anything* right, so I'm just going to
27611     report the "native" device format.
27612     */
27613     pData->pDeviceInfo->nativeDataFormats[0].format     = ma_format_from_pulse(pInfo->sample_spec.format);
27614     pData->pDeviceInfo->nativeDataFormats[0].channels   = pInfo->sample_spec.channels;
27615     pData->pDeviceInfo->nativeDataFormats[0].sampleRate = pInfo->sample_spec.rate;
27616     pData->pDeviceInfo->nativeDataFormats[0].flags      = 0;
27617     pData->pDeviceInfo->nativeDataFormatCount = 1;
27618
27619     if (pData->defaultDeviceIndex == pInfo->index) {
27620         pData->pDeviceInfo->isDefault = MA_TRUE;
27621     }
27622
27623     (void)pPulseContext; /* Unused. */
27624 }
27625
27626 static void ma_context_get_device_info_source_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData)
27627 {
27628     ma_context_get_device_info_callback_data__pulse* pData = (ma_context_get_device_info_callback_data__pulse*)pUserData;
27629
27630     if (endOfList > 0) {
27631         return;
27632     }
27633
27634     MA_ASSERT(pData != NULL);
27635     pData->foundDevice = MA_TRUE;
27636
27637     if (pInfo->name != NULL) {
27638         ma_strncpy_s(pData->pDeviceInfo->id.pulse, sizeof(pData->pDeviceInfo->id.pulse), pInfo->name, (size_t)-1);
27639     }
27640
27641     if (pInfo->description != NULL) {
27642         ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pInfo->description, (size_t)-1);
27643     }
27644
27645     /*
27646     We're just reporting a single data format here. I think technically PulseAudio might support
27647     all formats, but I don't trust that PulseAudio will do *anything* right, so I'm just going to
27648     report the "native" device format.
27649     */
27650     pData->pDeviceInfo->nativeDataFormats[0].format     = ma_format_from_pulse(pInfo->sample_spec.format);
27651     pData->pDeviceInfo->nativeDataFormats[0].channels   = pInfo->sample_spec.channels;
27652     pData->pDeviceInfo->nativeDataFormats[0].sampleRate = pInfo->sample_spec.rate;
27653     pData->pDeviceInfo->nativeDataFormats[0].flags      = 0;
27654     pData->pDeviceInfo->nativeDataFormatCount = 1;
27655
27656     if (pData->defaultDeviceIndex == pInfo->index) {
27657         pData->pDeviceInfo->isDefault = MA_TRUE;
27658     }
27659
27660     (void)pPulseContext; /* Unused. */
27661 }
27662
27663 static ma_result ma_context_get_device_info__pulse(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
27664 {
27665     ma_result result = MA_SUCCESS;
27666     ma_context_get_device_info_callback_data__pulse callbackData;
27667     ma_pa_operation* pOP = NULL;
27668     const char* pDeviceName = NULL;
27669
27670     MA_ASSERT(pContext != NULL);
27671
27672     callbackData.pDeviceInfo = pDeviceInfo;
27673     callbackData.foundDevice = MA_FALSE;
27674
27675     if (pDeviceID != NULL) {
27676         pDeviceName = pDeviceID->pulse;
27677     } else {
27678         pDeviceName = NULL;
27679     }
27680
27681     result = ma_context_get_default_device_index__pulse(pContext, deviceType, &callbackData.defaultDeviceIndex);
27682
27683     if (deviceType == ma_device_type_playback) {
27684         pOP = ((ma_pa_context_get_sink_info_by_name_proc)pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceName, ma_context_get_device_info_sink_callback__pulse, &callbackData);
27685     } else {
27686         pOP = ((ma_pa_context_get_source_info_by_name_proc)pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)(pContext->pulse.pPulseContext), pDeviceName, ma_context_get_device_info_source_callback__pulse, &callbackData);
27687     }
27688
27689     if (pOP != NULL) {
27690         ma_wait_for_operation_and_unref__pulse(pContext, pContext->pulse.pMainLoop, pOP);
27691     } else {
27692         result = MA_ERROR;
27693         goto done;
27694     }
27695
27696     if (!callbackData.foundDevice) {
27697         result = MA_NO_DEVICE;
27698         goto done;
27699     }
27700
27701 done:
27702     return result;
27703 }
27704
27705 static ma_result ma_device_uninit__pulse(ma_device* pDevice)
27706 {
27707     ma_context* pContext;
27708
27709     MA_ASSERT(pDevice != NULL);
27710
27711     pContext = pDevice->pContext;
27712     MA_ASSERT(pContext != NULL);
27713
27714     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
27715         ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
27716         ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
27717     }
27718
27719     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
27720         ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
27721         ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
27722     }
27723
27724     if (pDevice->type == ma_device_type_duplex) {
27725         ma_duplex_rb_uninit(&pDevice->duplexRB);
27726     }
27727
27728     ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pDevice->pulse.pPulseContext);
27729     ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pDevice->pulse.pPulseContext);
27730     ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pDevice->pulse.pMainLoop);
27731
27732     return MA_SUCCESS;
27733 }
27734
27735 static ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 periodSizeInFrames, ma_uint32 periods, const ma_pa_sample_spec* ss)
27736 {
27737     ma_pa_buffer_attr attr;
27738     attr.maxlength = periodSizeInFrames * periods * ma_get_bytes_per_frame(ma_format_from_pulse(ss->format), ss->channels);
27739     attr.tlength   = attr.maxlength / periods;
27740     attr.prebuf    = (ma_uint32)-1;
27741     attr.minreq    = (ma_uint32)-1;
27742     attr.fragsize  = attr.maxlength / periods;
27743
27744     return attr;
27745 }
27746
27747 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)
27748 {
27749     static int g_StreamCounter = 0;
27750     char actualStreamName[256];
27751
27752     if (pStreamName != NULL) {
27753         ma_strncpy_s(actualStreamName, sizeof(actualStreamName), pStreamName, (size_t)-1);
27754     } else {
27755         ma_strcpy_s(actualStreamName, sizeof(actualStreamName), "miniaudio:");
27756         ma_itoa_s(g_StreamCounter, actualStreamName + 8, sizeof(actualStreamName)-8, 10);  /* 8 = strlen("miniaudio:") */
27757     }
27758     g_StreamCounter += 1;
27759
27760     return ((ma_pa_stream_new_proc)pDevice->pContext->pulse.pa_stream_new)((ma_pa_context*)pDevice->pulse.pPulseContext, actualStreamName, ss, cmap);
27761 }
27762
27763
27764 static void ma_device_on_read__pulse(ma_pa_stream* pStream, size_t byteCount, void* pUserData)
27765 {
27766     ma_device* pDevice = (ma_device*)pUserData;
27767     ma_uint32 bpf;
27768     ma_uint32 deviceState;
27769     ma_uint64 frameCount;
27770     ma_uint64 framesProcessed;
27771
27772     MA_ASSERT(pDevice != NULL);
27773
27774     /*
27775     Don't do anything if the device isn't initialized yet. Yes, this can happen because PulseAudio
27776     can fire this callback before the stream has even started. Ridiculous.
27777     */
27778     deviceState = ma_device_get_state(pDevice);
27779     if (deviceState != ma_device_state_starting && deviceState != ma_device_state_started) {
27780         return;
27781     }
27782
27783     bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
27784     MA_ASSERT(bpf > 0);
27785
27786     frameCount = byteCount / bpf;
27787     framesProcessed = 0;
27788
27789     while (ma_device_get_state(pDevice) == ma_device_state_started && framesProcessed < frameCount) {
27790         const void* pMappedPCMFrames;
27791         size_t bytesMapped;
27792         ma_uint64 framesMapped;
27793
27794         int pulseResult = ((ma_pa_stream_peek_proc)pDevice->pContext->pulse.pa_stream_peek)(pStream, &pMappedPCMFrames, &bytesMapped);
27795         if (pulseResult < 0) {
27796             break; /* Failed to map. Abort. */
27797         }
27798
27799         framesMapped = bytesMapped / bpf;
27800         if (framesMapped > 0) {
27801             if (pMappedPCMFrames != NULL) {
27802                 ma_device_handle_backend_data_callback(pDevice, NULL, pMappedPCMFrames, framesMapped);
27803             } else {
27804                 /* It's a hole. */
27805                 ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] ma_device_on_read__pulse: Hole.\n");
27806             }
27807
27808             pulseResult = ((ma_pa_stream_drop_proc)pDevice->pContext->pulse.pa_stream_drop)(pStream);
27809             if (pulseResult < 0) {
27810                 break;  /* Failed to drop the buffer. */
27811             }
27812
27813             framesProcessed += framesMapped;
27814
27815         } else {
27816             /* Nothing was mapped. Just abort. */
27817             break;
27818         }
27819     }
27820 }
27821
27822 static ma_result ma_device_write_to_stream__pulse(ma_device* pDevice, ma_pa_stream* pStream, ma_uint64* pFramesProcessed)
27823 {
27824     ma_result result = MA_SUCCESS;
27825     ma_uint64 framesProcessed = 0;
27826     size_t bytesMapped;
27827     ma_uint32 bpf;
27828     ma_uint32 deviceState;
27829
27830     MA_ASSERT(pDevice != NULL);
27831     MA_ASSERT(pStream != NULL);
27832
27833     bpf = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
27834     MA_ASSERT(bpf > 0);
27835
27836     deviceState = ma_device_get_state(pDevice);
27837
27838     bytesMapped = ((ma_pa_stream_writable_size_proc)pDevice->pContext->pulse.pa_stream_writable_size)(pStream);
27839     if (bytesMapped != (size_t)-1) {
27840         if (bytesMapped > 0) {
27841             ma_uint64 framesMapped;
27842             void* pMappedPCMFrames;
27843             int pulseResult = ((ma_pa_stream_begin_write_proc)pDevice->pContext->pulse.pa_stream_begin_write)(pStream, &pMappedPCMFrames, &bytesMapped);
27844             if (pulseResult < 0) {
27845                 result = ma_result_from_pulse(pulseResult);
27846                 goto done;
27847             }
27848
27849             framesMapped = bytesMapped / bpf;
27850
27851             if (deviceState == ma_device_state_started || deviceState == ma_device_state_starting) {  /* Check for starting state just in case this is being used to do the initial fill. */
27852                 ma_device_handle_backend_data_callback(pDevice, pMappedPCMFrames, NULL, framesMapped);
27853             } else {
27854                 /* Device is not started. Write silence. */
27855                 ma_silence_pcm_frames(pMappedPCMFrames, framesMapped, pDevice->playback.format, pDevice->playback.channels);
27856             }
27857
27858             pulseResult = ((ma_pa_stream_write_proc)pDevice->pContext->pulse.pa_stream_write)(pStream, pMappedPCMFrames, bytesMapped, NULL, 0, MA_PA_SEEK_RELATIVE);
27859             if (pulseResult < 0) {
27860                 result = ma_result_from_pulse(pulseResult);
27861                 goto done;  /* Failed to write data to stream. */
27862             }
27863
27864             framesProcessed += framesMapped;
27865         } else {
27866             result = MA_ERROR;  /* No data available. Abort. */
27867             goto done;
27868         }
27869     } else {
27870         result = MA_ERROR;  /* Failed to retrieve the writable size. Abort. */
27871         goto done;
27872     }
27873
27874 done:
27875     if (pFramesProcessed != NULL) {
27876         *pFramesProcessed = framesProcessed;
27877     }
27878
27879     return result;
27880 }
27881
27882 static void ma_device_on_write__pulse(ma_pa_stream* pStream, size_t byteCount, void* pUserData)
27883 {
27884     ma_device* pDevice = (ma_device*)pUserData;
27885     ma_uint32 bpf;
27886     ma_uint64 frameCount;
27887     ma_uint64 framesProcessed;
27888     ma_uint32 deviceState;
27889     ma_result result;
27890
27891     MA_ASSERT(pDevice != NULL);
27892
27893     /*
27894     Don't do anything if the device isn't initialized yet. Yes, this can happen because PulseAudio
27895     can fire this callback before the stream has even started. Ridiculous.
27896     */
27897     deviceState = ma_device_get_state(pDevice);
27898     if (deviceState != ma_device_state_starting && deviceState != ma_device_state_started) {
27899         return;
27900     }
27901
27902     bpf = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
27903     MA_ASSERT(bpf > 0);
27904
27905     frameCount = byteCount / bpf;
27906     framesProcessed = 0;
27907
27908     while (framesProcessed < frameCount) {
27909         ma_uint64 framesProcessedThisIteration;
27910
27911         /* Don't keep trying to process frames if the device isn't started. */
27912         deviceState = ma_device_get_state(pDevice);
27913         if (deviceState != ma_device_state_starting && deviceState != ma_device_state_started) {
27914             break;
27915         }
27916
27917         result = ma_device_write_to_stream__pulse(pDevice, pStream, &framesProcessedThisIteration);
27918         if (result != MA_SUCCESS) {
27919             break;
27920         }
27921
27922         framesProcessed += framesProcessedThisIteration;
27923     }
27924 }
27925
27926 static void ma_device_on_suspended__pulse(ma_pa_stream* pStream, void* pUserData)
27927 {
27928     ma_device* pDevice = (ma_device*)pUserData;
27929     int suspended;
27930
27931     (void)pStream;
27932
27933     suspended = ((ma_pa_stream_is_suspended_proc)pDevice->pContext->pulse.pa_stream_is_suspended)(pStream);
27934     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. pa_stream_is_suspended() returned %d.\n", suspended);
27935
27936     if (suspended < 0) {
27937         return;
27938     }
27939
27940     if (suspended == 1) {
27941         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Suspended.\n");
27942         ma_device__on_notification_stopped(pDevice);
27943     } else {
27944         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[Pulse] Device suspended state changed. Resumed.\n");
27945         ma_device__on_notification_started(pDevice);
27946     }
27947 }
27948
27949 static void ma_device_on_rerouted__pulse(ma_pa_stream* pStream, void* pUserData)
27950 {
27951     ma_device* pDevice = (ma_device*)pUserData;
27952
27953     (void)pStream;
27954     (void)pUserData;
27955
27956     ma_device__on_notification_rerouted(pDevice);
27957 }
27958
27959 static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
27960 {
27961     /*
27962     Notes for PulseAudio:
27963
27964       - We're always using native format/channels/rate regardless of whether or not PulseAudio
27965         supports the format directly through their own data conversion system. I'm doing this to
27966         reduce as much variability from the PulseAudio side as possible because it's seems to be
27967         extremely unreliable at everything it does.
27968
27969       - When both the period size in frames and milliseconds are 0, we default to miniaudio's
27970         default buffer sizes rather than leaving it up to PulseAudio because I don't trust
27971         PulseAudio to give us any kind of reasonable latency by default.
27972
27973       - Do not ever, *ever* forget to use MA_PA_STREAM_ADJUST_LATENCY. If you don't specify this
27974         flag, capture mode will just not work properly until you open another PulseAudio app.
27975     */
27976
27977     ma_result result = MA_SUCCESS;
27978     int error = 0;
27979     const char* devPlayback = NULL;
27980     const char* devCapture  = NULL;
27981     ma_format format = ma_format_unknown;
27982     ma_uint32 channels = 0;
27983     ma_uint32 sampleRate = 0;
27984     ma_pa_sink_info sinkInfo;
27985     ma_pa_source_info sourceInfo;
27986     ma_pa_sample_spec ss;
27987     ma_pa_channel_map cmap;
27988     ma_pa_buffer_attr attr;
27989     const ma_pa_sample_spec* pActualSS   = NULL;
27990     const ma_pa_channel_map* pActualCMap = NULL;
27991     const ma_pa_buffer_attr* pActualAttr = NULL;
27992     ma_uint32 iChannel;
27993     ma_pa_stream_flags_t streamFlags;
27994
27995     MA_ASSERT(pDevice != NULL);
27996     MA_ZERO_OBJECT(&pDevice->pulse);
27997
27998     printf("TESTING\n");
27999
28000     if (pConfig->deviceType == ma_device_type_loopback) {
28001         return MA_DEVICE_TYPE_NOT_SUPPORTED;
28002     }
28003
28004     /* No exclusive mode with the PulseAudio backend. */
28005     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) ||
28006         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode  == ma_share_mode_exclusive)) {
28007         return MA_SHARE_MODE_NOT_SUPPORTED;
28008     }
28009
28010     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
28011         if (pDescriptorPlayback->pDeviceID != NULL) {
28012             devPlayback = pDescriptorPlayback->pDeviceID->pulse;
28013         }
28014
28015         format     = pDescriptorPlayback->format;
28016         channels   = pDescriptorPlayback->channels;
28017         sampleRate = pDescriptorPlayback->sampleRate;
28018     }
28019
28020     if (pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) {
28021         if (pDescriptorCapture->pDeviceID != NULL) {
28022             devCapture = pDescriptorCapture->pDeviceID->pulse;
28023         }
28024
28025         format     = pDescriptorCapture->format;
28026         channels   = pDescriptorCapture->channels;
28027         sampleRate = pDescriptorCapture->sampleRate;
28028     }
28029
28030     
28031
28032     result = ma_init_pa_mainloop_and_pa_context__pulse(pDevice->pContext, pDevice->pContext->pulse.pApplicationName, pDevice->pContext->pulse.pServerName, MA_FALSE, &pDevice->pulse.pMainLoop, &pDevice->pulse.pPulseContext);
28033     if (result != MA_SUCCESS) {
28034         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize PA mainloop and context for device.\n");
28035         return result;
28036     }
28037
28038     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
28039         result = ma_context_get_source_info__pulse(pDevice->pContext, devCapture, &sourceInfo);
28040         if (result != MA_SUCCESS) {
28041             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve source info for capture device.");
28042             goto on_error0;
28043         }
28044
28045         ss   = sourceInfo.sample_spec;
28046         cmap = sourceInfo.channel_map;
28047
28048         if (ma_format_from_pulse(ss.format) == ma_format_unknown) {
28049             if (ma_is_little_endian()) {
28050                 ss.format = MA_PA_SAMPLE_FLOAT32LE;
28051             } else {
28052                 ss.format = MA_PA_SAMPLE_FLOAT32BE;
28053             }
28054             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_RATE_FLOAT32\n");
28055         }
28056         if (ss.rate == 0) {
28057             ss.rate = MA_DEFAULT_SAMPLE_RATE;
28058             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.rate = 0. Defaulting to %d\n", ss.rate);
28059         }
28060         if (ss.channels == 0) {
28061             ss.channels = MA_DEFAULT_CHANNELS;
28062             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.channels = 0. Defaulting to %d\n", ss.channels);
28063         }
28064
28065         /* We now have enough information to calculate our actual period size in frames. */
28066         pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, ss.rate, pConfig->performanceProfile);
28067
28068         attr = ma_device__pa_buffer_attr_new(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->periodCount, &ss);
28069         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Capture attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames);
28070
28071         pDevice->pulse.pStreamCapture = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNameCapture, &ss, &cmap);
28072         if (pDevice->pulse.pStreamCapture == NULL) {
28073             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream.");
28074             result = MA_ERROR;
28075             goto on_error0;
28076         }
28077
28078
28079         /* The callback needs to be set before connecting the stream. */
28080         ((ma_pa_stream_set_read_callback_proc)pDevice->pContext->pulse.pa_stream_set_read_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_read__pulse, pDevice);
28081
28082         /* State callback for checking when the device has been corked. */
28083         ((ma_pa_stream_set_suspended_callback_proc)pDevice->pContext->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_suspended__pulse, pDevice);
28084
28085         /* Rerouting notification. */
28086         ((ma_pa_stream_set_moved_callback_proc)pDevice->pContext->pulse.pa_stream_set_moved_callback)((ma_pa_stream*)pDevice->pulse.pStreamCapture, ma_device_on_rerouted__pulse, pDevice);
28087
28088
28089         /* Connect after we've got all of our internal state set up. */
28090         streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS;
28091         if (devCapture != NULL) {
28092             streamFlags |= MA_PA_STREAM_DONT_MOVE;
28093         }
28094
28095         error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags);
28096         if (error != MA_PA_OK) {
28097             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream.");
28098             result = ma_result_from_pulse(error);
28099             goto on_error1;
28100         }
28101
28102         result = ma_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, (ma_pa_stream*)pDevice->pulse.pStreamCapture);
28103         if (result != MA_SUCCESS) {
28104             goto on_error2;
28105         }
28106
28107         /* Internal format. */
28108         pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
28109         if (pActualSS != NULL) {
28110             ss = *pActualSS;
28111         }
28112
28113         pDescriptorCapture->format     = ma_format_from_pulse(ss.format);
28114         pDescriptorCapture->channels   = ss.channels;
28115         pDescriptorCapture->sampleRate = ss.rate;
28116
28117         /* Internal channel map. */
28118         pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
28119         if (pActualCMap != NULL) {
28120             cmap = *pActualCMap;
28121         }
28122
28123         for (iChannel = 0; iChannel < pDescriptorCapture->channels; ++iChannel) {
28124             pDescriptorCapture->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]);
28125         }
28126
28127
28128         /* Buffer. */
28129         pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pDevice->pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
28130         if (pActualAttr != NULL) {
28131             attr = *pActualAttr;
28132         }
28133
28134         pDescriptorCapture->periodCount        = attr.maxlength / attr.fragsize;
28135         pDescriptorCapture->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / pDescriptorCapture->periodCount;
28136
28137         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Capture actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorCapture->periodSizeInFrames);
28138
28139 #if 0
28140         /* Name. */
28141         devCapture = ((ma_pa_stream_get_device_name_proc)pDevice->pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
28142         if (devCapture != NULL) {
28143             ma_pa_operation* pOP = ((ma_pa_context_get_source_info_by_name_proc)pDevice->pContext->pulse.pa_context_get_source_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devCapture, ma_device_source_name_callback, pDevice);
28144             ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP);
28145         }
28146 #endif
28147     }
28148
28149     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
28150         result = ma_context_get_sink_info__pulse(pDevice->pContext, devPlayback, &sinkInfo);
28151         if (result != MA_SUCCESS) {
28152             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device.");
28153             goto on_error2;
28154         }
28155
28156         ss   = sinkInfo.sample_spec;
28157         cmap = sinkInfo.channel_map;
28158
28159         if (ma_format_from_pulse(ss.format) == ma_format_unknown) {
28160             if (ma_is_little_endian()) {
28161                 ss.format = MA_PA_SAMPLE_FLOAT32LE;
28162             } else {
28163                 ss.format = MA_PA_SAMPLE_FLOAT32BE;
28164             }
28165             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.format not supported by miniaudio. Defaulting to PA_SAMPLE_RATE_FLOAT32\n");
28166         }
28167         if (ss.rate == 0) {
28168             ss.rate = MA_DEFAULT_SAMPLE_RATE;
28169             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.rate = 0. Defaulting to %d\n", ss.rate);
28170         }
28171         if (ss.channels == 0) {
28172             ss.channels = MA_DEFAULT_CHANNELS;
28173             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] WARNING: sample_spec.channels = 0. Defaulting to %d\n", ss.channels);
28174         }
28175
28176         /* We now have enough information to calculate the actual buffer size in frames. */
28177         pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, ss.rate, pConfig->performanceProfile);
28178
28179         attr = ma_device__pa_buffer_attr_new(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->periodCount, &ss);
28180
28181         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[PulseAudio] Playback attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; periodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDescriptorPlayback->periodSizeInFrames);
28182
28183         pDevice->pulse.pStreamPlayback = ma_device__pa_stream_new__pulse(pDevice, pConfig->pulse.pStreamNamePlayback, &ss, &cmap);
28184         if (pDevice->pulse.pStreamPlayback == NULL) {
28185             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream.");
28186             result = MA_ERROR;
28187             goto on_error2;
28188         }
28189
28190
28191         /*
28192         Note that this callback will be fired as soon as the stream is connected, even though it's started as corked. The callback needs to handle a
28193         device state of ma_device_state_uninitialized.
28194         */
28195         ((ma_pa_stream_set_write_callback_proc)pDevice->pContext->pulse.pa_stream_set_write_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_write__pulse, pDevice);
28196
28197         /* State callback for checking when the device has been corked. */
28198         ((ma_pa_stream_set_suspended_callback_proc)pDevice->pContext->pulse.pa_stream_set_suspended_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_suspended__pulse, pDevice);
28199
28200         /* Rerouting notification. */
28201         ((ma_pa_stream_set_moved_callback_proc)pDevice->pContext->pulse.pa_stream_set_moved_callback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_device_on_rerouted__pulse, pDevice);
28202
28203
28204         /* Connect after we've got all of our internal state set up. */
28205         streamFlags = MA_PA_STREAM_START_CORKED | MA_PA_STREAM_ADJUST_LATENCY | MA_PA_STREAM_FIX_FORMAT | MA_PA_STREAM_FIX_RATE | MA_PA_STREAM_FIX_CHANNELS;
28206         if (devPlayback != NULL) {
28207             streamFlags |= MA_PA_STREAM_DONT_MOVE;
28208         }
28209
28210         error = ((ma_pa_stream_connect_playback_proc)pDevice->pContext->pulse.pa_stream_connect_playback)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, devPlayback, &attr, streamFlags, NULL, NULL);
28211         if (error != MA_PA_OK) {
28212             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream.");
28213             result = ma_result_from_pulse(error);
28214             goto on_error3;
28215         }
28216
28217         result = ma_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, (ma_pa_stream*)pDevice->pulse.pStreamPlayback);
28218         if (result != MA_SUCCESS) {
28219             goto on_error3;
28220         }
28221
28222
28223         /* Internal format. */
28224         pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
28225         if (pActualSS != NULL) {
28226             ss = *pActualSS;
28227         }
28228
28229         pDescriptorPlayback->format     = ma_format_from_pulse(ss.format);
28230         pDescriptorPlayback->channels   = ss.channels;
28231         pDescriptorPlayback->sampleRate = ss.rate;
28232
28233         /* Internal channel map. */
28234         pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
28235         if (pActualCMap != NULL) {
28236             cmap = *pActualCMap;
28237         }
28238
28239         for (iChannel = 0; iChannel < pDescriptorPlayback->channels; ++iChannel) {
28240             pDescriptorPlayback->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]);
28241         }
28242
28243
28244         /* Buffer. */
28245         pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pDevice->pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
28246         if (pActualAttr != NULL) {
28247             attr = *pActualAttr;
28248         }
28249
28250         pDescriptorPlayback->periodCount        = ma_max(attr.maxlength / attr.tlength, 1);
28251         pDescriptorPlayback->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) / pDescriptorPlayback->periodCount;
28252         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[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, pDescriptorPlayback->periodSizeInFrames);
28253
28254 #if 0
28255         /* Name. */
28256         devPlayback = ((ma_pa_stream_get_device_name_proc)pDevice->pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
28257         if (devPlayback != NULL) {
28258             ma_pa_operation* pOP = ((ma_pa_context_get_sink_info_by_name_proc)pDevice->pContext->pulse.pa_context_get_sink_info_by_name)((ma_pa_context*)pDevice->pulse.pPulseContext, devPlayback, ma_device_sink_name_callback, pDevice);
28259             ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP);
28260         }
28261 #endif
28262     }
28263
28264
28265     /*
28266     We need a ring buffer for handling duplex mode. We can use the main duplex ring buffer in the main
28267     part of the ma_device struct. We cannot, however, depend on ma_device_init() initializing this for
28268     us later on because that will only do it if it's a fully asynchronous backend - i.e. the
28269     onDeviceDataLoop callback is NULL, which is not the case for PulseAudio.
28270     */
28271     if (pConfig->deviceType == ma_device_type_duplex) {
28272         ma_format rbFormat     = (format != ma_format_unknown) ? format     : pDescriptorCapture->format;
28273         ma_uint32 rbChannels   = (channels   > 0)              ? channels   : pDescriptorCapture->channels;
28274         ma_uint32 rbSampleRate = (sampleRate > 0)              ? sampleRate : pDescriptorCapture->sampleRate;
28275
28276         result = ma_duplex_rb_init(rbFormat, rbChannels, rbSampleRate, pDescriptorCapture->sampleRate, pDescriptorCapture->periodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB);
28277         if (result != MA_SUCCESS) {
28278             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize ring buffer. %s.\n", ma_result_description(result));
28279             goto on_error4;
28280         }
28281     }
28282
28283     return MA_SUCCESS;
28284
28285
28286 on_error4:
28287     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
28288         ((ma_pa_stream_disconnect_proc)pDevice->pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
28289     }
28290 on_error3:
28291     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
28292         ((ma_pa_stream_unref_proc)pDevice->pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
28293     }
28294 on_error2:
28295     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
28296         ((ma_pa_stream_disconnect_proc)pDevice->pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
28297     }
28298 on_error1:
28299     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
28300         ((ma_pa_stream_unref_proc)pDevice->pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
28301     }
28302 on_error0:
28303     return result;
28304 }
28305
28306
28307 static void ma_pulse_operation_complete_callback(ma_pa_stream* pStream, int success, void* pUserData)
28308 {
28309     ma_bool32* pIsSuccessful = (ma_bool32*)pUserData;
28310     MA_ASSERT(pIsSuccessful != NULL);
28311
28312     *pIsSuccessful = (ma_bool32)success;
28313
28314     (void)pStream; /* Unused. */
28315 }
28316
28317 static ma_result ma_device__cork_stream__pulse(ma_device* pDevice, ma_device_type deviceType, int cork)
28318 {
28319     ma_context* pContext = pDevice->pContext;
28320     ma_bool32 wasSuccessful;
28321     ma_pa_stream* pStream;
28322     ma_pa_operation* pOP;
28323     ma_result result;
28324
28325     /* This should not be called with a duplex device type. */
28326     if (deviceType == ma_device_type_duplex) {
28327         return MA_INVALID_ARGS;
28328     }
28329
28330     wasSuccessful = MA_FALSE;
28331
28332     pStream = (ma_pa_stream*)((deviceType == ma_device_type_capture) ? pDevice->pulse.pStreamCapture : pDevice->pulse.pStreamPlayback);
28333     MA_ASSERT(pStream != NULL);
28334
28335     pOP = ((ma_pa_stream_cork_proc)pContext->pulse.pa_stream_cork)(pStream, cork, ma_pulse_operation_complete_callback, &wasSuccessful);
28336     if (pOP == NULL) {
28337         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to cork PulseAudio stream.");
28338         return MA_ERROR;
28339     }
28340
28341     result = ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP);
28342     if (result != MA_SUCCESS) {
28343         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while waiting for the PulseAudio stream to cork.");
28344         return result;
28345     }
28346
28347     if (!wasSuccessful) {
28348         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to %s PulseAudio stream.", (cork) ? "stop" : "start");
28349         return MA_ERROR;
28350     }
28351
28352     return MA_SUCCESS;
28353 }
28354
28355 static ma_result ma_device_start__pulse(ma_device* pDevice)
28356 {
28357     ma_result result;
28358
28359     MA_ASSERT(pDevice != NULL);
28360
28361     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28362         result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 0);
28363         if (result != MA_SUCCESS) {
28364             return result;
28365         }
28366     }
28367
28368     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28369         /* We need to fill some data before uncorking. Not doing this will result in the write callback never getting fired. */
28370         result = ma_device_write_to_stream__pulse(pDevice, (ma_pa_stream*)(pDevice->pulse.pStreamPlayback), NULL);
28371         if (result != MA_SUCCESS) {
28372             return result; /* Failed to write data. Not sure what to do here... Just aborting. */
28373         }
28374
28375         result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 0);
28376         if (result != MA_SUCCESS) {
28377             return result;
28378         }
28379     }
28380
28381     return MA_SUCCESS;
28382 }
28383
28384 static ma_result ma_device_stop__pulse(ma_device* pDevice)
28385 {
28386     ma_result result;
28387     ma_bool32 wasSuccessful;
28388
28389     MA_ASSERT(pDevice != NULL);
28390
28391     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28392         result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 1);
28393         if (result != MA_SUCCESS) {
28394             return result;
28395         }
28396     }
28397
28398     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28399         /* The stream needs to be drained if it's a playback device. */
28400         ma_pa_operation* pOP = ((ma_pa_stream_drain_proc)pDevice->pContext->pulse.pa_stream_drain)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_pulse_operation_complete_callback, &wasSuccessful);
28401         ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP);
28402
28403         result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 1);
28404         if (result != MA_SUCCESS) {
28405             return result;
28406         }
28407     }
28408
28409     return MA_SUCCESS;
28410 }
28411
28412 static ma_result ma_device_data_loop__pulse(ma_device* pDevice)
28413 {
28414     int resultPA;
28415
28416     MA_ASSERT(pDevice != NULL);
28417
28418     /* NOTE: Don't start the device here. It'll be done at a higher level. */
28419
28420     /*
28421     All data is handled through callbacks. All we need to do is iterate over the main loop and let
28422     the callbacks deal with it.
28423     */
28424     while (ma_device_get_state(pDevice) == ma_device_state_started) {
28425         resultPA = ((ma_pa_mainloop_iterate_proc)pDevice->pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pulse.pMainLoop, 1, NULL);
28426         if (resultPA < 0) {
28427             break;
28428         }
28429     }
28430
28431     /* NOTE: Don't stop the device here. It'll be done at a higher level. */
28432     return MA_SUCCESS;
28433 }
28434
28435 static ma_result ma_device_data_loop_wakeup__pulse(ma_device* pDevice)
28436 {
28437     MA_ASSERT(pDevice != NULL);
28438
28439     ((ma_pa_mainloop_wakeup_proc)pDevice->pContext->pulse.pa_mainloop_wakeup)((ma_pa_mainloop*)pDevice->pulse.pMainLoop);
28440
28441     return MA_SUCCESS;
28442 }
28443
28444 static ma_result ma_context_uninit__pulse(ma_context* pContext)
28445 {
28446     MA_ASSERT(pContext != NULL);
28447     MA_ASSERT(pContext->backend == ma_backend_pulseaudio);
28448
28449     ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pContext->pulse.pPulseContext);
28450     ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pContext->pulse.pPulseContext);
28451     ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pContext->pulse.pMainLoop);
28452
28453     ma_free(pContext->pulse.pServerName, &pContext->allocationCallbacks);
28454     ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks);
28455
28456 #ifndef MA_NO_RUNTIME_LINKING
28457     ma_dlclose(pContext, pContext->pulse.pulseSO);
28458 #endif
28459
28460     return MA_SUCCESS;
28461 }
28462
28463 static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
28464 {
28465     ma_result result;
28466 #ifndef MA_NO_RUNTIME_LINKING
28467     const char* libpulseNames[] = {
28468         "libpulse.so",
28469         "libpulse.so.0"
28470     };
28471     size_t i;
28472
28473     for (i = 0; i < ma_countof(libpulseNames); ++i) {
28474         pContext->pulse.pulseSO = ma_dlopen(pContext, libpulseNames[i]);
28475         if (pContext->pulse.pulseSO != NULL) {
28476             break;
28477         }
28478     }
28479
28480     if (pContext->pulse.pulseSO == NULL) {
28481         return MA_NO_BACKEND;
28482     }
28483
28484     pContext->pulse.pa_mainloop_new                    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_new");
28485     pContext->pulse.pa_mainloop_free                   = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_free");
28486     pContext->pulse.pa_mainloop_quit                   = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_quit");
28487     pContext->pulse.pa_mainloop_get_api                = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_get_api");
28488     pContext->pulse.pa_mainloop_iterate                = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_iterate");
28489     pContext->pulse.pa_mainloop_wakeup                 = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_wakeup");
28490     pContext->pulse.pa_threaded_mainloop_new           = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_new");
28491     pContext->pulse.pa_threaded_mainloop_free          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_free");
28492     pContext->pulse.pa_threaded_mainloop_start         = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_start");
28493     pContext->pulse.pa_threaded_mainloop_stop          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_stop");
28494     pContext->pulse.pa_threaded_mainloop_lock          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_lock");
28495     pContext->pulse.pa_threaded_mainloop_unlock        = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_unlock");
28496     pContext->pulse.pa_threaded_mainloop_wait          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_wait");
28497     pContext->pulse.pa_threaded_mainloop_signal        = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_signal");
28498     pContext->pulse.pa_threaded_mainloop_accept        = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_accept");
28499     pContext->pulse.pa_threaded_mainloop_get_retval    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_get_retval");
28500     pContext->pulse.pa_threaded_mainloop_get_api       = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_get_api");
28501     pContext->pulse.pa_threaded_mainloop_in_thread     = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_in_thread");
28502     pContext->pulse.pa_threaded_mainloop_set_name      = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_set_name");
28503     pContext->pulse.pa_context_new                     = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_new");
28504     pContext->pulse.pa_context_unref                   = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_unref");
28505     pContext->pulse.pa_context_connect                 = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_connect");
28506     pContext->pulse.pa_context_disconnect              = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_disconnect");
28507     pContext->pulse.pa_context_set_state_callback      = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_set_state_callback");
28508     pContext->pulse.pa_context_get_state               = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_state");
28509     pContext->pulse.pa_context_get_sink_info_list      = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_list");
28510     pContext->pulse.pa_context_get_source_info_list    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_list");
28511     pContext->pulse.pa_context_get_sink_info_by_name   = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_by_name");
28512     pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_by_name");
28513     pContext->pulse.pa_operation_unref                 = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_unref");
28514     pContext->pulse.pa_operation_get_state             = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_get_state");
28515     pContext->pulse.pa_channel_map_init_extend         = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_init_extend");
28516     pContext->pulse.pa_channel_map_valid               = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_valid");
28517     pContext->pulse.pa_channel_map_compatible          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_compatible");
28518     pContext->pulse.pa_stream_new                      = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_new");
28519     pContext->pulse.pa_stream_unref                    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_unref");
28520     pContext->pulse.pa_stream_connect_playback         = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_playback");
28521     pContext->pulse.pa_stream_connect_record           = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_record");
28522     pContext->pulse.pa_stream_disconnect               = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_disconnect");
28523     pContext->pulse.pa_stream_get_state                = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_state");
28524     pContext->pulse.pa_stream_get_sample_spec          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_sample_spec");
28525     pContext->pulse.pa_stream_get_channel_map          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_channel_map");
28526     pContext->pulse.pa_stream_get_buffer_attr          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_buffer_attr");
28527     pContext->pulse.pa_stream_set_buffer_attr          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_buffer_attr");
28528     pContext->pulse.pa_stream_get_device_name          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_device_name");
28529     pContext->pulse.pa_stream_set_write_callback       = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_write_callback");
28530     pContext->pulse.pa_stream_set_read_callback        = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_read_callback");
28531     pContext->pulse.pa_stream_set_suspended_callback   = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_suspended_callback");
28532     pContext->pulse.pa_stream_set_moved_callback       = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_moved_callback");
28533     pContext->pulse.pa_stream_is_suspended             = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_suspended");
28534     pContext->pulse.pa_stream_flush                    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_flush");
28535     pContext->pulse.pa_stream_drain                    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drain");
28536     pContext->pulse.pa_stream_is_corked                = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_corked");
28537     pContext->pulse.pa_stream_cork                     = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_cork");
28538     pContext->pulse.pa_stream_trigger                  = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_trigger");
28539     pContext->pulse.pa_stream_begin_write              = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_begin_write");
28540     pContext->pulse.pa_stream_write                    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_write");
28541     pContext->pulse.pa_stream_peek                     = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_peek");
28542     pContext->pulse.pa_stream_drop                     = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drop");
28543     pContext->pulse.pa_stream_writable_size            = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_writable_size");
28544     pContext->pulse.pa_stream_readable_size            = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_readable_size");
28545 #else
28546     /* This strange assignment system is just for type safety. */
28547     ma_pa_mainloop_new_proc                    _pa_mainloop_new                   = pa_mainloop_new;
28548     ma_pa_mainloop_free_proc                   _pa_mainloop_free                  = pa_mainloop_free;
28549     ma_pa_mainloop_quit_proc                   _pa_mainloop_quit                  = pa_mainloop_quit;
28550     ma_pa_mainloop_get_api_proc                _pa_mainloop_get_api               = pa_mainloop_get_api;
28551     ma_pa_mainloop_iterate_proc                _pa_mainloop_iterate               = pa_mainloop_iterate;
28552     ma_pa_mainloop_wakeup_proc                 _pa_mainloop_wakeup                = pa_mainloop_wakeup;
28553     ma_pa_threaded_mainloop_new_proc           _pa_threaded_mainloop_new          = pa_threaded_mainloop_new;
28554     ma_pa_threaded_mainloop_free_proc          _pa_threaded_mainloop_free         = pa_threaded_mainloop_free;
28555     ma_pa_threaded_mainloop_start_proc         _pa_threaded_mainloop_start        = pa_threaded_mainloop_start;
28556     ma_pa_threaded_mainloop_stop_proc          _pa_threaded_mainloop_stop         = pa_threaded_mainloop_stop;
28557     ma_pa_threaded_mainloop_lock_proc          _pa_threaded_mainloop_lock         = pa_threaded_mainloop_lock;
28558     ma_pa_threaded_mainloop_unlock_proc        _pa_threaded_mainloop_unlock       = pa_threaded_mainloop_unlock;
28559     ma_pa_threaded_mainloop_wait_proc          _pa_threaded_mainloop_wait         = pa_threaded_mainloop_wait;
28560     ma_pa_threaded_mainloop_signal_proc        _pa_threaded_mainloop_signal       = pa_threaded_mainloop_signal;
28561     ma_pa_threaded_mainloop_accept_proc        _pa_threaded_mainloop_accept       = pa_threaded_mainloop_accept;
28562     ma_pa_threaded_mainloop_get_retval_proc    _pa_threaded_mainloop_get_retval   = pa_threaded_mainloop_get_retval;
28563     ma_pa_threaded_mainloop_get_api_proc       _pa_threaded_mainloop_get_api      = pa_threaded_mainloop_get_api;
28564     ma_pa_threaded_mainloop_in_thread_proc     _pa_threaded_mainloop_in_thread    = pa_threaded_mainloop_in_thread;
28565     ma_pa_threaded_mainloop_set_name_proc      _pa_threaded_mainloop_set_name     = pa_threaded_mainloop_set_name;
28566     ma_pa_context_new_proc                     _pa_context_new                    = pa_context_new;
28567     ma_pa_context_unref_proc                   _pa_context_unref                  = pa_context_unref;
28568     ma_pa_context_connect_proc                 _pa_context_connect                = pa_context_connect;
28569     ma_pa_context_disconnect_proc              _pa_context_disconnect             = pa_context_disconnect;
28570     ma_pa_context_set_state_callback_proc      _pa_context_set_state_callback     = pa_context_set_state_callback;
28571     ma_pa_context_get_state_proc               _pa_context_get_state              = pa_context_get_state;
28572     ma_pa_context_get_sink_info_list_proc      _pa_context_get_sink_info_list     = pa_context_get_sink_info_list;
28573     ma_pa_context_get_source_info_list_proc    _pa_context_get_source_info_list   = pa_context_get_source_info_list;
28574     ma_pa_context_get_sink_info_by_name_proc   _pa_context_get_sink_info_by_name  = pa_context_get_sink_info_by_name;
28575     ma_pa_context_get_source_info_by_name_proc _pa_context_get_source_info_by_name= pa_context_get_source_info_by_name;
28576     ma_pa_operation_unref_proc                 _pa_operation_unref                = pa_operation_unref;
28577     ma_pa_operation_get_state_proc             _pa_operation_get_state            = pa_operation_get_state;
28578     ma_pa_channel_map_init_extend_proc         _pa_channel_map_init_extend        = pa_channel_map_init_extend;
28579     ma_pa_channel_map_valid_proc               _pa_channel_map_valid              = pa_channel_map_valid;
28580     ma_pa_channel_map_compatible_proc          _pa_channel_map_compatible         = pa_channel_map_compatible;
28581     ma_pa_stream_new_proc                      _pa_stream_new                     = pa_stream_new;
28582     ma_pa_stream_unref_proc                    _pa_stream_unref                   = pa_stream_unref;
28583     ma_pa_stream_connect_playback_proc         _pa_stream_connect_playback        = pa_stream_connect_playback;
28584     ma_pa_stream_connect_record_proc           _pa_stream_connect_record          = pa_stream_connect_record;
28585     ma_pa_stream_disconnect_proc               _pa_stream_disconnect              = pa_stream_disconnect;
28586     ma_pa_stream_get_state_proc                _pa_stream_get_state               = pa_stream_get_state;
28587     ma_pa_stream_get_sample_spec_proc          _pa_stream_get_sample_spec         = pa_stream_get_sample_spec;
28588     ma_pa_stream_get_channel_map_proc          _pa_stream_get_channel_map         = pa_stream_get_channel_map;
28589     ma_pa_stream_get_buffer_attr_proc          _pa_stream_get_buffer_attr         = pa_stream_get_buffer_attr;
28590     ma_pa_stream_set_buffer_attr_proc          _pa_stream_set_buffer_attr         = pa_stream_set_buffer_attr;
28591     ma_pa_stream_get_device_name_proc          _pa_stream_get_device_name         = pa_stream_get_device_name;
28592     ma_pa_stream_set_write_callback_proc       _pa_stream_set_write_callback      = pa_stream_set_write_callback;
28593     ma_pa_stream_set_read_callback_proc        _pa_stream_set_read_callback       = pa_stream_set_read_callback;
28594     ma_pa_stream_set_suspended_callback_proc   _pa_stream_set_suspended_callback  = pa_stream_set_suspended_callback;
28595     ma_pa_stream_set_moved_callback_proc       _pa_stream_set_moved_callback      = pa_stream_set_moved_callback;
28596     ma_pa_stream_is_suspended_proc             _pa_stream_is_suspended            = pa_stream_is_suspended;
28597     ma_pa_stream_flush_proc                    _pa_stream_flush                   = pa_stream_flush;
28598     ma_pa_stream_drain_proc                    _pa_stream_drain                   = pa_stream_drain;
28599     ma_pa_stream_is_corked_proc                _pa_stream_is_corked               = pa_stream_is_corked;
28600     ma_pa_stream_cork_proc                     _pa_stream_cork                    = pa_stream_cork;
28601     ma_pa_stream_trigger_proc                  _pa_stream_trigger                 = pa_stream_trigger;
28602     ma_pa_stream_begin_write_proc              _pa_stream_begin_write             = pa_stream_begin_write;
28603     ma_pa_stream_write_proc                    _pa_stream_write                   = pa_stream_write;
28604     ma_pa_stream_peek_proc                     _pa_stream_peek                    = pa_stream_peek;
28605     ma_pa_stream_drop_proc                     _pa_stream_drop                    = pa_stream_drop;
28606     ma_pa_stream_writable_size_proc            _pa_stream_writable_size           = pa_stream_writable_size;
28607     ma_pa_stream_readable_size_proc            _pa_stream_readable_size           = pa_stream_readable_size;
28608
28609     pContext->pulse.pa_mainloop_new                    = (ma_proc)_pa_mainloop_new;
28610     pContext->pulse.pa_mainloop_free                   = (ma_proc)_pa_mainloop_free;
28611     pContext->pulse.pa_mainloop_quit                   = (ma_proc)_pa_mainloop_quit;
28612     pContext->pulse.pa_mainloop_get_api                = (ma_proc)_pa_mainloop_get_api;
28613     pContext->pulse.pa_mainloop_iterate                = (ma_proc)_pa_mainloop_iterate;
28614     pContext->pulse.pa_mainloop_wakeup                 = (ma_proc)_pa_mainloop_wakeup;
28615     pContext->pulse.pa_threaded_mainloop_new           = (ma_proc)_pa_threaded_mainloop_new;
28616     pContext->pulse.pa_threaded_mainloop_free          = (ma_proc)_pa_threaded_mainloop_free;
28617     pContext->pulse.pa_threaded_mainloop_start         = (ma_proc)_pa_threaded_mainloop_start;
28618     pContext->pulse.pa_threaded_mainloop_stop          = (ma_proc)_pa_threaded_mainloop_stop;
28619     pContext->pulse.pa_threaded_mainloop_lock          = (ma_proc)_pa_threaded_mainloop_lock;
28620     pContext->pulse.pa_threaded_mainloop_unlock        = (ma_proc)_pa_threaded_mainloop_unlock;
28621     pContext->pulse.pa_threaded_mainloop_wait          = (ma_proc)_pa_threaded_mainloop_wait;
28622     pContext->pulse.pa_threaded_mainloop_signal        = (ma_proc)_pa_threaded_mainloop_signal;
28623     pContext->pulse.pa_threaded_mainloop_accept        = (ma_proc)_pa_threaded_mainloop_accept;
28624     pContext->pulse.pa_threaded_mainloop_get_retval    = (ma_proc)_pa_threaded_mainloop_get_retval;
28625     pContext->pulse.pa_threaded_mainloop_get_api       = (ma_proc)_pa_threaded_mainloop_get_api;
28626     pContext->pulse.pa_threaded_mainloop_in_thread     = (ma_proc)_pa_threaded_mainloop_in_thread;
28627     pContext->pulse.pa_threaded_mainloop_set_name      = (ma_proc)_pa_threaded_mainloop_set_name;
28628     pContext->pulse.pa_context_new                     = (ma_proc)_pa_context_new;
28629     pContext->pulse.pa_context_unref                   = (ma_proc)_pa_context_unref;
28630     pContext->pulse.pa_context_connect                 = (ma_proc)_pa_context_connect;
28631     pContext->pulse.pa_context_disconnect              = (ma_proc)_pa_context_disconnect;
28632     pContext->pulse.pa_context_set_state_callback      = (ma_proc)_pa_context_set_state_callback;
28633     pContext->pulse.pa_context_get_state               = (ma_proc)_pa_context_get_state;
28634     pContext->pulse.pa_context_get_sink_info_list      = (ma_proc)_pa_context_get_sink_info_list;
28635     pContext->pulse.pa_context_get_source_info_list    = (ma_proc)_pa_context_get_source_info_list;
28636     pContext->pulse.pa_context_get_sink_info_by_name   = (ma_proc)_pa_context_get_sink_info_by_name;
28637     pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)_pa_context_get_source_info_by_name;
28638     pContext->pulse.pa_operation_unref                 = (ma_proc)_pa_operation_unref;
28639     pContext->pulse.pa_operation_get_state             = (ma_proc)_pa_operation_get_state;
28640     pContext->pulse.pa_channel_map_init_extend         = (ma_proc)_pa_channel_map_init_extend;
28641     pContext->pulse.pa_channel_map_valid               = (ma_proc)_pa_channel_map_valid;
28642     pContext->pulse.pa_channel_map_compatible          = (ma_proc)_pa_channel_map_compatible;
28643     pContext->pulse.pa_stream_new                      = (ma_proc)_pa_stream_new;
28644     pContext->pulse.pa_stream_unref                    = (ma_proc)_pa_stream_unref;
28645     pContext->pulse.pa_stream_connect_playback         = (ma_proc)_pa_stream_connect_playback;
28646     pContext->pulse.pa_stream_connect_record           = (ma_proc)_pa_stream_connect_record;
28647     pContext->pulse.pa_stream_disconnect               = (ma_proc)_pa_stream_disconnect;
28648     pContext->pulse.pa_stream_get_state                = (ma_proc)_pa_stream_get_state;
28649     pContext->pulse.pa_stream_get_sample_spec          = (ma_proc)_pa_stream_get_sample_spec;
28650     pContext->pulse.pa_stream_get_channel_map          = (ma_proc)_pa_stream_get_channel_map;
28651     pContext->pulse.pa_stream_get_buffer_attr          = (ma_proc)_pa_stream_get_buffer_attr;
28652     pContext->pulse.pa_stream_set_buffer_attr          = (ma_proc)_pa_stream_set_buffer_attr;
28653     pContext->pulse.pa_stream_get_device_name          = (ma_proc)_pa_stream_get_device_name;
28654     pContext->pulse.pa_stream_set_write_callback       = (ma_proc)_pa_stream_set_write_callback;
28655     pContext->pulse.pa_stream_set_read_callback        = (ma_proc)_pa_stream_set_read_callback;
28656     pContext->pulse.pa_stream_set_suspended_callback   = (ma_proc)_pa_stream_set_suspended_callback;
28657     pContext->pulse.pa_stream_set_moved_callback       = (ma_proc)_pa_stream_set_moved_callback;
28658     pContext->pulse.pa_stream_is_suspended             = (ma_proc)_pa_stream_is_suspended;
28659     pContext->pulse.pa_stream_flush                    = (ma_proc)_pa_stream_flush;
28660     pContext->pulse.pa_stream_drain                    = (ma_proc)_pa_stream_drain;
28661     pContext->pulse.pa_stream_is_corked                = (ma_proc)_pa_stream_is_corked;
28662     pContext->pulse.pa_stream_cork                     = (ma_proc)_pa_stream_cork;
28663     pContext->pulse.pa_stream_trigger                  = (ma_proc)_pa_stream_trigger;
28664     pContext->pulse.pa_stream_begin_write              = (ma_proc)_pa_stream_begin_write;
28665     pContext->pulse.pa_stream_write                    = (ma_proc)_pa_stream_write;
28666     pContext->pulse.pa_stream_peek                     = (ma_proc)_pa_stream_peek;
28667     pContext->pulse.pa_stream_drop                     = (ma_proc)_pa_stream_drop;
28668     pContext->pulse.pa_stream_writable_size            = (ma_proc)_pa_stream_writable_size;
28669     pContext->pulse.pa_stream_readable_size            = (ma_proc)_pa_stream_readable_size;
28670 #endif
28671
28672     /* We need to make a copy of the application and server names so we can pass them to the pa_context of each device. */
28673     pContext->pulse.pApplicationName = ma_copy_string(pConfig->pulse.pApplicationName, &pContext->allocationCallbacks);
28674     if (pContext->pulse.pApplicationName == NULL && pConfig->pulse.pApplicationName != NULL) {
28675         return MA_OUT_OF_MEMORY;
28676     }
28677
28678     pContext->pulse.pServerName = ma_copy_string(pConfig->pulse.pServerName, &pContext->allocationCallbacks);
28679     if (pContext->pulse.pServerName == NULL && pConfig->pulse.pServerName != NULL) {
28680         ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks);
28681         return MA_OUT_OF_MEMORY;
28682     }
28683
28684     result = ma_init_pa_mainloop_and_pa_context__pulse(pContext, pConfig->pulse.pApplicationName, pConfig->pulse.pServerName, pConfig->pulse.tryAutoSpawn, &pContext->pulse.pMainLoop, &pContext->pulse.pPulseContext);
28685     if (result != MA_SUCCESS) {
28686         ma_free(pContext->pulse.pServerName, &pContext->allocationCallbacks);
28687         ma_free(pContext->pulse.pApplicationName, &pContext->allocationCallbacks);
28688     #ifndef MA_NO_RUNTIME_LINKING
28689         ma_dlclose(pContext, pContext->pulse.pulseSO);
28690     #endif
28691         return result;
28692     }
28693
28694     /* With pa_mainloop we run a synchronous backend, but we implement our own main loop. */
28695     pCallbacks->onContextInit             = ma_context_init__pulse;
28696     pCallbacks->onContextUninit           = ma_context_uninit__pulse;
28697     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__pulse;
28698     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__pulse;
28699     pCallbacks->onDeviceInit              = ma_device_init__pulse;
28700     pCallbacks->onDeviceUninit            = ma_device_uninit__pulse;
28701     pCallbacks->onDeviceStart             = ma_device_start__pulse;
28702     pCallbacks->onDeviceStop              = ma_device_stop__pulse;
28703     pCallbacks->onDeviceRead              = NULL;   /* Not used because we're implementing onDeviceDataLoop. */
28704     pCallbacks->onDeviceWrite             = NULL;   /* Not used because we're implementing onDeviceDataLoop. */
28705     pCallbacks->onDeviceDataLoop          = ma_device_data_loop__pulse;
28706     pCallbacks->onDeviceDataLoopWakeup    = ma_device_data_loop_wakeup__pulse;
28707
28708     return MA_SUCCESS;
28709 }
28710 #endif
28711
28712
28713 /******************************************************************************
28714
28715 JACK Backend
28716
28717 ******************************************************************************/
28718 #ifdef MA_HAS_JACK
28719
28720 /* It is assumed jack.h is available when compile-time linking is being used. */
28721 #ifdef MA_NO_RUNTIME_LINKING
28722 #include <jack/jack.h>
28723
28724 typedef jack_nframes_t              ma_jack_nframes_t;
28725 typedef jack_options_t              ma_jack_options_t;
28726 typedef jack_status_t               ma_jack_status_t;
28727 typedef jack_client_t               ma_jack_client_t;
28728 typedef jack_port_t                 ma_jack_port_t;
28729 typedef JackProcessCallback         ma_JackProcessCallback;
28730 typedef JackBufferSizeCallback      ma_JackBufferSizeCallback;
28731 typedef JackShutdownCallback        ma_JackShutdownCallback;
28732 #define MA_JACK_DEFAULT_AUDIO_TYPE  JACK_DEFAULT_AUDIO_TYPE
28733 #define ma_JackNoStartServer        JackNoStartServer
28734 #define ma_JackPortIsInput          JackPortIsInput
28735 #define ma_JackPortIsOutput         JackPortIsOutput
28736 #define ma_JackPortIsPhysical       JackPortIsPhysical
28737 #else
28738 typedef ma_uint32               ma_jack_nframes_t;
28739 typedef int                     ma_jack_options_t;
28740 typedef int                     ma_jack_status_t;
28741 typedef struct ma_jack_client_t ma_jack_client_t;
28742 typedef struct ma_jack_port_t   ma_jack_port_t;
28743 typedef int  (* ma_JackProcessCallback)   (ma_jack_nframes_t nframes, void* arg);
28744 typedef int  (* ma_JackBufferSizeCallback)(ma_jack_nframes_t nframes, void* arg);
28745 typedef void (* ma_JackShutdownCallback)  (void* arg);
28746 #define MA_JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio"
28747 #define ma_JackNoStartServer       1
28748 #define ma_JackPortIsInput         1
28749 #define ma_JackPortIsOutput        2
28750 #define ma_JackPortIsPhysical      4
28751 #endif
28752
28753 typedef ma_jack_client_t* (* ma_jack_client_open_proc)             (const char* client_name, ma_jack_options_t options, ma_jack_status_t* status, ...);
28754 typedef int               (* ma_jack_client_close_proc)            (ma_jack_client_t* client);
28755 typedef int               (* ma_jack_client_name_size_proc)        (void);
28756 typedef int               (* ma_jack_set_process_callback_proc)    (ma_jack_client_t* client, ma_JackProcessCallback process_callback, void* arg);
28757 typedef int               (* ma_jack_set_buffer_size_callback_proc)(ma_jack_client_t* client, ma_JackBufferSizeCallback bufsize_callback, void* arg);
28758 typedef void              (* ma_jack_on_shutdown_proc)             (ma_jack_client_t* client, ma_JackShutdownCallback function, void* arg);
28759 typedef ma_jack_nframes_t (* ma_jack_get_sample_rate_proc)         (ma_jack_client_t* client);
28760 typedef ma_jack_nframes_t (* ma_jack_get_buffer_size_proc)         (ma_jack_client_t* client);
28761 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);
28762 typedef int               (* ma_jack_activate_proc)                (ma_jack_client_t* client);
28763 typedef int               (* ma_jack_deactivate_proc)              (ma_jack_client_t* client);
28764 typedef int               (* ma_jack_connect_proc)                 (ma_jack_client_t* client, const char* source_port, const char* destination_port);
28765 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);
28766 typedef const char*       (* ma_jack_port_name_proc)               (const ma_jack_port_t* port);
28767 typedef void*             (* ma_jack_port_get_buffer_proc)         (ma_jack_port_t* port, ma_jack_nframes_t nframes);
28768 typedef void              (* ma_jack_free_proc)                    (void* ptr);
28769
28770 static ma_result ma_context_open_client__jack(ma_context* pContext, ma_jack_client_t** ppClient)
28771 {
28772     size_t maxClientNameSize;
28773     char clientName[256];
28774     ma_jack_status_t status;
28775     ma_jack_client_t* pClient;
28776
28777     MA_ASSERT(pContext != NULL);
28778     MA_ASSERT(ppClient != NULL);
28779
28780     if (ppClient) {
28781         *ppClient = NULL;
28782     }
28783
28784     maxClientNameSize = ((ma_jack_client_name_size_proc)pContext->jack.jack_client_name_size)(); /* Includes null terminator. */
28785     ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (pContext->jack.pClientName != NULL) ? pContext->jack.pClientName : "miniaudio", (size_t)-1);
28786
28787     pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? 0 : ma_JackNoStartServer, &status, NULL);
28788     if (pClient == NULL) {
28789         return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
28790     }
28791
28792     if (ppClient) {
28793         *ppClient = pClient;
28794     }
28795
28796     return MA_SUCCESS;
28797 }
28798
28799
28800 static ma_result ma_context_enumerate_devices__jack(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
28801 {
28802     ma_bool32 cbResult = MA_TRUE;
28803
28804     MA_ASSERT(pContext != NULL);
28805     MA_ASSERT(callback != NULL);
28806
28807     /* Playback. */
28808     if (cbResult) {
28809         ma_device_info deviceInfo;
28810         MA_ZERO_OBJECT(&deviceInfo);
28811         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
28812         deviceInfo.isDefault = MA_TRUE;    /* JACK only uses default devices. */
28813         cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
28814     }
28815
28816     /* Capture. */
28817     if (cbResult) {
28818         ma_device_info deviceInfo;
28819         MA_ZERO_OBJECT(&deviceInfo);
28820         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
28821         deviceInfo.isDefault = MA_TRUE;    /* JACK only uses default devices. */
28822         cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
28823     }
28824
28825     (void)cbResult; /* For silencing a static analysis warning. */
28826
28827     return MA_SUCCESS;
28828 }
28829
28830 static ma_result ma_context_get_device_info__jack(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
28831 {
28832     ma_jack_client_t* pClient;
28833     ma_result result;
28834     const char** ppPorts;
28835
28836     MA_ASSERT(pContext != NULL);
28837
28838     if (pDeviceID != NULL && pDeviceID->jack != 0) {
28839         return MA_NO_DEVICE;   /* Don't know the device. */
28840     }
28841
28842     /* Name / Description */
28843     if (deviceType == ma_device_type_playback) {
28844         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
28845     } else {
28846         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
28847     }
28848
28849     /* Jack only uses default devices. */
28850     pDeviceInfo->isDefault = MA_TRUE;
28851
28852     /* Jack only supports f32 and has a specific channel count and sample rate. */
28853     pDeviceInfo->nativeDataFormats[0].format = ma_format_f32;
28854
28855     /* The channel count and sample rate can only be determined by opening the device. */
28856     result = ma_context_open_client__jack(pContext, &pClient);
28857     if (result != MA_SUCCESS) {
28858         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.");
28859         return result;
28860     }
28861
28862     pDeviceInfo->nativeDataFormats[0].sampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pClient);
28863     pDeviceInfo->nativeDataFormats[0].channels   = 0;
28864
28865     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));
28866     if (ppPorts == NULL) {
28867         ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient);
28868         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.");
28869         return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
28870     }
28871
28872     while (ppPorts[pDeviceInfo->nativeDataFormats[0].channels] != NULL) {
28873         pDeviceInfo->nativeDataFormats[0].channels += 1;
28874     }
28875
28876     pDeviceInfo->nativeDataFormats[0].flags = 0;
28877     pDeviceInfo->nativeDataFormatCount = 1;
28878
28879     ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
28880     ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient);
28881
28882     (void)pContext;
28883     return MA_SUCCESS;
28884 }
28885
28886
28887 static ma_result ma_device_uninit__jack(ma_device* pDevice)
28888 {
28889     ma_context* pContext;
28890
28891     MA_ASSERT(pDevice != NULL);
28892
28893     pContext = pDevice->pContext;
28894     MA_ASSERT(pContext != NULL);
28895
28896     if (pDevice->jack.pClient != NULL) {
28897         ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDevice->jack.pClient);
28898     }
28899
28900     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28901         ma_free(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks);
28902         ma_free(pDevice->jack.ppPortsCapture, &pDevice->pContext->allocationCallbacks);
28903     }
28904
28905     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28906         ma_free(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks);
28907         ma_free(pDevice->jack.ppPortsPlayback, &pDevice->pContext->allocationCallbacks);
28908     }
28909
28910     return MA_SUCCESS;
28911 }
28912
28913 static void ma_device__jack_shutdown_callback(void* pUserData)
28914 {
28915     /* JACK died. Stop the device. */
28916     ma_device* pDevice = (ma_device*)pUserData;
28917     MA_ASSERT(pDevice != NULL);
28918
28919     ma_device_stop(pDevice);
28920 }
28921
28922 static int ma_device__jack_buffer_size_callback(ma_jack_nframes_t frameCount, void* pUserData)
28923 {
28924     ma_device* pDevice = (ma_device*)pUserData;
28925     MA_ASSERT(pDevice != NULL);
28926
28927     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28928         size_t newBufferSize = frameCount * (pDevice->capture.internalChannels * ma_get_bytes_per_sample(pDevice->capture.internalFormat));
28929         float* pNewBuffer = (float*)ma_calloc(newBufferSize, &pDevice->pContext->allocationCallbacks);
28930         if (pNewBuffer == NULL) {
28931             return MA_OUT_OF_MEMORY;
28932         }
28933
28934         ma_free(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks);
28935
28936         pDevice->jack.pIntermediaryBufferCapture = pNewBuffer;
28937         pDevice->playback.internalPeriodSizeInFrames = frameCount;
28938     }
28939
28940     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28941         size_t newBufferSize = frameCount * (pDevice->playback.internalChannels * ma_get_bytes_per_sample(pDevice->playback.internalFormat));
28942         float* pNewBuffer = (float*)ma_calloc(newBufferSize, &pDevice->pContext->allocationCallbacks);
28943         if (pNewBuffer == NULL) {
28944             return MA_OUT_OF_MEMORY;
28945         }
28946
28947         ma_free(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks);
28948
28949         pDevice->jack.pIntermediaryBufferPlayback = pNewBuffer;
28950         pDevice->playback.internalPeriodSizeInFrames = frameCount;
28951     }
28952
28953     return 0;
28954 }
28955
28956 static int ma_device__jack_process_callback(ma_jack_nframes_t frameCount, void* pUserData)
28957 {
28958     ma_device* pDevice;
28959     ma_context* pContext;
28960     ma_uint32 iChannel;
28961
28962     pDevice = (ma_device*)pUserData;
28963     MA_ASSERT(pDevice != NULL);
28964
28965     pContext = pDevice->pContext;
28966     MA_ASSERT(pContext != NULL);
28967
28968     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28969         /* Channels need to be interleaved. */
28970         for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) {
28971             const float* pSrc = (const float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.ppPortsCapture[iChannel], frameCount);
28972             if (pSrc != NULL) {
28973                 float* pDst = pDevice->jack.pIntermediaryBufferCapture + iChannel;
28974                 ma_jack_nframes_t iFrame;
28975                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
28976                     *pDst = *pSrc;
28977
28978                     pDst += pDevice->capture.internalChannels;
28979                     pSrc += 1;
28980                 }
28981             }
28982         }
28983
28984         ma_device_handle_backend_data_callback(pDevice, NULL, pDevice->jack.pIntermediaryBufferCapture, frameCount);
28985     }
28986
28987     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28988         ma_device_handle_backend_data_callback(pDevice, pDevice->jack.pIntermediaryBufferPlayback, NULL, frameCount);
28989
28990         /* Channels need to be deinterleaved. */
28991         for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) {
28992             float* pDst = (float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.ppPortsPlayback[iChannel], frameCount);
28993             if (pDst != NULL) {
28994                 const float* pSrc = pDevice->jack.pIntermediaryBufferPlayback + iChannel;
28995                 ma_jack_nframes_t iFrame;
28996                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
28997                     *pDst = *pSrc;
28998
28999                     pDst += 1;
29000                     pSrc += pDevice->playback.internalChannels;
29001                 }
29002             }
29003         }
29004     }
29005
29006     return 0;
29007 }
29008
29009 static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
29010 {
29011     ma_result result;
29012     ma_uint32 periodSizeInFrames;
29013
29014     MA_ASSERT(pConfig != NULL);
29015     MA_ASSERT(pDevice != NULL);
29016
29017     if (pConfig->deviceType == ma_device_type_loopback) {
29018         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Loopback mode not supported.");
29019         return MA_DEVICE_TYPE_NOT_SUPPORTED;
29020     }
29021
29022     /* Only supporting default devices with JACK. */
29023     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->pDeviceID != NULL && pDescriptorPlayback->pDeviceID->jack != 0) ||
29024         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->pDeviceID  != NULL && pDescriptorCapture->pDeviceID->jack  != 0)) {
29025         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Only default devices are supported.");
29026         return MA_NO_DEVICE;
29027     }
29028
29029     /* No exclusive mode with the JACK backend. */
29030     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
29031         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive)) {
29032         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Exclusive mode not supported.");
29033         return MA_SHARE_MODE_NOT_SUPPORTED;
29034     }
29035
29036     /* Open the client. */
29037     result = ma_context_open_client__jack(pDevice->pContext, (ma_jack_client_t**)&pDevice->jack.pClient);
29038     if (result != MA_SUCCESS) {
29039         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.");
29040         return result;
29041     }
29042
29043     /* Callbacks. */
29044     if (((ma_jack_set_process_callback_proc)pDevice->pContext->jack.jack_set_process_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_process_callback, pDevice) != 0) {
29045         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to set process callback.");
29046         return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
29047     }
29048     if (((ma_jack_set_buffer_size_callback_proc)pDevice->pContext->jack.jack_set_buffer_size_callback)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_buffer_size_callback, pDevice) != 0) {
29049         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to set buffer size callback.");
29050         return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
29051     }
29052
29053     ((ma_jack_on_shutdown_proc)pDevice->pContext->jack.jack_on_shutdown)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_shutdown_callback, pDevice);
29054
29055
29056     /* The buffer size in frames can change. */
29057     periodSizeInFrames = ((ma_jack_get_buffer_size_proc)pDevice->pContext->jack.jack_get_buffer_size)((ma_jack_client_t*)pDevice->jack.pClient);
29058
29059     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
29060         ma_uint32 iPort;
29061         const char** ppPorts;
29062
29063         pDescriptorCapture->format     = ma_format_f32;
29064         pDescriptorCapture->channels   = 0;
29065         pDescriptorCapture->sampleRate = ((ma_jack_get_sample_rate_proc)pDevice->pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient);
29066         ma_channel_map_init_standard(ma_standard_channel_map_alsa, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap), pDescriptorCapture->channels);
29067
29068         ppPorts = ((ma_jack_get_ports_proc)pDevice->pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsOutput);
29069         if (ppPorts == NULL) {
29070             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.");
29071             return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
29072         }
29073
29074         /* Need to count the number of ports first so we can allocate some memory. */
29075         while (ppPorts[pDescriptorCapture->channels] != NULL) {
29076             pDescriptorCapture->channels += 1;
29077         }
29078
29079         pDevice->jack.ppPortsCapture = (ma_ptr*)ma_malloc(sizeof(*pDevice->jack.ppPortsCapture) * pDescriptorCapture->channels, &pDevice->pContext->allocationCallbacks);
29080         if (pDevice->jack.ppPortsCapture == NULL) {
29081             return MA_OUT_OF_MEMORY;
29082         }
29083
29084         for (iPort = 0; iPort < pDescriptorCapture->channels; iPort += 1) {
29085             char name[64];
29086             ma_strcpy_s(name, sizeof(name), "capture");
29087             ma_itoa_s((int)iPort, name+7, sizeof(name)-7, 10); /* 7 = length of "capture" */
29088
29089             pDevice->jack.ppPortsCapture[iPort] = ((ma_jack_port_register_proc)pDevice->pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsInput, 0);
29090             if (pDevice->jack.ppPortsCapture[iPort] == NULL) {
29091                 ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts);
29092                 ma_device_uninit__jack(pDevice);
29093                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.");
29094                 return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
29095             }
29096         }
29097
29098         ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts);
29099
29100         pDescriptorCapture->periodSizeInFrames = periodSizeInFrames;
29101         pDescriptorCapture->periodCount        = 1; /* There's no notion of a period in JACK. Just set to 1. */
29102
29103         pDevice->jack.pIntermediaryBufferCapture = (float*)ma_calloc(pDescriptorCapture->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels), &pDevice->pContext->allocationCallbacks);
29104         if (pDevice->jack.pIntermediaryBufferCapture == NULL) {
29105             ma_device_uninit__jack(pDevice);
29106             return MA_OUT_OF_MEMORY;
29107         }
29108     }
29109
29110     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
29111         ma_uint32 iPort;
29112         const char** ppPorts;
29113
29114         pDescriptorPlayback->format     = ma_format_f32;
29115         pDescriptorPlayback->channels   = 0;
29116         pDescriptorPlayback->sampleRate = ((ma_jack_get_sample_rate_proc)pDevice->pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient);
29117         ma_channel_map_init_standard(ma_standard_channel_map_alsa, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels);
29118
29119         ppPorts = ((ma_jack_get_ports_proc)pDevice->pContext->jack.jack_get_ports)((ma_jack_client_t*)pDevice->jack.pClient, NULL, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsPhysical | ma_JackPortIsInput);
29120         if (ppPorts == NULL) {
29121             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.");
29122             return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
29123         }
29124
29125         /* Need to count the number of ports first so we can allocate some memory. */
29126         while (ppPorts[pDescriptorPlayback->channels] != NULL) {
29127             pDescriptorPlayback->channels += 1;
29128         }
29129
29130         pDevice->jack.ppPortsPlayback = (ma_ptr*)ma_malloc(sizeof(*pDevice->jack.ppPortsPlayback) * pDescriptorPlayback->channels, &pDevice->pContext->allocationCallbacks);
29131         if (pDevice->jack.ppPortsPlayback == NULL) {
29132             ma_free(pDevice->jack.ppPortsCapture, &pDevice->pContext->allocationCallbacks);
29133             return MA_OUT_OF_MEMORY;
29134         }
29135
29136         for (iPort = 0; iPort < pDescriptorPlayback->channels; iPort += 1) {
29137             char name[64];
29138             ma_strcpy_s(name, sizeof(name), "playback");
29139             ma_itoa_s((int)iPort, name+8, sizeof(name)-8, 10); /* 8 = length of "playback" */
29140
29141             pDevice->jack.ppPortsPlayback[iPort] = ((ma_jack_port_register_proc)pDevice->pContext->jack.jack_port_register)((ma_jack_client_t*)pDevice->jack.pClient, name, MA_JACK_DEFAULT_AUDIO_TYPE, ma_JackPortIsOutput, 0);
29142             if (pDevice->jack.ppPortsPlayback[iPort] == NULL) {
29143                 ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts);
29144                 ma_device_uninit__jack(pDevice);
29145                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.");
29146                 return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
29147             }
29148         }
29149
29150         ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts);
29151
29152         pDescriptorPlayback->periodSizeInFrames = periodSizeInFrames;
29153         pDescriptorPlayback->periodCount        = 1;   /* There's no notion of a period in JACK. Just set to 1. */
29154
29155         pDevice->jack.pIntermediaryBufferPlayback = (float*)ma_calloc(pDescriptorPlayback->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels), &pDevice->pContext->allocationCallbacks);
29156         if (pDevice->jack.pIntermediaryBufferPlayback == NULL) {
29157             ma_device_uninit__jack(pDevice);
29158             return MA_OUT_OF_MEMORY;
29159         }
29160     }
29161
29162     return MA_SUCCESS;
29163 }
29164
29165
29166 static ma_result ma_device_start__jack(ma_device* pDevice)
29167 {
29168     ma_context* pContext = pDevice->pContext;
29169     int resultJACK;
29170     size_t i;
29171
29172     resultJACK = ((ma_jack_activate_proc)pContext->jack.jack_activate)((ma_jack_client_t*)pDevice->jack.pClient);
29173     if (resultJACK != 0) {
29174         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to activate the JACK client.");
29175         return MA_FAILED_TO_START_BACKEND_DEVICE;
29176     }
29177
29178     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
29179         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);
29180         if (ppServerPorts == NULL) {
29181             ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
29182             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.");
29183             return MA_ERROR;
29184         }
29185
29186         for (i = 0; ppServerPorts[i] != NULL; ++i) {
29187             const char* pServerPort = ppServerPorts[i];
29188             const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.ppPortsCapture[i]);
29189
29190             resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pServerPort, pClientPort);
29191             if (resultJACK != 0) {
29192                 ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
29193                 ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
29194                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.");
29195                 return MA_ERROR;
29196             }
29197         }
29198
29199         ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
29200     }
29201
29202     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
29203         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);
29204         if (ppServerPorts == NULL) {
29205             ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
29206             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.");
29207             return MA_ERROR;
29208         }
29209
29210         for (i = 0; ppServerPorts[i] != NULL; ++i) {
29211             const char* pServerPort = ppServerPorts[i];
29212             const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.ppPortsPlayback[i]);
29213
29214             resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pClientPort, pServerPort);
29215             if (resultJACK != 0) {
29216                 ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
29217                 ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
29218                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.");
29219                 return MA_ERROR;
29220             }
29221         }
29222
29223         ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
29224     }
29225
29226     return MA_SUCCESS;
29227 }
29228
29229 static ma_result ma_device_stop__jack(ma_device* pDevice)
29230 {
29231     ma_context* pContext = pDevice->pContext;
29232
29233     if (((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient) != 0) {
29234         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[JACK] An error occurred when deactivating the JACK client.");
29235         return MA_ERROR;
29236     }
29237
29238     ma_device__on_notification_stopped(pDevice);
29239
29240     return MA_SUCCESS;
29241 }
29242
29243
29244 static ma_result ma_context_uninit__jack(ma_context* pContext)
29245 {
29246     MA_ASSERT(pContext != NULL);
29247     MA_ASSERT(pContext->backend == ma_backend_jack);
29248
29249     ma_free(pContext->jack.pClientName, &pContext->allocationCallbacks);
29250     pContext->jack.pClientName = NULL;
29251
29252 #ifndef MA_NO_RUNTIME_LINKING
29253     ma_dlclose(pContext, pContext->jack.jackSO);
29254 #endif
29255
29256     return MA_SUCCESS;
29257 }
29258
29259 static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
29260 {
29261 #ifndef MA_NO_RUNTIME_LINKING
29262     const char* libjackNames[] = {
29263 #ifdef MA_WIN32
29264         "libjack.dll",
29265         "libjack64.dll"
29266 #else
29267         "libjack.so",
29268         "libjack.so.0"
29269 #endif
29270     };
29271     size_t i;
29272
29273     for (i = 0; i < ma_countof(libjackNames); ++i) {
29274         pContext->jack.jackSO = ma_dlopen(pContext, libjackNames[i]);
29275         if (pContext->jack.jackSO != NULL) {
29276             break;
29277         }
29278     }
29279
29280     if (pContext->jack.jackSO == NULL) {
29281         return MA_NO_BACKEND;
29282     }
29283
29284     pContext->jack.jack_client_open              = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_open");
29285     pContext->jack.jack_client_close             = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_close");
29286     pContext->jack.jack_client_name_size         = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_name_size");
29287     pContext->jack.jack_set_process_callback     = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_process_callback");
29288     pContext->jack.jack_set_buffer_size_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_buffer_size_callback");
29289     pContext->jack.jack_on_shutdown              = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_on_shutdown");
29290     pContext->jack.jack_get_sample_rate          = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_sample_rate");
29291     pContext->jack.jack_get_buffer_size          = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_buffer_size");
29292     pContext->jack.jack_get_ports                = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_ports");
29293     pContext->jack.jack_activate                 = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_activate");
29294     pContext->jack.jack_deactivate               = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_deactivate");
29295     pContext->jack.jack_connect                  = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_connect");
29296     pContext->jack.jack_port_register            = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_register");
29297     pContext->jack.jack_port_name                = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_name");
29298     pContext->jack.jack_port_get_buffer          = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_get_buffer");
29299     pContext->jack.jack_free                     = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_free");
29300 #else
29301     /*
29302     This strange assignment system is here just to ensure type safety of miniaudio's function pointer
29303     types. If anything differs slightly the compiler should throw a warning.
29304     */
29305     ma_jack_client_open_proc              _jack_client_open              = jack_client_open;
29306     ma_jack_client_close_proc             _jack_client_close             = jack_client_close;
29307     ma_jack_client_name_size_proc         _jack_client_name_size         = jack_client_name_size;
29308     ma_jack_set_process_callback_proc     _jack_set_process_callback     = jack_set_process_callback;
29309     ma_jack_set_buffer_size_callback_proc _jack_set_buffer_size_callback = jack_set_buffer_size_callback;
29310     ma_jack_on_shutdown_proc              _jack_on_shutdown              = jack_on_shutdown;
29311     ma_jack_get_sample_rate_proc          _jack_get_sample_rate          = jack_get_sample_rate;
29312     ma_jack_get_buffer_size_proc          _jack_get_buffer_size          = jack_get_buffer_size;
29313     ma_jack_get_ports_proc                _jack_get_ports                = jack_get_ports;
29314     ma_jack_activate_proc                 _jack_activate                 = jack_activate;
29315     ma_jack_deactivate_proc               _jack_deactivate               = jack_deactivate;
29316     ma_jack_connect_proc                  _jack_connect                  = jack_connect;
29317     ma_jack_port_register_proc            _jack_port_register            = jack_port_register;
29318     ma_jack_port_name_proc                _jack_port_name                = jack_port_name;
29319     ma_jack_port_get_buffer_proc          _jack_port_get_buffer          = jack_port_get_buffer;
29320     ma_jack_free_proc                     _jack_free                     = jack_free;
29321
29322     pContext->jack.jack_client_open              = (ma_proc)_jack_client_open;
29323     pContext->jack.jack_client_close             = (ma_proc)_jack_client_close;
29324     pContext->jack.jack_client_name_size         = (ma_proc)_jack_client_name_size;
29325     pContext->jack.jack_set_process_callback     = (ma_proc)_jack_set_process_callback;
29326     pContext->jack.jack_set_buffer_size_callback = (ma_proc)_jack_set_buffer_size_callback;
29327     pContext->jack.jack_on_shutdown              = (ma_proc)_jack_on_shutdown;
29328     pContext->jack.jack_get_sample_rate          = (ma_proc)_jack_get_sample_rate;
29329     pContext->jack.jack_get_buffer_size          = (ma_proc)_jack_get_buffer_size;
29330     pContext->jack.jack_get_ports                = (ma_proc)_jack_get_ports;
29331     pContext->jack.jack_activate                 = (ma_proc)_jack_activate;
29332     pContext->jack.jack_deactivate               = (ma_proc)_jack_deactivate;
29333     pContext->jack.jack_connect                  = (ma_proc)_jack_connect;
29334     pContext->jack.jack_port_register            = (ma_proc)_jack_port_register;
29335     pContext->jack.jack_port_name                = (ma_proc)_jack_port_name;
29336     pContext->jack.jack_port_get_buffer          = (ma_proc)_jack_port_get_buffer;
29337     pContext->jack.jack_free                     = (ma_proc)_jack_free;
29338 #endif
29339
29340     if (pConfig->jack.pClientName != NULL) {
29341         pContext->jack.pClientName = ma_copy_string(pConfig->jack.pClientName, &pContext->allocationCallbacks);
29342     }
29343     pContext->jack.tryStartServer = pConfig->jack.tryStartServer;
29344
29345     /*
29346     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
29347     a temporary client.
29348     */
29349     {
29350         ma_jack_client_t* pDummyClient;
29351         ma_result result = ma_context_open_client__jack(pContext, &pDummyClient);
29352         if (result != MA_SUCCESS) {
29353             ma_free(pContext->jack.pClientName, &pContext->allocationCallbacks);
29354         #ifndef MA_NO_RUNTIME_LINKING
29355             ma_dlclose(pContext, pContext->jack.jackSO);
29356         #endif
29357             return MA_NO_BACKEND;
29358         }
29359
29360         ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDummyClient);
29361     }
29362
29363
29364     pCallbacks->onContextInit             = ma_context_init__jack;
29365     pCallbacks->onContextUninit           = ma_context_uninit__jack;
29366     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__jack;
29367     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__jack;
29368     pCallbacks->onDeviceInit              = ma_device_init__jack;
29369     pCallbacks->onDeviceUninit            = ma_device_uninit__jack;
29370     pCallbacks->onDeviceStart             = ma_device_start__jack;
29371     pCallbacks->onDeviceStop              = ma_device_stop__jack;
29372     pCallbacks->onDeviceRead              = NULL;   /* Not used because JACK is asynchronous. */
29373     pCallbacks->onDeviceWrite             = NULL;   /* Not used because JACK is asynchronous. */
29374     pCallbacks->onDeviceDataLoop          = NULL;   /* Not used because JACK is asynchronous. */
29375
29376     return MA_SUCCESS;
29377 }
29378 #endif  /* JACK */
29379
29380
29381
29382 /******************************************************************************
29383
29384 Core Audio Backend
29385
29386 References
29387 ==========
29388 - Technical Note TN2091: Device input using the HAL Output Audio Unit
29389     https://developer.apple.com/library/archive/technotes/tn2091/_index.html
29390
29391 ******************************************************************************/
29392 #ifdef MA_HAS_COREAUDIO
29393 #include <TargetConditionals.h>
29394
29395 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1
29396     #define MA_APPLE_MOBILE
29397     #if defined(TARGET_OS_TV) && TARGET_OS_TV == 1
29398         #define MA_APPLE_TV
29399     #endif
29400     #if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
29401         #define MA_APPLE_WATCH
29402     #endif
29403     #if __has_feature(objc_arc)
29404         #define MA_BRIDGE_TRANSFER  __bridge_transfer
29405         #define MA_BRIDGE_RETAINED  __bridge_retained
29406     #else
29407         #define MA_BRIDGE_TRANSFER
29408         #define MA_BRIDGE_RETAINED
29409     #endif
29410 #else
29411     #define MA_APPLE_DESKTOP
29412 #endif
29413
29414 #if defined(MA_APPLE_DESKTOP)
29415 #include <CoreAudio/CoreAudio.h>
29416 #else
29417 #include <AVFoundation/AVFoundation.h>
29418 #endif
29419
29420 #include <AudioToolbox/AudioToolbox.h>
29421
29422 /* CoreFoundation */
29423 typedef Boolean (* ma_CFStringGetCString_proc)(CFStringRef theString, char* buffer, CFIndex bufferSize, CFStringEncoding encoding);
29424 typedef void (* ma_CFRelease_proc)(CFTypeRef cf);
29425
29426 /* CoreAudio */
29427 #if defined(MA_APPLE_DESKTOP)
29428 typedef OSStatus (* ma_AudioObjectGetPropertyData_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* ioDataSize, void* outData);
29429 typedef OSStatus (* ma_AudioObjectGetPropertyDataSize_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize);
29430 typedef OSStatus (* ma_AudioObjectSetPropertyData_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData);
29431 typedef OSStatus (* ma_AudioObjectAddPropertyListener_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, AudioObjectPropertyListenerProc inListener, void* inClientData);
29432 typedef OSStatus (* ma_AudioObjectRemovePropertyListener_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, AudioObjectPropertyListenerProc inListener, void* inClientData);
29433 #endif
29434
29435 /* AudioToolbox */
29436 typedef AudioComponent (* ma_AudioComponentFindNext_proc)(AudioComponent inComponent, const AudioComponentDescription* inDesc);
29437 typedef OSStatus (* ma_AudioComponentInstanceDispose_proc)(AudioComponentInstance inInstance);
29438 typedef OSStatus (* ma_AudioComponentInstanceNew_proc)(AudioComponent inComponent, AudioComponentInstance* outInstance);
29439 typedef OSStatus (* ma_AudioOutputUnitStart_proc)(AudioUnit inUnit);
29440 typedef OSStatus (* ma_AudioOutputUnitStop_proc)(AudioUnit inUnit);
29441 typedef OSStatus (* ma_AudioUnitAddPropertyListener_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitPropertyListenerProc inProc, void* inProcUserData);
29442 typedef OSStatus (* ma_AudioUnitGetPropertyInfo_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32* outDataSize, Boolean* outWriteable);
29443 typedef OSStatus (* ma_AudioUnitGetProperty_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData, UInt32* ioDataSize);
29444 typedef OSStatus (* ma_AudioUnitSetProperty_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void* inData, UInt32 inDataSize);
29445 typedef OSStatus (* ma_AudioUnitInitialize_proc)(AudioUnit inUnit);
29446 typedef OSStatus (* ma_AudioUnitRender_proc)(AudioUnit inUnit, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData);
29447
29448
29449 #define MA_COREAUDIO_OUTPUT_BUS    0
29450 #define MA_COREAUDIO_INPUT_BUS     1
29451
29452 #if defined(MA_APPLE_DESKTOP)
29453 static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_device_type deviceType, ma_bool32 disposePreviousAudioUnit);
29454 #endif
29455
29456 /*
29457 Core Audio
29458
29459 So far, Core Audio has been the worst backend to work with due to being both unintuitive and having almost no documentation
29460 apart from comments in the headers (which admittedly are quite good). For my own purposes, and for anybody out there whose
29461 needing to figure out how this darn thing works, I'm going to outline a few things here.
29462
29463 Since miniaudio is a fairly low-level API, one of the things it needs is control over specific devices, and it needs to be
29464 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
29465 that supports this level of detail. There was some public domain sample code I stumbled across that used the AudioComponent
29466 and AudioUnit APIs, but I couldn't see anything that gave low-level control over device selection and capabilities (the
29467 distinction between playback and capture in particular). Therefore, miniaudio is using the AudioObject API.
29468
29469 Most (all?) functions in the AudioObject API take a AudioObjectID as it's input. This is the device identifier. When
29470 retrieving global information, such as the device list, you use kAudioObjectSystemObject. When retrieving device-specific
29471 data, you pass in the ID for that device. In order to retrieve device-specific IDs you need to enumerate over each of the
29472 devices. This is done using the AudioObjectGetPropertyDataSize() and AudioObjectGetPropertyData() APIs which seem to be
29473 the central APIs for retrieving information about the system and specific devices.
29474
29475 To use the AudioObjectGetPropertyData() API you need to use the notion of a property address. A property address is a
29476 structure with three variables and is used to identify which property you are getting or setting. The first is the "selector"
29477 which is basically the specific property that you're wanting to retrieve or set. The second is the "scope", which is
29478 typically set to kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyScopeInput for input-specific properties and
29479 kAudioObjectPropertyScopeOutput for output-specific properties. The last is the "element" which is always set to
29480 kAudioObjectPropertyElementMaster in miniaudio's case. I don't know of any cases where this would be set to anything different.
29481
29482 Back to the earlier issue of device retrieval, you first use the AudioObjectGetPropertyDataSize() API to retrieve the size
29483 of the raw data which is just a list of AudioDeviceID's. You use the kAudioObjectSystemObject AudioObjectID, and a property
29484 address with the kAudioHardwarePropertyDevices selector and the kAudioObjectPropertyScopeGlobal scope. Once you have the
29485 size, allocate a block of memory of that size and then call AudioObjectGetPropertyData(). The data is just a list of
29486 AudioDeviceID's so just do "dataSize/sizeof(AudioDeviceID)" to know the device count.
29487 */
29488
29489 static ma_result ma_result_from_OSStatus(OSStatus status)
29490 {
29491     switch (status)
29492     {
29493         case noErr:                                   return MA_SUCCESS;
29494     #if defined(MA_APPLE_DESKTOP)
29495         case kAudioHardwareNotRunningError:           return MA_DEVICE_NOT_STARTED;
29496         case kAudioHardwareUnspecifiedError:          return MA_ERROR;
29497         case kAudioHardwareUnknownPropertyError:      return MA_INVALID_ARGS;
29498         case kAudioHardwareBadPropertySizeError:      return MA_INVALID_OPERATION;
29499         case kAudioHardwareIllegalOperationError:     return MA_INVALID_OPERATION;
29500         case kAudioHardwareBadObjectError:            return MA_INVALID_ARGS;
29501         case kAudioHardwareBadDeviceError:            return MA_INVALID_ARGS;
29502         case kAudioHardwareBadStreamError:            return MA_INVALID_ARGS;
29503         case kAudioHardwareUnsupportedOperationError: return MA_INVALID_OPERATION;
29504         case kAudioDeviceUnsupportedFormatError:      return MA_FORMAT_NOT_SUPPORTED;
29505         case kAudioDevicePermissionsError:            return MA_ACCESS_DENIED;
29506     #endif
29507         default:                                      return MA_ERROR;
29508     }
29509 }
29510
29511 #if 0
29512 static ma_channel ma_channel_from_AudioChannelBitmap(AudioChannelBitmap bit)
29513 {
29514     switch (bit)
29515     {
29516         case kAudioChannelBit_Left:                 return MA_CHANNEL_LEFT;
29517         case kAudioChannelBit_Right:                return MA_CHANNEL_RIGHT;
29518         case kAudioChannelBit_Center:               return MA_CHANNEL_FRONT_CENTER;
29519         case kAudioChannelBit_LFEScreen:            return MA_CHANNEL_LFE;
29520         case kAudioChannelBit_LeftSurround:         return MA_CHANNEL_BACK_LEFT;
29521         case kAudioChannelBit_RightSurround:        return MA_CHANNEL_BACK_RIGHT;
29522         case kAudioChannelBit_LeftCenter:           return MA_CHANNEL_FRONT_LEFT_CENTER;
29523         case kAudioChannelBit_RightCenter:          return MA_CHANNEL_FRONT_RIGHT_CENTER;
29524         case kAudioChannelBit_CenterSurround:       return MA_CHANNEL_BACK_CENTER;
29525         case kAudioChannelBit_LeftSurroundDirect:   return MA_CHANNEL_SIDE_LEFT;
29526         case kAudioChannelBit_RightSurroundDirect:  return MA_CHANNEL_SIDE_RIGHT;
29527         case kAudioChannelBit_TopCenterSurround:    return MA_CHANNEL_TOP_CENTER;
29528         case kAudioChannelBit_VerticalHeightLeft:   return MA_CHANNEL_TOP_FRONT_LEFT;
29529         case kAudioChannelBit_VerticalHeightCenter: return MA_CHANNEL_TOP_FRONT_CENTER;
29530         case kAudioChannelBit_VerticalHeightRight:  return MA_CHANNEL_TOP_FRONT_RIGHT;
29531         case kAudioChannelBit_TopBackLeft:          return MA_CHANNEL_TOP_BACK_LEFT;
29532         case kAudioChannelBit_TopBackCenter:        return MA_CHANNEL_TOP_BACK_CENTER;
29533         case kAudioChannelBit_TopBackRight:         return MA_CHANNEL_TOP_BACK_RIGHT;
29534         default:                                    return MA_CHANNEL_NONE;
29535     }
29536 }
29537 #endif
29538
29539 static ma_result ma_format_from_AudioStreamBasicDescription(const AudioStreamBasicDescription* pDescription, ma_format* pFormatOut)
29540 {
29541     MA_ASSERT(pDescription != NULL);
29542     MA_ASSERT(pFormatOut != NULL);
29543
29544     *pFormatOut = ma_format_unknown;   /* Safety. */
29545
29546     /* There's a few things miniaudio doesn't support. */
29547     if (pDescription->mFormatID != kAudioFormatLinearPCM) {
29548         return MA_FORMAT_NOT_SUPPORTED;
29549     }
29550
29551     /* We don't support any non-packed formats that are aligned high. */
29552     if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) != 0) {
29553         return MA_FORMAT_NOT_SUPPORTED;
29554     }
29555
29556     /* Only supporting native-endian. */
29557     if ((ma_is_little_endian() && (pDescription->mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) || (ma_is_big_endian() && (pDescription->mFormatFlags & kAudioFormatFlagIsBigEndian) == 0)) {
29558         return MA_FORMAT_NOT_SUPPORTED;
29559     }
29560
29561     /* We are not currently supporting non-interleaved formats (this will be added in a future version of miniaudio). */
29562     /*if ((pDescription->mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0) {
29563         return MA_FORMAT_NOT_SUPPORTED;
29564     }*/
29565
29566     if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0) {
29567         if (pDescription->mBitsPerChannel == 32) {
29568             *pFormatOut = ma_format_f32;
29569             return MA_SUCCESS;
29570         }
29571     } else {
29572         if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) != 0) {
29573             if (pDescription->mBitsPerChannel == 16) {
29574                 *pFormatOut = ma_format_s16;
29575                 return MA_SUCCESS;
29576             } else if (pDescription->mBitsPerChannel == 24) {
29577                 if (pDescription->mBytesPerFrame == (pDescription->mBitsPerChannel/8 * pDescription->mChannelsPerFrame)) {
29578                     *pFormatOut = ma_format_s24;
29579                     return MA_SUCCESS;
29580                 } else {
29581                     if (pDescription->mBytesPerFrame/pDescription->mChannelsPerFrame == sizeof(ma_int32)) {
29582                         /* TODO: Implement ma_format_s24_32. */
29583                         /**pFormatOut = ma_format_s24_32;*/
29584                         /*return MA_SUCCESS;*/
29585                         return MA_FORMAT_NOT_SUPPORTED;
29586                     }
29587                 }
29588             } else if (pDescription->mBitsPerChannel == 32) {
29589                 *pFormatOut = ma_format_s32;
29590                 return MA_SUCCESS;
29591             }
29592         } else {
29593             if (pDescription->mBitsPerChannel == 8) {
29594                 *pFormatOut = ma_format_u8;
29595                 return MA_SUCCESS;
29596             }
29597         }
29598     }
29599
29600     /* Getting here means the format is not supported. */
29601     return MA_FORMAT_NOT_SUPPORTED;
29602 }
29603
29604 #if defined(MA_APPLE_DESKTOP)
29605 static ma_channel ma_channel_from_AudioChannelLabel(AudioChannelLabel label)
29606 {
29607     switch (label)
29608     {
29609         case kAudioChannelLabel_Unknown:              return MA_CHANNEL_NONE;
29610         case kAudioChannelLabel_Unused:               return MA_CHANNEL_NONE;
29611         case kAudioChannelLabel_UseCoordinates:       return MA_CHANNEL_NONE;
29612         case kAudioChannelLabel_Left:                 return MA_CHANNEL_LEFT;
29613         case kAudioChannelLabel_Right:                return MA_CHANNEL_RIGHT;
29614         case kAudioChannelLabel_Center:               return MA_CHANNEL_FRONT_CENTER;
29615         case kAudioChannelLabel_LFEScreen:            return MA_CHANNEL_LFE;
29616         case kAudioChannelLabel_LeftSurround:         return MA_CHANNEL_BACK_LEFT;
29617         case kAudioChannelLabel_RightSurround:        return MA_CHANNEL_BACK_RIGHT;
29618         case kAudioChannelLabel_LeftCenter:           return MA_CHANNEL_FRONT_LEFT_CENTER;
29619         case kAudioChannelLabel_RightCenter:          return MA_CHANNEL_FRONT_RIGHT_CENTER;
29620         case kAudioChannelLabel_CenterSurround:       return MA_CHANNEL_BACK_CENTER;
29621         case kAudioChannelLabel_LeftSurroundDirect:   return MA_CHANNEL_SIDE_LEFT;
29622         case kAudioChannelLabel_RightSurroundDirect:  return MA_CHANNEL_SIDE_RIGHT;
29623         case kAudioChannelLabel_TopCenterSurround:    return MA_CHANNEL_TOP_CENTER;
29624         case kAudioChannelLabel_VerticalHeightLeft:   return MA_CHANNEL_TOP_FRONT_LEFT;
29625         case kAudioChannelLabel_VerticalHeightCenter: return MA_CHANNEL_TOP_FRONT_CENTER;
29626         case kAudioChannelLabel_VerticalHeightRight:  return MA_CHANNEL_TOP_FRONT_RIGHT;
29627         case kAudioChannelLabel_TopBackLeft:          return MA_CHANNEL_TOP_BACK_LEFT;
29628         case kAudioChannelLabel_TopBackCenter:        return MA_CHANNEL_TOP_BACK_CENTER;
29629         case kAudioChannelLabel_TopBackRight:         return MA_CHANNEL_TOP_BACK_RIGHT;
29630         case kAudioChannelLabel_RearSurroundLeft:     return MA_CHANNEL_BACK_LEFT;
29631         case kAudioChannelLabel_RearSurroundRight:    return MA_CHANNEL_BACK_RIGHT;
29632         case kAudioChannelLabel_LeftWide:             return MA_CHANNEL_SIDE_LEFT;
29633         case kAudioChannelLabel_RightWide:            return MA_CHANNEL_SIDE_RIGHT;
29634         case kAudioChannelLabel_LFE2:                 return MA_CHANNEL_LFE;
29635         case kAudioChannelLabel_LeftTotal:            return MA_CHANNEL_LEFT;
29636         case kAudioChannelLabel_RightTotal:           return MA_CHANNEL_RIGHT;
29637         case kAudioChannelLabel_HearingImpaired:      return MA_CHANNEL_NONE;
29638         case kAudioChannelLabel_Narration:            return MA_CHANNEL_MONO;
29639         case kAudioChannelLabel_Mono:                 return MA_CHANNEL_MONO;
29640         case kAudioChannelLabel_DialogCentricMix:     return MA_CHANNEL_MONO;
29641         case kAudioChannelLabel_CenterSurroundDirect: return MA_CHANNEL_BACK_CENTER;
29642         case kAudioChannelLabel_Haptic:               return MA_CHANNEL_NONE;
29643         case kAudioChannelLabel_Ambisonic_W:          return MA_CHANNEL_NONE;
29644         case kAudioChannelLabel_Ambisonic_X:          return MA_CHANNEL_NONE;
29645         case kAudioChannelLabel_Ambisonic_Y:          return MA_CHANNEL_NONE;
29646         case kAudioChannelLabel_Ambisonic_Z:          return MA_CHANNEL_NONE;
29647         case kAudioChannelLabel_MS_Mid:               return MA_CHANNEL_LEFT;
29648         case kAudioChannelLabel_MS_Side:              return MA_CHANNEL_RIGHT;
29649         case kAudioChannelLabel_XY_X:                 return MA_CHANNEL_LEFT;
29650         case kAudioChannelLabel_XY_Y:                 return MA_CHANNEL_RIGHT;
29651         case kAudioChannelLabel_HeadphonesLeft:       return MA_CHANNEL_LEFT;
29652         case kAudioChannelLabel_HeadphonesRight:      return MA_CHANNEL_RIGHT;
29653         case kAudioChannelLabel_ClickTrack:           return MA_CHANNEL_NONE;
29654         case kAudioChannelLabel_ForeignLanguage:      return MA_CHANNEL_NONE;
29655         case kAudioChannelLabel_Discrete:             return MA_CHANNEL_NONE;
29656         case kAudioChannelLabel_Discrete_0:           return MA_CHANNEL_AUX_0;
29657         case kAudioChannelLabel_Discrete_1:           return MA_CHANNEL_AUX_1;
29658         case kAudioChannelLabel_Discrete_2:           return MA_CHANNEL_AUX_2;
29659         case kAudioChannelLabel_Discrete_3:           return MA_CHANNEL_AUX_3;
29660         case kAudioChannelLabel_Discrete_4:           return MA_CHANNEL_AUX_4;
29661         case kAudioChannelLabel_Discrete_5:           return MA_CHANNEL_AUX_5;
29662         case kAudioChannelLabel_Discrete_6:           return MA_CHANNEL_AUX_6;
29663         case kAudioChannelLabel_Discrete_7:           return MA_CHANNEL_AUX_7;
29664         case kAudioChannelLabel_Discrete_8:           return MA_CHANNEL_AUX_8;
29665         case kAudioChannelLabel_Discrete_9:           return MA_CHANNEL_AUX_9;
29666         case kAudioChannelLabel_Discrete_10:          return MA_CHANNEL_AUX_10;
29667         case kAudioChannelLabel_Discrete_11:          return MA_CHANNEL_AUX_11;
29668         case kAudioChannelLabel_Discrete_12:          return MA_CHANNEL_AUX_12;
29669         case kAudioChannelLabel_Discrete_13:          return MA_CHANNEL_AUX_13;
29670         case kAudioChannelLabel_Discrete_14:          return MA_CHANNEL_AUX_14;
29671         case kAudioChannelLabel_Discrete_15:          return MA_CHANNEL_AUX_15;
29672         case kAudioChannelLabel_Discrete_65535:       return MA_CHANNEL_NONE;
29673
29674     #if 0   /* Introduced in a later version of macOS. */
29675         case kAudioChannelLabel_HOA_ACN:              return MA_CHANNEL_NONE;
29676         case kAudioChannelLabel_HOA_ACN_0:            return MA_CHANNEL_AUX_0;
29677         case kAudioChannelLabel_HOA_ACN_1:            return MA_CHANNEL_AUX_1;
29678         case kAudioChannelLabel_HOA_ACN_2:            return MA_CHANNEL_AUX_2;
29679         case kAudioChannelLabel_HOA_ACN_3:            return MA_CHANNEL_AUX_3;
29680         case kAudioChannelLabel_HOA_ACN_4:            return MA_CHANNEL_AUX_4;
29681         case kAudioChannelLabel_HOA_ACN_5:            return MA_CHANNEL_AUX_5;
29682         case kAudioChannelLabel_HOA_ACN_6:            return MA_CHANNEL_AUX_6;
29683         case kAudioChannelLabel_HOA_ACN_7:            return MA_CHANNEL_AUX_7;
29684         case kAudioChannelLabel_HOA_ACN_8:            return MA_CHANNEL_AUX_8;
29685         case kAudioChannelLabel_HOA_ACN_9:            return MA_CHANNEL_AUX_9;
29686         case kAudioChannelLabel_HOA_ACN_10:           return MA_CHANNEL_AUX_10;
29687         case kAudioChannelLabel_HOA_ACN_11:           return MA_CHANNEL_AUX_11;
29688         case kAudioChannelLabel_HOA_ACN_12:           return MA_CHANNEL_AUX_12;
29689         case kAudioChannelLabel_HOA_ACN_13:           return MA_CHANNEL_AUX_13;
29690         case kAudioChannelLabel_HOA_ACN_14:           return MA_CHANNEL_AUX_14;
29691         case kAudioChannelLabel_HOA_ACN_15:           return MA_CHANNEL_AUX_15;
29692         case kAudioChannelLabel_HOA_ACN_65024:        return MA_CHANNEL_NONE;
29693     #endif
29694
29695         default:                                      return MA_CHANNEL_NONE;
29696     }
29697 }
29698
29699 static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* pChannelLayout, ma_channel* pChannelMap, size_t channelMapCap)
29700 {
29701     MA_ASSERT(pChannelLayout != NULL);
29702
29703     if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
29704         UInt32 iChannel;
29705         for (iChannel = 0; iChannel < pChannelLayout->mNumberChannelDescriptions && iChannel < channelMapCap; ++iChannel) {
29706             pChannelMap[iChannel] = ma_channel_from_AudioChannelLabel(pChannelLayout->mChannelDescriptions[iChannel].mChannelLabel);
29707         }
29708     } else
29709 #if 0
29710     if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {
29711         /* This is the same kind of system that's used by Windows audio APIs. */
29712         UInt32 iChannel = 0;
29713         UInt32 iBit;
29714         AudioChannelBitmap bitmap = pChannelLayout->mChannelBitmap;
29715         for (iBit = 0; iBit < 32 && iChannel < channelMapCap; ++iBit) {
29716             AudioChannelBitmap bit = bitmap & (1 << iBit);
29717             if (bit != 0) {
29718                 pChannelMap[iChannel++] = ma_channel_from_AudioChannelBit(bit);
29719             }
29720         }
29721     } else
29722 #endif
29723     {
29724         /*
29725         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
29726         be updated to determine the mapping based on the tag.
29727         */
29728         UInt32 channelCount;
29729
29730         /* Our channel map retrieval APIs below take 32-bit integers, so we'll want to clamp the channel map capacity. */
29731         if (channelMapCap > 0xFFFFFFFF) {
29732             channelMapCap = 0xFFFFFFFF;
29733         }
29734
29735         channelCount = ma_min(AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag), (UInt32)channelMapCap);
29736
29737         switch (pChannelLayout->mChannelLayoutTag)
29738         {
29739             case kAudioChannelLayoutTag_Mono:
29740             case kAudioChannelLayoutTag_Stereo:
29741             case kAudioChannelLayoutTag_StereoHeadphones:
29742             case kAudioChannelLayoutTag_MatrixStereo:
29743             case kAudioChannelLayoutTag_MidSide:
29744             case kAudioChannelLayoutTag_XY:
29745             case kAudioChannelLayoutTag_Binaural:
29746             case kAudioChannelLayoutTag_Ambisonic_B_Format:
29747             {
29748                 ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channelCount);
29749             } break;
29750
29751             case kAudioChannelLayoutTag_Octagonal:
29752             {
29753                 pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
29754                 pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
29755             } /* Intentional fallthrough. */
29756             case kAudioChannelLayoutTag_Hexagonal:
29757             {
29758                 pChannelMap[5] = MA_CHANNEL_BACK_CENTER;
29759             } /* Intentional fallthrough. */
29760             case kAudioChannelLayoutTag_Pentagonal:
29761             {
29762                 pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
29763             } /* Intentional fallghrough. */
29764             case kAudioChannelLayoutTag_Quadraphonic:
29765             {
29766                 pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
29767                 pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
29768                 pChannelMap[1] = MA_CHANNEL_RIGHT;
29769                 pChannelMap[0] = MA_CHANNEL_LEFT;
29770             } break;
29771
29772             /* TODO: Add support for more tags here. */
29773
29774             default:
29775             {
29776                 ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channelCount);
29777             } break;
29778         }
29779     }
29780
29781     return MA_SUCCESS;
29782 }
29783
29784 static ma_result ma_get_device_object_ids__coreaudio(ma_context* pContext, UInt32* pDeviceCount, AudioObjectID** ppDeviceObjectIDs) /* NOTE: Free the returned buffer with ma_free(). */
29785 {
29786     AudioObjectPropertyAddress propAddressDevices;
29787     UInt32 deviceObjectsDataSize;
29788     OSStatus status;
29789     AudioObjectID* pDeviceObjectIDs;
29790
29791     MA_ASSERT(pContext != NULL);
29792     MA_ASSERT(pDeviceCount != NULL);
29793     MA_ASSERT(ppDeviceObjectIDs != NULL);
29794
29795     /* Safety. */
29796     *pDeviceCount = 0;
29797     *ppDeviceObjectIDs = NULL;
29798
29799     propAddressDevices.mSelector = kAudioHardwarePropertyDevices;
29800     propAddressDevices.mScope    = kAudioObjectPropertyScopeGlobal;
29801     propAddressDevices.mElement  = kAudioObjectPropertyElementMaster;
29802
29803     status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(kAudioObjectSystemObject, &propAddressDevices, 0, NULL, &deviceObjectsDataSize);
29804     if (status != noErr) {
29805         return ma_result_from_OSStatus(status);
29806     }
29807
29808     pDeviceObjectIDs = (AudioObjectID*)ma_malloc(deviceObjectsDataSize, &pContext->allocationCallbacks);
29809     if (pDeviceObjectIDs == NULL) {
29810         return MA_OUT_OF_MEMORY;
29811     }
29812
29813     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject, &propAddressDevices, 0, NULL, &deviceObjectsDataSize, pDeviceObjectIDs);
29814     if (status != noErr) {
29815         ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
29816         return ma_result_from_OSStatus(status);
29817     }
29818
29819     *pDeviceCount = deviceObjectsDataSize / sizeof(AudioObjectID);
29820     *ppDeviceObjectIDs = pDeviceObjectIDs;
29821
29822     return MA_SUCCESS;
29823 }
29824
29825 static ma_result ma_get_AudioObject_uid_as_CFStringRef(ma_context* pContext, AudioObjectID objectID, CFStringRef* pUID)
29826 {
29827     AudioObjectPropertyAddress propAddress;
29828     UInt32 dataSize;
29829     OSStatus status;
29830
29831     MA_ASSERT(pContext != NULL);
29832
29833     propAddress.mSelector = kAudioDevicePropertyDeviceUID;
29834     propAddress.mScope    = kAudioObjectPropertyScopeGlobal;
29835     propAddress.mElement  = kAudioObjectPropertyElementMaster;
29836
29837     dataSize = sizeof(*pUID);
29838     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, pUID);
29839     if (status != noErr) {
29840         return ma_result_from_OSStatus(status);
29841     }
29842
29843     return MA_SUCCESS;
29844 }
29845
29846 static ma_result ma_get_AudioObject_uid(ma_context* pContext, AudioObjectID objectID, size_t bufferSize, char* bufferOut)
29847 {
29848     CFStringRef uid;
29849     ma_result result;
29850
29851     MA_ASSERT(pContext != NULL);
29852
29853     result = ma_get_AudioObject_uid_as_CFStringRef(pContext, objectID, &uid);
29854     if (result != MA_SUCCESS) {
29855         return result;
29856     }
29857
29858     if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(uid, bufferOut, bufferSize, kCFStringEncodingUTF8)) {
29859         return MA_ERROR;
29860     }
29861
29862     ((ma_CFRelease_proc)pContext->coreaudio.CFRelease)(uid);
29863     return MA_SUCCESS;
29864 }
29865
29866 static ma_result ma_get_AudioObject_name(ma_context* pContext, AudioObjectID objectID, size_t bufferSize, char* bufferOut)
29867 {
29868     AudioObjectPropertyAddress propAddress;
29869     CFStringRef deviceName = NULL;
29870     UInt32 dataSize;
29871     OSStatus status;
29872
29873     MA_ASSERT(pContext != NULL);
29874
29875     propAddress.mSelector = kAudioDevicePropertyDeviceNameCFString;
29876     propAddress.mScope    = kAudioObjectPropertyScopeGlobal;
29877     propAddress.mElement  = kAudioObjectPropertyElementMaster;
29878
29879     dataSize = sizeof(deviceName);
29880     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, &deviceName);
29881     if (status != noErr) {
29882         return ma_result_from_OSStatus(status);
29883     }
29884
29885     if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(deviceName, bufferOut, bufferSize, kCFStringEncodingUTF8)) {
29886         return MA_ERROR;
29887     }
29888
29889     ((ma_CFRelease_proc)pContext->coreaudio.CFRelease)(deviceName);
29890     return MA_SUCCESS;
29891 }
29892
29893 static ma_bool32 ma_does_AudioObject_support_scope(ma_context* pContext, AudioObjectID deviceObjectID, AudioObjectPropertyScope scope)
29894 {
29895     AudioObjectPropertyAddress propAddress;
29896     UInt32 dataSize;
29897     OSStatus status;
29898     AudioBufferList* pBufferList;
29899     ma_bool32 isSupported;
29900
29901     MA_ASSERT(pContext != NULL);
29902
29903     /* 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. */
29904     propAddress.mSelector = kAudioDevicePropertyStreamConfiguration;
29905     propAddress.mScope    = scope;
29906     propAddress.mElement  = kAudioObjectPropertyElementMaster;
29907
29908     status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
29909     if (status != noErr) {
29910         return MA_FALSE;
29911     }
29912
29913     pBufferList = (AudioBufferList*)ma_malloc(dataSize, &pContext->allocationCallbacks);
29914     if (pBufferList == NULL) {
29915         return MA_FALSE;   /* Out of memory. */
29916     }
29917
29918     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pBufferList);
29919     if (status != noErr) {
29920         ma_free(pBufferList, &pContext->allocationCallbacks);
29921         return MA_FALSE;
29922     }
29923
29924     isSupported = MA_FALSE;
29925     if (pBufferList->mNumberBuffers > 0) {
29926         isSupported = MA_TRUE;
29927     }
29928
29929     ma_free(pBufferList, &pContext->allocationCallbacks);
29930     return isSupported;
29931 }
29932
29933 static ma_bool32 ma_does_AudioObject_support_playback(ma_context* pContext, AudioObjectID deviceObjectID)
29934 {
29935     return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeOutput);
29936 }
29937
29938 static ma_bool32 ma_does_AudioObject_support_capture(ma_context* pContext, AudioObjectID deviceObjectID)
29939 {
29940     return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeInput);
29941 }
29942
29943
29944 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(). */
29945 {
29946     AudioObjectPropertyAddress propAddress;
29947     UInt32 dataSize;
29948     OSStatus status;
29949     AudioStreamRangedDescription* pDescriptions;
29950
29951     MA_ASSERT(pContext != NULL);
29952     MA_ASSERT(pDescriptionCount != NULL);
29953     MA_ASSERT(ppDescriptions != NULL);
29954
29955     /*
29956     TODO: Experiment with kAudioStreamPropertyAvailablePhysicalFormats instead of (or in addition to) kAudioStreamPropertyAvailableVirtualFormats. My
29957           MacBook Pro uses s24/32 format, however, which miniaudio does not currently support.
29958     */
29959     propAddress.mSelector = kAudioStreamPropertyAvailableVirtualFormats; /*kAudioStreamPropertyAvailablePhysicalFormats;*/
29960     propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
29961     propAddress.mElement  = kAudioObjectPropertyElementMaster;
29962
29963     status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
29964     if (status != noErr) {
29965         return ma_result_from_OSStatus(status);
29966     }
29967
29968     pDescriptions = (AudioStreamRangedDescription*)ma_malloc(dataSize, &pContext->allocationCallbacks);
29969     if (pDescriptions == NULL) {
29970         return MA_OUT_OF_MEMORY;
29971     }
29972
29973     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pDescriptions);
29974     if (status != noErr) {
29975         ma_free(pDescriptions, &pContext->allocationCallbacks);
29976         return ma_result_from_OSStatus(status);
29977     }
29978
29979     *pDescriptionCount = dataSize / sizeof(*pDescriptions);
29980     *ppDescriptions = pDescriptions;
29981     return MA_SUCCESS;
29982 }
29983
29984
29985 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(). */
29986 {
29987     AudioObjectPropertyAddress propAddress;
29988     UInt32 dataSize;
29989     OSStatus status;
29990     AudioChannelLayout* pChannelLayout;
29991
29992     MA_ASSERT(pContext != NULL);
29993     MA_ASSERT(ppChannelLayout != NULL);
29994
29995     *ppChannelLayout = NULL;    /* Safety. */
29996
29997     propAddress.mSelector = kAudioDevicePropertyPreferredChannelLayout;
29998     propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
29999     propAddress.mElement  = kAudioObjectPropertyElementMaster;
30000
30001     status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
30002     if (status != noErr) {
30003         return ma_result_from_OSStatus(status);
30004     }
30005
30006     pChannelLayout = (AudioChannelLayout*)ma_malloc(dataSize, &pContext->allocationCallbacks);
30007     if (pChannelLayout == NULL) {
30008         return MA_OUT_OF_MEMORY;
30009     }
30010
30011     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pChannelLayout);
30012     if (status != noErr) {
30013         ma_free(pChannelLayout, &pContext->allocationCallbacks);
30014         return ma_result_from_OSStatus(status);
30015     }
30016
30017     *ppChannelLayout = pChannelLayout;
30018     return MA_SUCCESS;
30019 }
30020
30021 static ma_result ma_get_AudioObject_channel_count(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32* pChannelCount)
30022 {
30023     AudioChannelLayout* pChannelLayout;
30024     ma_result result;
30025
30026     MA_ASSERT(pContext != NULL);
30027     MA_ASSERT(pChannelCount != NULL);
30028
30029     *pChannelCount = 0; /* Safety. */
30030
30031     result = ma_get_AudioObject_channel_layout(pContext, deviceObjectID, deviceType, &pChannelLayout);
30032     if (result != MA_SUCCESS) {
30033         return result;
30034     }
30035
30036     if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
30037         *pChannelCount = pChannelLayout->mNumberChannelDescriptions;
30038     } else if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {
30039         *pChannelCount = ma_count_set_bits(pChannelLayout->mChannelBitmap);
30040     } else {
30041         *pChannelCount = AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag);
30042     }
30043
30044     ma_free(pChannelLayout, &pContext->allocationCallbacks);
30045     return MA_SUCCESS;
30046 }
30047
30048 #if 0
30049 static ma_result ma_get_AudioObject_channel_map(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_channel* pChannelMap, size_t channelMapCap)
30050 {
30051     AudioChannelLayout* pChannelLayout;
30052     ma_result result;
30053
30054     MA_ASSERT(pContext != NULL);
30055
30056     result = ma_get_AudioObject_channel_layout(pContext, deviceObjectID, deviceType, &pChannelLayout);
30057     if (result != MA_SUCCESS) {
30058         return result;  /* Rather than always failing here, would it be more robust to simply assume a default? */
30059     }
30060
30061     result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, pChannelMap, channelMapCap);
30062     if (result != MA_SUCCESS) {
30063         ma_free(pChannelLayout, &pContext->allocationCallbacks);
30064         return result;
30065     }
30066
30067     ma_free(pChannelLayout, &pContext->allocationCallbacks);
30068     return result;
30069 }
30070 #endif
30071
30072 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(). */
30073 {
30074     AudioObjectPropertyAddress propAddress;
30075     UInt32 dataSize;
30076     OSStatus status;
30077     AudioValueRange* pSampleRateRanges;
30078
30079     MA_ASSERT(pContext != NULL);
30080     MA_ASSERT(pSampleRateRangesCount != NULL);
30081     MA_ASSERT(ppSampleRateRanges != NULL);
30082
30083     /* Safety. */
30084     *pSampleRateRangesCount = 0;
30085     *ppSampleRateRanges = NULL;
30086
30087     propAddress.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
30088     propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
30089     propAddress.mElement  = kAudioObjectPropertyElementMaster;
30090
30091     status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
30092     if (status != noErr) {
30093         return ma_result_from_OSStatus(status);
30094     }
30095
30096     pSampleRateRanges = (AudioValueRange*)ma_malloc(dataSize, &pContext->allocationCallbacks);
30097     if (pSampleRateRanges == NULL) {
30098         return MA_OUT_OF_MEMORY;
30099     }
30100
30101     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pSampleRateRanges);
30102     if (status != noErr) {
30103         ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
30104         return ma_result_from_OSStatus(status);
30105     }
30106
30107     *pSampleRateRangesCount = dataSize / sizeof(*pSampleRateRanges);
30108     *ppSampleRateRanges = pSampleRateRanges;
30109     return MA_SUCCESS;
30110 }
30111
30112 #if 0
30113 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)
30114 {
30115     UInt32 sampleRateRangeCount;
30116     AudioValueRange* pSampleRateRanges;
30117     ma_result result;
30118
30119     MA_ASSERT(pContext != NULL);
30120     MA_ASSERT(pSampleRateOut != NULL);
30121
30122     *pSampleRateOut = 0;    /* Safety. */
30123
30124     result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges);
30125     if (result != MA_SUCCESS) {
30126         return result;
30127     }
30128
30129     if (sampleRateRangeCount == 0) {
30130         ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
30131         return MA_ERROR;   /* Should never hit this case should we? */
30132     }
30133
30134     if (sampleRateIn == 0) {
30135         /* Search in order of miniaudio's preferred priority. */
30136         UInt32 iMALSampleRate;
30137         for (iMALSampleRate = 0; iMALSampleRate < ma_countof(g_maStandardSampleRatePriorities); ++iMALSampleRate) {
30138             ma_uint32 malSampleRate = g_maStandardSampleRatePriorities[iMALSampleRate];
30139             UInt32 iCASampleRate;
30140             for (iCASampleRate = 0; iCASampleRate < sampleRateRangeCount; ++iCASampleRate) {
30141                 AudioValueRange caSampleRate = pSampleRateRanges[iCASampleRate];
30142                 if (caSampleRate.mMinimum <= malSampleRate && caSampleRate.mMaximum >= malSampleRate) {
30143                     *pSampleRateOut = malSampleRate;
30144                     ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
30145                     return MA_SUCCESS;
30146                 }
30147             }
30148         }
30149
30150         /*
30151         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
30152         case we just fall back to the first one reported by Core Audio.
30153         */
30154         MA_ASSERT(sampleRateRangeCount > 0);
30155
30156         *pSampleRateOut = pSampleRateRanges[0].mMinimum;
30157         ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
30158         return MA_SUCCESS;
30159     } else {
30160         /* Find the closest match to this sample rate. */
30161         UInt32 currentAbsoluteDifference = INT32_MAX;
30162         UInt32 iCurrentClosestRange = (UInt32)-1;
30163         UInt32 iRange;
30164         for (iRange = 0; iRange < sampleRateRangeCount; ++iRange) {
30165             if (pSampleRateRanges[iRange].mMinimum <= sampleRateIn && pSampleRateRanges[iRange].mMaximum >= sampleRateIn) {
30166                 *pSampleRateOut = sampleRateIn;
30167                 ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
30168                 return MA_SUCCESS;
30169             } else {
30170                 UInt32 absoluteDifference;
30171                 if (pSampleRateRanges[iRange].mMinimum > sampleRateIn) {
30172                     absoluteDifference = pSampleRateRanges[iRange].mMinimum - sampleRateIn;
30173                 } else {
30174                     absoluteDifference = sampleRateIn - pSampleRateRanges[iRange].mMaximum;
30175                 }
30176
30177                 if (currentAbsoluteDifference > absoluteDifference) {
30178                     currentAbsoluteDifference = absoluteDifference;
30179                     iCurrentClosestRange = iRange;
30180                 }
30181             }
30182         }
30183
30184         MA_ASSERT(iCurrentClosestRange != (UInt32)-1);
30185
30186         *pSampleRateOut = pSampleRateRanges[iCurrentClosestRange].mMinimum;
30187         ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
30188         return MA_SUCCESS;
30189     }
30190
30191     /* Should never get here, but it would mean we weren't able to find any suitable sample rates. */
30192     /*ma_free(pSampleRateRanges, &pContext->allocationCallbacks);*/
30193     /*return MA_ERROR;*/
30194 }
30195 #endif
30196
30197 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)
30198 {
30199     AudioObjectPropertyAddress propAddress;
30200     AudioValueRange bufferSizeRange;
30201     UInt32 dataSize;
30202     OSStatus status;
30203
30204     MA_ASSERT(pContext != NULL);
30205     MA_ASSERT(pBufferSizeInFramesOut != NULL);
30206
30207     *pBufferSizeInFramesOut = 0;    /* Safety. */
30208
30209     propAddress.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
30210     propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
30211     propAddress.mElement  = kAudioObjectPropertyElementMaster;
30212
30213     dataSize = sizeof(bufferSizeRange);
30214     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, &bufferSizeRange);
30215     if (status != noErr) {
30216         return ma_result_from_OSStatus(status);
30217     }
30218
30219     /* This is just a clamp. */
30220     if (bufferSizeInFramesIn < bufferSizeRange.mMinimum) {
30221         *pBufferSizeInFramesOut = (ma_uint32)bufferSizeRange.mMinimum;
30222     } else if (bufferSizeInFramesIn > bufferSizeRange.mMaximum) {
30223         *pBufferSizeInFramesOut = (ma_uint32)bufferSizeRange.mMaximum;
30224     } else {
30225         *pBufferSizeInFramesOut = bufferSizeInFramesIn;
30226     }
30227
30228     return MA_SUCCESS;
30229 }
30230
30231 static ma_result ma_set_AudioObject_buffer_size_in_frames(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32* pPeriodSizeInOut)
30232 {
30233     ma_result result;
30234     ma_uint32 chosenBufferSizeInFrames;
30235     AudioObjectPropertyAddress propAddress;
30236     UInt32 dataSize;
30237     OSStatus status;
30238
30239     MA_ASSERT(pContext != NULL);
30240
30241     result = ma_get_AudioObject_closest_buffer_size_in_frames(pContext, deviceObjectID, deviceType, *pPeriodSizeInOut, &chosenBufferSizeInFrames);
30242     if (result != MA_SUCCESS) {
30243         return result;
30244     }
30245
30246     /* Try setting the size of the buffer... If this fails we just use whatever is currently set. */
30247     propAddress.mSelector = kAudioDevicePropertyBufferFrameSize;
30248     propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
30249     propAddress.mElement  = kAudioObjectPropertyElementMaster;
30250
30251     ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(chosenBufferSizeInFrames), &chosenBufferSizeInFrames);
30252
30253     /* Get the actual size of the buffer. */
30254     dataSize = sizeof(*pPeriodSizeInOut);
30255     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, &chosenBufferSizeInFrames);
30256     if (status != noErr) {
30257         return ma_result_from_OSStatus(status);
30258     }
30259
30260     *pPeriodSizeInOut = chosenBufferSizeInFrames;
30261     return MA_SUCCESS;
30262 }
30263
30264 static ma_result ma_find_default_AudioObjectID(ma_context* pContext, ma_device_type deviceType, AudioObjectID* pDeviceObjectID)
30265 {
30266     AudioObjectPropertyAddress propAddressDefaultDevice;
30267     UInt32 defaultDeviceObjectIDSize = sizeof(AudioObjectID);
30268     AudioObjectID defaultDeviceObjectID;
30269     OSStatus status;
30270
30271     MA_ASSERT(pContext != NULL);
30272     MA_ASSERT(pDeviceObjectID != NULL);
30273
30274     /* Safety. */
30275     *pDeviceObjectID = 0;
30276
30277     propAddressDefaultDevice.mScope = kAudioObjectPropertyScopeGlobal;
30278     propAddressDefaultDevice.mElement = kAudioObjectPropertyElementMaster;
30279     if (deviceType == ma_device_type_playback) {
30280         propAddressDefaultDevice.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
30281     } else {
30282         propAddressDefaultDevice.mSelector = kAudioHardwarePropertyDefaultInputDevice;
30283     }
30284
30285     defaultDeviceObjectIDSize = sizeof(AudioObjectID);
30286     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject, &propAddressDefaultDevice, 0, NULL, &defaultDeviceObjectIDSize, &defaultDeviceObjectID);
30287     if (status == noErr) {
30288         *pDeviceObjectID = defaultDeviceObjectID;
30289         return MA_SUCCESS;
30290     }
30291
30292     /* If we get here it means we couldn't find the device. */
30293     return MA_NO_DEVICE;
30294 }
30295
30296 static ma_result ma_find_AudioObjectID(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, AudioObjectID* pDeviceObjectID)
30297 {
30298     MA_ASSERT(pContext != NULL);
30299     MA_ASSERT(pDeviceObjectID != NULL);
30300
30301     /* Safety. */
30302     *pDeviceObjectID = 0;
30303
30304     if (pDeviceID == NULL) {
30305         /* Default device. */
30306         return ma_find_default_AudioObjectID(pContext, deviceType, pDeviceObjectID);
30307     } else {
30308         /* Explicit device. */
30309         UInt32 deviceCount;
30310         AudioObjectID* pDeviceObjectIDs;
30311         ma_result result;
30312         UInt32 iDevice;
30313
30314         result = ma_get_device_object_ids__coreaudio(pContext, &deviceCount, &pDeviceObjectIDs);
30315         if (result != MA_SUCCESS) {
30316             return result;
30317         }
30318
30319         for (iDevice = 0; iDevice < deviceCount; ++iDevice) {
30320             AudioObjectID deviceObjectID = pDeviceObjectIDs[iDevice];
30321
30322             char uid[256];
30323             if (ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(uid), uid) != MA_SUCCESS) {
30324                 continue;
30325             }
30326
30327             if (deviceType == ma_device_type_playback) {
30328                 if (ma_does_AudioObject_support_playback(pContext, deviceObjectID)) {
30329                     if (strcmp(uid, pDeviceID->coreaudio) == 0) {
30330                         *pDeviceObjectID = deviceObjectID;
30331                         ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
30332                         return MA_SUCCESS;
30333                     }
30334                 }
30335             } else {
30336                 if (ma_does_AudioObject_support_capture(pContext, deviceObjectID)) {
30337                     if (strcmp(uid, pDeviceID->coreaudio) == 0) {
30338                         *pDeviceObjectID = deviceObjectID;
30339                         ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
30340                         return MA_SUCCESS;
30341                     }
30342                 }
30343             }
30344         }
30345
30346         ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
30347     }
30348
30349     /* If we get here it means we couldn't find the device. */
30350     return MA_NO_DEVICE;
30351 }
30352
30353
30354 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, const AudioStreamBasicDescription* pOrigFormat, AudioStreamBasicDescription* pFormat)
30355 {
30356     UInt32 deviceFormatDescriptionCount;
30357     AudioStreamRangedDescription* pDeviceFormatDescriptions;
30358     ma_result result;
30359     ma_uint32 desiredSampleRate;
30360     ma_uint32 desiredChannelCount;
30361     ma_format desiredFormat;
30362     AudioStreamBasicDescription bestDeviceFormatSoFar;
30363     ma_bool32 hasSupportedFormat;
30364     UInt32 iFormat;
30365
30366     result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &deviceFormatDescriptionCount, &pDeviceFormatDescriptions);
30367     if (result != MA_SUCCESS) {
30368         return result;
30369     }
30370
30371     desiredSampleRate = sampleRate;
30372     if (desiredSampleRate == 0) {
30373         desiredSampleRate = pOrigFormat->mSampleRate;
30374     }
30375
30376     desiredChannelCount = channels;
30377     if (desiredChannelCount == 0) {
30378         desiredChannelCount = pOrigFormat->mChannelsPerFrame;
30379     }
30380
30381     desiredFormat = format;
30382     if (desiredFormat == ma_format_unknown) {
30383         result = ma_format_from_AudioStreamBasicDescription(pOrigFormat, &desiredFormat);
30384         if (result != MA_SUCCESS || desiredFormat == ma_format_unknown) {
30385             desiredFormat = g_maFormatPriorities[0];
30386         }
30387     }
30388
30389     /*
30390     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
30391     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.
30392     */
30393     MA_ZERO_OBJECT(&bestDeviceFormatSoFar);
30394
30395     hasSupportedFormat = MA_FALSE;
30396     for (iFormat = 0; iFormat < deviceFormatDescriptionCount; ++iFormat) {
30397         ma_format format;
30398         ma_result formatResult = ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat, &format);
30399         if (formatResult == MA_SUCCESS && format != ma_format_unknown) {
30400             hasSupportedFormat = MA_TRUE;
30401             bestDeviceFormatSoFar = pDeviceFormatDescriptions[iFormat].mFormat;
30402             break;
30403         }
30404     }
30405
30406     if (!hasSupportedFormat) {
30407         ma_free(pDeviceFormatDescriptions, &pContext->allocationCallbacks);
30408         return MA_FORMAT_NOT_SUPPORTED;
30409     }
30410
30411
30412     for (iFormat = 0; iFormat < deviceFormatDescriptionCount; ++iFormat) {
30413         AudioStreamBasicDescription thisDeviceFormat = pDeviceFormatDescriptions[iFormat].mFormat;
30414         ma_format thisSampleFormat;
30415         ma_result formatResult;
30416         ma_format bestSampleFormatSoFar;
30417
30418         /* If the format is not supported by miniaudio we need to skip this one entirely. */
30419         formatResult = ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat, &thisSampleFormat);
30420         if (formatResult != MA_SUCCESS || thisSampleFormat == ma_format_unknown) {
30421             continue;   /* The format is not supported by miniaudio. Skip. */
30422         }
30423
30424         ma_format_from_AudioStreamBasicDescription(&bestDeviceFormatSoFar, &bestSampleFormatSoFar);
30425
30426         /* Getting here means the format is supported by miniaudio which makes this format a candidate. */
30427         if (thisDeviceFormat.mSampleRate != desiredSampleRate) {
30428             /*
30429             The sample rate does not match, but this format could still be usable, although it's a very low priority. If the best format
30430             so far has an equal sample rate we can just ignore this one.
30431             */
30432             if (bestDeviceFormatSoFar.mSampleRate == desiredSampleRate) {
30433                 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. */
30434             } else {
30435                 /* In this case, neither the best format so far nor this one have the same sample rate. Check the channel count next. */
30436                 if (thisDeviceFormat.mChannelsPerFrame != desiredChannelCount) {
30437                     /* This format has a different sample rate _and_ a different channel count. */
30438                     if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) {
30439                         continue;   /* No change to the best format. */
30440                     } else {
30441                         /*
30442                         Both this format and the best so far have different sample rates and different channel counts. Whichever has the
30443                         best format is the new best.
30444                         */
30445                         if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
30446                             bestDeviceFormatSoFar = thisDeviceFormat;
30447                             continue;
30448                         } else {
30449                             continue;   /* No change to the best format. */
30450                         }
30451                     }
30452                 } else {
30453                     /* This format has a different sample rate but the desired channel count. */
30454                     if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) {
30455                         /* Both this format and the best so far have the desired channel count. Whichever has the best format is the new best. */
30456                         if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
30457                             bestDeviceFormatSoFar = thisDeviceFormat;
30458                             continue;
30459                         } else {
30460                             continue;   /* No change to the best format for now. */
30461                         }
30462                     } else {
30463                         /* This format has the desired channel count, but the best so far does not. We have a new best. */
30464                         bestDeviceFormatSoFar = thisDeviceFormat;
30465                         continue;
30466                     }
30467                 }
30468             }
30469         } else {
30470             /*
30471             The sample rates match which makes this format a very high priority contender. If the best format so far has a different
30472             sample rate it needs to be replaced with this one.
30473             */
30474             if (bestDeviceFormatSoFar.mSampleRate != desiredSampleRate) {
30475                 bestDeviceFormatSoFar = thisDeviceFormat;
30476                 continue;
30477             } else {
30478                 /* In this case both this format and the best format so far have the same sample rate. Check the channel count next. */
30479                 if (thisDeviceFormat.mChannelsPerFrame == desiredChannelCount) {
30480                     /*
30481                     In this case this format has the same channel count as what the client is requesting. If the best format so far has
30482                     a different count, this one becomes the new best.
30483                     */
30484                     if (bestDeviceFormatSoFar.mChannelsPerFrame != desiredChannelCount) {
30485                         bestDeviceFormatSoFar = thisDeviceFormat;
30486                         continue;
30487                     } else {
30488                         /* In this case both this format and the best so far have the ideal sample rate and channel count. Check the format. */
30489                         if (thisSampleFormat == desiredFormat) {
30490                             bestDeviceFormatSoFar = thisDeviceFormat;
30491                             break;  /* Found the exact match. */
30492                         } else {
30493                             /* The formats are different. The new best format is the one with the highest priority format according to miniaudio. */
30494                             if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
30495                                 bestDeviceFormatSoFar = thisDeviceFormat;
30496                                 continue;
30497                             } else {
30498                                 continue;   /* No change to the best format for now. */
30499                             }
30500                         }
30501                     }
30502                 } else {
30503                     /*
30504                     In this case the channel count is different to what the client has requested. If the best so far has the same channel
30505                     count as the requested count then it remains the best.
30506                     */
30507                     if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) {
30508                         continue;
30509                     } else {
30510                         /*
30511                         This is the case where both have the same sample rate (good) but different channel counts. Right now both have about
30512                         the same priority, but we need to compare the format now.
30513                         */
30514                         if (thisSampleFormat == bestSampleFormatSoFar) {
30515                             if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
30516                                 bestDeviceFormatSoFar = thisDeviceFormat;
30517                                 continue;
30518                             } else {
30519                                 continue;   /* No change to the best format for now. */
30520                             }
30521                         }
30522                     }
30523                 }
30524             }
30525         }
30526     }
30527
30528     *pFormat = bestDeviceFormatSoFar;
30529
30530     ma_free(pDeviceFormatDescriptions, &pContext->allocationCallbacks);
30531     return MA_SUCCESS;
30532 }
30533
30534 static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit audioUnit, ma_device_type deviceType, ma_channel* pChannelMap, size_t channelMapCap)
30535 {
30536     AudioUnitScope deviceScope;
30537     AudioUnitElement deviceBus;
30538     UInt32 channelLayoutSize;
30539     OSStatus status;
30540     AudioChannelLayout* pChannelLayout;
30541     ma_result result;
30542
30543     MA_ASSERT(pContext != NULL);
30544
30545     if (deviceType == ma_device_type_playback) {
30546         deviceScope = kAudioUnitScope_Input;
30547         deviceBus = MA_COREAUDIO_OUTPUT_BUS;
30548     } else {
30549         deviceScope = kAudioUnitScope_Output;
30550         deviceBus = MA_COREAUDIO_INPUT_BUS;
30551     }
30552
30553     status = ((ma_AudioUnitGetPropertyInfo_proc)pContext->coreaudio.AudioUnitGetPropertyInfo)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, &channelLayoutSize, NULL);
30554     if (status != noErr) {
30555         return ma_result_from_OSStatus(status);
30556     }
30557
30558     pChannelLayout = (AudioChannelLayout*)ma_malloc(channelLayoutSize, &pContext->allocationCallbacks);
30559     if (pChannelLayout == NULL) {
30560         return MA_OUT_OF_MEMORY;
30561     }
30562
30563     status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, pChannelLayout, &channelLayoutSize);
30564     if (status != noErr) {
30565         ma_free(pChannelLayout, &pContext->allocationCallbacks);
30566         return ma_result_from_OSStatus(status);
30567     }
30568
30569     result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, pChannelMap, channelMapCap);
30570     if (result != MA_SUCCESS) {
30571         ma_free(pChannelLayout, &pContext->allocationCallbacks);
30572         return result;
30573     }
30574
30575     ma_free(pChannelLayout, &pContext->allocationCallbacks);
30576     return MA_SUCCESS;
30577 }
30578 #endif /* MA_APPLE_DESKTOP */
30579
30580
30581 #if !defined(MA_APPLE_DESKTOP)
30582 static void ma_AVAudioSessionPortDescription_to_device_info(AVAudioSessionPortDescription* pPortDesc, ma_device_info* pInfo)
30583 {
30584     MA_ZERO_OBJECT(pInfo);
30585     ma_strncpy_s(pInfo->name,         sizeof(pInfo->name),         [pPortDesc.portName UTF8String], (size_t)-1);
30586     ma_strncpy_s(pInfo->id.coreaudio, sizeof(pInfo->id.coreaudio), [pPortDesc.UID      UTF8String], (size_t)-1);
30587 }
30588 #endif
30589
30590 static ma_result ma_context_enumerate_devices__coreaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
30591 {
30592 #if defined(MA_APPLE_DESKTOP)
30593     UInt32 deviceCount;
30594     AudioObjectID* pDeviceObjectIDs;
30595     AudioObjectID defaultDeviceObjectIDPlayback;
30596     AudioObjectID defaultDeviceObjectIDCapture;
30597     ma_result result;
30598     UInt32 iDevice;
30599
30600     ma_find_default_AudioObjectID(pContext, ma_device_type_playback, &defaultDeviceObjectIDPlayback);   /* OK if this fails. */
30601     ma_find_default_AudioObjectID(pContext, ma_device_type_capture,  &defaultDeviceObjectIDCapture);    /* OK if this fails. */
30602
30603     result = ma_get_device_object_ids__coreaudio(pContext, &deviceCount, &pDeviceObjectIDs);
30604     if (result != MA_SUCCESS) {
30605         return result;
30606     }
30607
30608     for (iDevice = 0; iDevice < deviceCount; ++iDevice) {
30609         AudioObjectID deviceObjectID = pDeviceObjectIDs[iDevice];
30610         ma_device_info info;
30611
30612         MA_ZERO_OBJECT(&info);
30613         if (ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(info.id.coreaudio), info.id.coreaudio) != MA_SUCCESS) {
30614             continue;
30615         }
30616         if (ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(info.name), info.name) != MA_SUCCESS) {
30617             continue;
30618         }
30619
30620         if (ma_does_AudioObject_support_playback(pContext, deviceObjectID)) {
30621             if (deviceObjectID == defaultDeviceObjectIDPlayback) {
30622                 info.isDefault = MA_TRUE;
30623             }
30624
30625             if (!callback(pContext, ma_device_type_playback, &info, pUserData)) {
30626                 break;
30627             }
30628         }
30629         if (ma_does_AudioObject_support_capture(pContext, deviceObjectID)) {
30630             if (deviceObjectID == defaultDeviceObjectIDCapture) {
30631                 info.isDefault = MA_TRUE;
30632             }
30633
30634             if (!callback(pContext, ma_device_type_capture, &info, pUserData)) {
30635                 break;
30636             }
30637         }
30638     }
30639
30640     ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
30641 #else
30642     ma_device_info info;
30643     NSArray *pInputs  = [[[AVAudioSession sharedInstance] currentRoute] inputs];
30644     NSArray *pOutputs = [[[AVAudioSession sharedInstance] currentRoute] outputs];
30645
30646     for (AVAudioSessionPortDescription* pPortDesc in pOutputs) {
30647         ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, &info);
30648         if (!callback(pContext, ma_device_type_playback, &info, pUserData)) {
30649             return MA_SUCCESS;
30650         }
30651     }
30652
30653     for (AVAudioSessionPortDescription* pPortDesc in pInputs) {
30654         ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, &info);
30655         if (!callback(pContext, ma_device_type_capture, &info, pUserData)) {
30656             return MA_SUCCESS;
30657         }
30658     }
30659 #endif
30660
30661     return MA_SUCCESS;
30662 }
30663
30664 static ma_result ma_context_get_device_info__coreaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
30665 {
30666     ma_result result;
30667
30668     MA_ASSERT(pContext != NULL);
30669
30670 #if defined(MA_APPLE_DESKTOP)
30671     /* Desktop */
30672     {
30673         AudioObjectID deviceObjectID;
30674         AudioObjectID defaultDeviceObjectID;
30675         UInt32 streamDescriptionCount;
30676         AudioStreamRangedDescription* pStreamDescriptions;
30677         UInt32 iStreamDescription;
30678         UInt32 sampleRateRangeCount;
30679         AudioValueRange* pSampleRateRanges;
30680
30681         ma_find_default_AudioObjectID(pContext, deviceType, &defaultDeviceObjectID);     /* OK if this fails. */
30682
30683         result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID);
30684         if (result != MA_SUCCESS) {
30685             return result;
30686         }
30687
30688         result = ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(pDeviceInfo->id.coreaudio), pDeviceInfo->id.coreaudio);
30689         if (result != MA_SUCCESS) {
30690             return result;
30691         }
30692
30693         result = ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(pDeviceInfo->name), pDeviceInfo->name);
30694         if (result != MA_SUCCESS) {
30695             return result;
30696         }
30697
30698         if (deviceObjectID == defaultDeviceObjectID) {
30699             pDeviceInfo->isDefault = MA_TRUE;
30700         }
30701
30702         /*
30703         There could be a large number of permutations here. Fortunately there is only a single channel count
30704         being reported which reduces this quite a bit. For sample rates we're only reporting those that are
30705         one of miniaudio's recognized "standard" rates. If there are still more formats than can fit into
30706         our fixed sized array we'll just need to truncate them. This is unlikely and will probably only happen
30707         if some driver performs software data conversion and therefore reports every possible format and
30708         sample rate.
30709         */
30710         pDeviceInfo->nativeDataFormatCount = 0;
30711
30712         /* Formats. */
30713         {
30714             ma_format uniqueFormats[ma_format_count];
30715             ma_uint32 uniqueFormatCount = 0;
30716             ma_uint32 channels;
30717
30718             /* Channels. */
30719             result = ma_get_AudioObject_channel_count(pContext, deviceObjectID, deviceType, &channels);
30720             if (result != MA_SUCCESS) {
30721                 return result;
30722             }
30723
30724             /* Formats. */
30725             result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &streamDescriptionCount, &pStreamDescriptions);
30726             if (result != MA_SUCCESS) {
30727                 return result;
30728             }
30729
30730             for (iStreamDescription = 0; iStreamDescription < streamDescriptionCount; ++iStreamDescription) {
30731                 ma_format format;
30732                 ma_bool32 hasFormatBeenHandled = MA_FALSE;
30733                 ma_uint32 iOutputFormat;
30734                 ma_uint32 iSampleRate;
30735
30736                 result = ma_format_from_AudioStreamBasicDescription(&pStreamDescriptions[iStreamDescription].mFormat, &format);
30737                 if (result != MA_SUCCESS) {
30738                     continue;
30739                 }
30740
30741                 MA_ASSERT(format != ma_format_unknown);
30742
30743                 /* Make sure the format isn't already in the output list. */
30744                 for (iOutputFormat = 0; iOutputFormat < uniqueFormatCount; ++iOutputFormat) {
30745                     if (uniqueFormats[iOutputFormat] == format) {
30746                         hasFormatBeenHandled = MA_TRUE;
30747                         break;
30748                     }
30749                 }
30750
30751                 /* If we've already handled this format just skip it. */
30752                 if (hasFormatBeenHandled) {
30753                     continue;
30754                 }
30755
30756                 uniqueFormats[uniqueFormatCount] = format;
30757                 uniqueFormatCount += 1;
30758
30759                 /* Sample Rates */
30760                 result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges);
30761                 if (result != MA_SUCCESS) {
30762                     return result;
30763                 }
30764
30765                 /*
30766                 Annoyingly Core Audio reports a sample rate range. We just get all the standard rates that are
30767                 between this range.
30768                 */
30769                 for (iSampleRate = 0; iSampleRate < sampleRateRangeCount; ++iSampleRate) {
30770                     ma_uint32 iStandardSampleRate;
30771                     for (iStandardSampleRate = 0; iStandardSampleRate < ma_countof(g_maStandardSampleRatePriorities); iStandardSampleRate += 1) {
30772                         ma_uint32 standardSampleRate = g_maStandardSampleRatePriorities[iStandardSampleRate];
30773                         if (standardSampleRate >= pSampleRateRanges[iSampleRate].mMinimum && standardSampleRate <= pSampleRateRanges[iSampleRate].mMaximum) {
30774                             /* We have a new data format. Add it to the list. */
30775                             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = format;
30776                             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
30777                             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = standardSampleRate;
30778                             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = 0;
30779                             pDeviceInfo->nativeDataFormatCount += 1;
30780
30781                             if (pDeviceInfo->nativeDataFormatCount >= ma_countof(pDeviceInfo->nativeDataFormats)) {
30782                                 break;  /* No more room for any more formats. */
30783                             }
30784                         }
30785                     }
30786                 }
30787
30788                 ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
30789
30790                 if (pDeviceInfo->nativeDataFormatCount >= ma_countof(pDeviceInfo->nativeDataFormats)) {
30791                     break;  /* No more room for any more formats. */
30792                 }
30793             }
30794
30795             ma_free(pStreamDescriptions, &pContext->allocationCallbacks);
30796         }
30797     }
30798 #else
30799     /* Mobile */
30800     {
30801         AudioComponentDescription desc;
30802         AudioComponent component;
30803         AudioUnit audioUnit;
30804         OSStatus status;
30805         AudioUnitScope formatScope;
30806         AudioUnitElement formatElement;
30807         AudioStreamBasicDescription bestFormat;
30808         UInt32 propSize;
30809
30810         /* We want to ensure we use a consistent device name to device enumeration. */
30811         if (pDeviceID != NULL) {
30812             ma_bool32 found = MA_FALSE;
30813             if (deviceType == ma_device_type_playback) {
30814                 NSArray *pOutputs = [[[AVAudioSession sharedInstance] currentRoute] outputs];
30815                 for (AVAudioSessionPortDescription* pPortDesc in pOutputs) {
30816                     if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
30817                         ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, pDeviceInfo);
30818                         found = MA_TRUE;
30819                         break;
30820                     }
30821                 }
30822             } else {
30823                 NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs];
30824                 for (AVAudioSessionPortDescription* pPortDesc in pInputs) {
30825                     if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
30826                         ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, pDeviceInfo);
30827                         found = MA_TRUE;
30828                         break;
30829                     }
30830                 }
30831             }
30832
30833             if (!found) {
30834                 return MA_DOES_NOT_EXIST;
30835             }
30836         } else {
30837             if (deviceType == ma_device_type_playback) {
30838                 ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
30839             } else {
30840                 ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
30841             }
30842         }
30843
30844
30845         /*
30846         Retrieving device information is more annoying on mobile than desktop. For simplicity I'm locking this down to whatever format is
30847         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
30848         retrieve from the AVAudioSession shared instance.
30849         */
30850         desc.componentType = kAudioUnitType_Output;
30851         desc.componentSubType = kAudioUnitSubType_RemoteIO;
30852         desc.componentManufacturer = kAudioUnitManufacturer_Apple;
30853         desc.componentFlags = 0;
30854         desc.componentFlagsMask = 0;
30855
30856         component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc);
30857         if (component == NULL) {
30858             return MA_FAILED_TO_INIT_BACKEND;
30859         }
30860
30861         status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)(component, &audioUnit);
30862         if (status != noErr) {
30863             return ma_result_from_OSStatus(status);
30864         }
30865
30866         formatScope   = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
30867         formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;
30868
30869         propSize = sizeof(bestFormat);
30870         status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, &propSize);
30871         if (status != noErr) {
30872             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
30873             return ma_result_from_OSStatus(status);
30874         }
30875
30876         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
30877         audioUnit = NULL;
30878
30879         /* Only a single format is being reported for iOS. */
30880         pDeviceInfo->nativeDataFormatCount = 1;
30881
30882         result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pDeviceInfo->nativeDataFormats[0].format);
30883         if (result != MA_SUCCESS) {
30884             return result;
30885         }
30886
30887         pDeviceInfo->nativeDataFormats[0].channels = bestFormat.mChannelsPerFrame;
30888
30889         /*
30890         It looks like Apple are wanting to push the whole AVAudioSession thing. Thus, we need to use that to determine device settings. To do
30891         this we just get the shared instance and inspect.
30892         */
30893         @autoreleasepool {
30894             AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
30895             MA_ASSERT(pAudioSession != NULL);
30896
30897             pDeviceInfo->nativeDataFormats[0].sampleRate = (ma_uint32)pAudioSession.sampleRate;
30898         }
30899     }
30900 #endif
30901
30902     (void)pDeviceInfo; /* Unused. */
30903     return MA_SUCCESS;
30904 }
30905
30906 static AudioBufferList* ma_allocate_AudioBufferList__coreaudio(ma_uint32 sizeInFrames, ma_format format, ma_uint32 channels, ma_stream_layout layout, const ma_allocation_callbacks* pAllocationCallbacks)
30907 {
30908     AudioBufferList* pBufferList;
30909     UInt32 audioBufferSizeInBytes;
30910     size_t allocationSize;
30911
30912     MA_ASSERT(sizeInFrames > 0);
30913     MA_ASSERT(format != ma_format_unknown);
30914     MA_ASSERT(channels > 0);
30915
30916     allocationSize = sizeof(AudioBufferList) - sizeof(AudioBuffer);  /* Subtract sizeof(AudioBuffer) because that part is dynamically sized. */
30917     if (layout == ma_stream_layout_interleaved) {
30918         /* Interleaved case. This is the simple case because we just have one buffer. */
30919         allocationSize += sizeof(AudioBuffer) * 1;
30920     } else {
30921         /* Non-interleaved case. This is the more complex case because there's more than one buffer. */
30922         allocationSize += sizeof(AudioBuffer) * channels;
30923     }
30924
30925     allocationSize += sizeInFrames * ma_get_bytes_per_frame(format, channels);
30926
30927     pBufferList = (AudioBufferList*)ma_malloc(allocationSize, pAllocationCallbacks);
30928     if (pBufferList == NULL) {
30929         return NULL;
30930     }
30931
30932     audioBufferSizeInBytes = (UInt32)(sizeInFrames * ma_get_bytes_per_sample(format));
30933
30934     if (layout == ma_stream_layout_interleaved) {
30935         pBufferList->mNumberBuffers = 1;
30936         pBufferList->mBuffers[0].mNumberChannels = channels;
30937         pBufferList->mBuffers[0].mDataByteSize   = audioBufferSizeInBytes * channels;
30938         pBufferList->mBuffers[0].mData           = (ma_uint8*)pBufferList + sizeof(AudioBufferList);
30939     } else {
30940         ma_uint32 iBuffer;
30941         pBufferList->mNumberBuffers = channels;
30942         for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) {
30943             pBufferList->mBuffers[iBuffer].mNumberChannels = 1;
30944             pBufferList->mBuffers[iBuffer].mDataByteSize   = audioBufferSizeInBytes;
30945             pBufferList->mBuffers[iBuffer].mData           = (ma_uint8*)pBufferList + ((sizeof(AudioBufferList) - sizeof(AudioBuffer)) + (sizeof(AudioBuffer) * channels)) + (audioBufferSizeInBytes * iBuffer);
30946         }
30947     }
30948
30949     return pBufferList;
30950 }
30951
30952 static ma_result ma_device_realloc_AudioBufferList__coreaudio(ma_device* pDevice, ma_uint32 sizeInFrames, ma_format format, ma_uint32 channels, ma_stream_layout layout)
30953 {
30954     MA_ASSERT(pDevice != NULL);
30955     MA_ASSERT(format != ma_format_unknown);
30956     MA_ASSERT(channels > 0);
30957
30958     /* Only resize the buffer if necessary. */
30959     if (pDevice->coreaudio.audioBufferCapInFrames < sizeInFrames) {
30960         AudioBufferList* pNewAudioBufferList;
30961
30962         pNewAudioBufferList = ma_allocate_AudioBufferList__coreaudio(sizeInFrames, format, channels, layout, &pDevice->pContext->allocationCallbacks);
30963         if (pNewAudioBufferList == NULL) {
30964             return MA_OUT_OF_MEMORY;
30965         }
30966
30967         /* At this point we'll have a new AudioBufferList and we can free the old one. */
30968         ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
30969         pDevice->coreaudio.pAudioBufferList = pNewAudioBufferList;
30970         pDevice->coreaudio.audioBufferCapInFrames = sizeInFrames;
30971     }
30972
30973     /* Getting here means the capacity of the audio is fine. */
30974     return MA_SUCCESS;
30975 }
30976
30977
30978 static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFlags* pActionFlags, const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pBufferList)
30979 {
30980     ma_device* pDevice = (ma_device*)pUserData;
30981     ma_stream_layout layout;
30982
30983     MA_ASSERT(pDevice != NULL);
30984
30985     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Output Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", (int)busNumber, (int)frameCount, (int)pBufferList->mNumberBuffers);
30986
30987     /* 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. */
30988     layout = ma_stream_layout_interleaved;
30989     if (pBufferList->mBuffers[0].mNumberChannels != pDevice->playback.internalChannels) {
30990         layout = ma_stream_layout_deinterleaved;
30991     }
30992
30993     if (layout == ma_stream_layout_interleaved) {
30994         /* For now we can assume everything is interleaved. */
30995         UInt32 iBuffer;
30996         for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) {
30997             if (pBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->playback.internalChannels) {
30998                 ma_uint32 frameCountForThisBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
30999                 if (frameCountForThisBuffer > 0) {
31000                     ma_device_handle_backend_data_callback(pDevice, pBufferList->mBuffers[iBuffer].mData, NULL, frameCountForThisBuffer);
31001                 }
31002
31003                 ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "  frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pBufferList->mBuffers[iBuffer].mNumberChannels, (int)pBufferList->mBuffers[iBuffer].mDataByteSize);
31004             } else {
31005                 /*
31006                 This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's
31007                 not interleaved, in which case we can't handle right now since miniaudio does not yet support non-interleaved streams. We just
31008                 output silence here.
31009                 */
31010                 MA_ZERO_MEMORY(pBufferList->mBuffers[iBuffer].mData, pBufferList->mBuffers[iBuffer].mDataByteSize);
31011                 ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "  WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pBufferList->mBuffers[iBuffer].mNumberChannels, (int)pBufferList->mBuffers[iBuffer].mDataByteSize);
31012             }
31013         }
31014     } else {
31015         /* This is the deinterleaved case. We need to update each buffer in groups of internalChannels. This assumes each buffer is the same size. */
31016         MA_ASSERT(pDevice->playback.internalChannels <= MA_MAX_CHANNELS);   /* This should heve been validated at initialization time. */
31017
31018         /*
31019         For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something
31020         very strange has happened and we're not going to support it.
31021         */
31022         if ((pBufferList->mNumberBuffers % pDevice->playback.internalChannels) == 0) {
31023             ma_uint8 tempBuffer[4096];
31024             UInt32 iBuffer;
31025
31026             for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; iBuffer += pDevice->playback.internalChannels) {
31027                 ma_uint32 frameCountPerBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_sample(pDevice->playback.internalFormat);
31028                 ma_uint32 framesRemaining = frameCountPerBuffer;
31029
31030                 while (framesRemaining > 0) {
31031                     void* ppDeinterleavedBuffers[MA_MAX_CHANNELS];
31032                     ma_uint32 iChannel;
31033                     ma_uint32 framesToRead = sizeof(tempBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
31034                     if (framesToRead > framesRemaining) {
31035                         framesToRead = framesRemaining;
31036                     }
31037
31038                     ma_device_handle_backend_data_callback(pDevice, tempBuffer, NULL, framesToRead);
31039
31040                     for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) {
31041                         ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pBufferList->mBuffers[iBuffer+iChannel].mData, (frameCountPerBuffer - framesRemaining) * ma_get_bytes_per_sample(pDevice->playback.internalFormat));
31042                     }
31043
31044                     ma_deinterleave_pcm_frames(pDevice->playback.internalFormat, pDevice->playback.internalChannels, framesToRead, tempBuffer, ppDeinterleavedBuffers);
31045
31046                     framesRemaining -= framesToRead;
31047                 }
31048             }
31049         }
31050     }
31051
31052     (void)pActionFlags;
31053     (void)pTimeStamp;
31054     (void)busNumber;
31055     (void)frameCount;
31056
31057     return noErr;
31058 }
31059
31060 static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFlags* pActionFlags, const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pUnusedBufferList)
31061 {
31062     ma_device* pDevice = (ma_device*)pUserData;
31063     AudioBufferList* pRenderedBufferList;
31064     ma_result result;
31065     ma_stream_layout layout;
31066     ma_uint32 iBuffer;
31067     OSStatus status;
31068
31069     MA_ASSERT(pDevice != NULL);
31070
31071     pRenderedBufferList = (AudioBufferList*)pDevice->coreaudio.pAudioBufferList;
31072     MA_ASSERT(pRenderedBufferList);
31073
31074     /* 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. */
31075     layout = ma_stream_layout_interleaved;
31076     if (pRenderedBufferList->mBuffers[0].mNumberChannels != pDevice->capture.internalChannels) {
31077         layout = ma_stream_layout_deinterleaved;
31078     }
31079
31080     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "INFO: Input Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", (int)busNumber, (int)frameCount, (int)pRenderedBufferList->mNumberBuffers);
31081
31082     /*
31083     There has been a situation reported where frame count passed into this function is greater than the capacity of
31084     our capture buffer. There doesn't seem to be a reliable way to determine what the maximum frame count will be,
31085     so we need to instead resort to dynamically reallocating our buffer to ensure it's large enough to capture the
31086     number of frames requested by this callback.
31087     */
31088     result = ma_device_realloc_AudioBufferList__coreaudio(pDevice, frameCount, pDevice->capture.internalFormat, pDevice->capture.internalChannels, layout);
31089     if (result != MA_SUCCESS) {
31090         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "Failed to allocate AudioBufferList for capture.");
31091         return noErr;
31092     }
31093     
31094     pRenderedBufferList = (AudioBufferList*)pDevice->coreaudio.pAudioBufferList;
31095     MA_ASSERT(pRenderedBufferList);
31096
31097     /*
31098     When you call AudioUnitRender(), Core Audio tries to be helpful by setting the mDataByteSize to the number of bytes
31099     that were actually rendered. The problem with this is that the next call can fail with -50 due to the size no longer
31100     being set to the capacity of the buffer, but instead the size in bytes of the previous render. This will cause a
31101     problem when a future call to this callback specifies a larger number of frames.
31102
31103     To work around this we need to explicitly set the size of each buffer to their respective size in bytes.
31104     */
31105     for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) {
31106         pRenderedBufferList->mBuffers[iBuffer].mDataByteSize = pDevice->coreaudio.audioBufferCapInFrames * ma_get_bytes_per_sample(pDevice->capture.internalFormat) * pRenderedBufferList->mBuffers[iBuffer].mNumberChannels;
31107     }
31108
31109     status = ((ma_AudioUnitRender_proc)pDevice->pContext->coreaudio.AudioUnitRender)((AudioUnit)pDevice->coreaudio.audioUnitCapture, pActionFlags, pTimeStamp, busNumber, frameCount, pRenderedBufferList);
31110     if (status != noErr) {
31111         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "  ERROR: AudioUnitRender() failed with %d\n", (int)status);
31112         return status;
31113     }
31114
31115     if (layout == ma_stream_layout_interleaved) {
31116         for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) {
31117             if (pRenderedBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->capture.internalChannels) {
31118                 ma_device_handle_backend_data_callback(pDevice, NULL, pRenderedBufferList->mBuffers[iBuffer].mData, frameCount);
31119                 ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "  mDataByteSize=%d\n", (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);
31120             } else {
31121                 /*
31122                 This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's
31123                 not interleaved, in which case we can't handle right now since miniaudio does not yet support non-interleaved streams.
31124                 */
31125                 ma_uint8 silentBuffer[4096];
31126                 ma_uint32 framesRemaining;
31127
31128                 MA_ZERO_MEMORY(silentBuffer, sizeof(silentBuffer));
31129
31130                 framesRemaining = frameCount;
31131                 while (framesRemaining > 0) {
31132                     ma_uint32 framesToSend = sizeof(silentBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
31133                     if (framesToSend > framesRemaining) {
31134                         framesToSend = framesRemaining;
31135                     }
31136
31137                     ma_device_handle_backend_data_callback(pDevice, NULL, silentBuffer, framesToSend);
31138
31139                     framesRemaining -= framesToSend;
31140                 }
31141
31142                 ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "  WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pRenderedBufferList->mBuffers[iBuffer].mNumberChannels, (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);
31143             }
31144         }
31145     } else {
31146         /* 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. */
31147         MA_ASSERT(pDevice->capture.internalChannels <= MA_MAX_CHANNELS);    /* This should have been validated at initialization time. */
31148
31149         /*
31150         For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something
31151         very strange has happened and we're not going to support it.
31152         */
31153         if ((pRenderedBufferList->mNumberBuffers % pDevice->capture.internalChannels) == 0) {
31154             ma_uint8 tempBuffer[4096];
31155             for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; iBuffer += pDevice->capture.internalChannels) {
31156                 ma_uint32 framesRemaining = frameCount;
31157                 while (framesRemaining > 0) {
31158                     void* ppDeinterleavedBuffers[MA_MAX_CHANNELS];
31159                     ma_uint32 iChannel;
31160                     ma_uint32 framesToSend = sizeof(tempBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
31161                     if (framesToSend > framesRemaining) {
31162                         framesToSend = framesRemaining;
31163                     }
31164
31165                     for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) {
31166                         ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pRenderedBufferList->mBuffers[iBuffer+iChannel].mData, (frameCount - framesRemaining) * ma_get_bytes_per_sample(pDevice->capture.internalFormat));
31167                     }
31168
31169                     ma_interleave_pcm_frames(pDevice->capture.internalFormat, pDevice->capture.internalChannels, framesToSend, (const void**)ppDeinterleavedBuffers, tempBuffer);
31170                     ma_device_handle_backend_data_callback(pDevice, NULL, tempBuffer, framesToSend);
31171
31172                     framesRemaining -= framesToSend;
31173                 }
31174             }
31175         }
31176     }
31177
31178     (void)pActionFlags;
31179     (void)pTimeStamp;
31180     (void)busNumber;
31181     (void)frameCount;
31182     (void)pUnusedBufferList;
31183
31184     return noErr;
31185 }
31186
31187 static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, AudioUnitPropertyID propertyID, AudioUnitScope scope, AudioUnitElement element)
31188 {
31189     ma_device* pDevice = (ma_device*)pUserData;
31190     MA_ASSERT(pDevice != NULL);
31191
31192     /* Don't do anything if it looks like we're just reinitializing due to a device switch. */
31193     if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) ||
31194         ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isSwitchingCaptureDevice)) {
31195         return;
31196     }
31197
31198     /*
31199     There's been a report of a deadlock here when triggered by ma_device_uninit(). It looks like
31200     AudioUnitGetProprty (called below) and AudioComponentInstanceDispose (called in ma_device_uninit)
31201     can try waiting on the same lock. I'm going to try working around this by not calling any Core
31202     Audio APIs in the callback when the device has been stopped or uninitialized.
31203     */
31204     if (ma_device_get_state(pDevice) == ma_device_state_uninitialized || ma_device_get_state(pDevice) == ma_device_state_stopping || ma_device_get_state(pDevice) == ma_device_state_stopped) {
31205         ma_device__on_notification_stopped(pDevice);
31206         ma_event_signal(&pDevice->coreaudio.stopEvent);
31207     } else {
31208         UInt32 isRunning;
31209         UInt32 isRunningSize = sizeof(isRunning);
31210         OSStatus status = ((ma_AudioUnitGetProperty_proc)pDevice->pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioOutputUnitProperty_IsRunning, scope, element, &isRunning, &isRunningSize);
31211         if (status != noErr) {
31212             return; /* Don't really know what to do in this case... just ignore it, I suppose... */
31213         }
31214
31215         if (!isRunning) {
31216             /*
31217             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:
31218
31219             1) When the device is unplugged, this will be called _before_ the default device change notification.
31220             2) When the device is changed via the default device change notification, this will be called _after_ the switch.
31221
31222             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.
31223             */
31224             if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isDefaultPlaybackDevice) ||
31225                 ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isDefaultCaptureDevice)) {
31226                 /*
31227                 It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device
31228                 via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the
31229                 device to be seamless to the client (we don't want them receiving the stopped event and thinking that the device has stopped when it
31230                 hasn't!).
31231                 */
31232                 if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) ||
31233                     ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isSwitchingCaptureDevice)) {
31234                     return;
31235                 }
31236
31237                 /*
31238                 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
31239                 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
31240                 likely be successful in switching to the new device.
31241
31242                 TODO: Try to predict if Core Audio will switch devices. If not, the stopped callback needs to be posted.
31243                 */
31244                 return;
31245             }
31246
31247             /* Getting here means we need to stop the device. */
31248             ma_device__on_notification_stopped(pDevice);
31249         }
31250     }
31251
31252     (void)propertyID; /* Unused. */
31253 }
31254
31255 #if defined(MA_APPLE_DESKTOP)
31256 static ma_spinlock g_DeviceTrackingInitLock_CoreAudio = 0;  /* A spinlock for mutal exclusion of the init/uninit of the global tracking data. Initialization to 0 is what we need. */
31257 static ma_uint32   g_DeviceTrackingInitCounter_CoreAudio = 0;
31258 static ma_mutex    g_DeviceTrackingMutex_CoreAudio;
31259 static ma_device** g_ppTrackedDevices_CoreAudio = NULL;
31260 static ma_uint32   g_TrackedDeviceCap_CoreAudio = 0;
31261 static ma_uint32   g_TrackedDeviceCount_CoreAudio = 0;
31262
31263 static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UInt32 addressCount, const AudioObjectPropertyAddress* pAddresses, void* pUserData)
31264 {
31265     ma_device_type deviceType;
31266
31267     /* Not sure if I really need to check this, but it makes me feel better. */
31268     if (addressCount == 0) {
31269         return noErr;
31270     }
31271
31272     if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultOutputDevice) {
31273         deviceType = ma_device_type_playback;
31274     } else if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultInputDevice) {
31275         deviceType = ma_device_type_capture;
31276     } else {
31277         return noErr;   /* Should never hit this. */
31278     }
31279
31280     ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
31281     {
31282         ma_uint32 iDevice;
31283         for (iDevice = 0; iDevice < g_TrackedDeviceCount_CoreAudio; iDevice += 1) {
31284             ma_result reinitResult;
31285             ma_device* pDevice;
31286
31287             pDevice = g_ppTrackedDevices_CoreAudio[iDevice];
31288             if (pDevice->type == deviceType || pDevice->type == ma_device_type_duplex) {
31289                 if (deviceType == ma_device_type_playback) {
31290                     pDevice->coreaudio.isSwitchingPlaybackDevice = MA_TRUE;
31291                     reinitResult = ma_device_reinit_internal__coreaudio(pDevice, deviceType, MA_TRUE);
31292                     pDevice->coreaudio.isSwitchingPlaybackDevice = MA_FALSE;
31293                 } else {
31294                     pDevice->coreaudio.isSwitchingCaptureDevice = MA_TRUE;
31295                     reinitResult = ma_device_reinit_internal__coreaudio(pDevice, deviceType, MA_TRUE);
31296                     pDevice->coreaudio.isSwitchingCaptureDevice = MA_FALSE;
31297                 }
31298
31299                 if (reinitResult == MA_SUCCESS) {
31300                     ma_device__post_init_setup(pDevice, deviceType);
31301
31302                     /* Restart the device if required. If this fails we need to stop the device entirely. */
31303                     if (ma_device_get_state(pDevice) == ma_device_state_started) {
31304                         OSStatus status;
31305                         if (deviceType == ma_device_type_playback) {
31306                             status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
31307                             if (status != noErr) {
31308                                 if (pDevice->type == ma_device_type_duplex) {
31309                                     ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
31310                                 }
31311                                 ma_device__set_state(pDevice, ma_device_state_stopped);
31312                             }
31313                         } else if (deviceType == ma_device_type_capture) {
31314                             status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
31315                             if (status != noErr) {
31316                                 if (pDevice->type == ma_device_type_duplex) {
31317                                     ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
31318                                 }
31319                                 ma_device__set_state(pDevice, ma_device_state_stopped);
31320                             }
31321                         }
31322                     }
31323
31324                     ma_device__on_notification_rerouted(pDevice);
31325                 }
31326             }
31327         }
31328     }
31329     ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
31330
31331     /* Unused parameters. */
31332     (void)objectID;
31333     (void)pUserData;
31334
31335     return noErr;
31336 }
31337
31338 static ma_result ma_context__init_device_tracking__coreaudio(ma_context* pContext)
31339 {
31340     MA_ASSERT(pContext != NULL);
31341
31342     ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio);
31343     {
31344         /* Don't do anything if we've already initializd device tracking. */
31345         if (g_DeviceTrackingInitCounter_CoreAudio == 0) {
31346             AudioObjectPropertyAddress propAddress;
31347             propAddress.mScope    = kAudioObjectPropertyScopeGlobal;
31348             propAddress.mElement  = kAudioObjectPropertyElementMaster;
31349
31350             ma_mutex_init(&g_DeviceTrackingMutex_CoreAudio);
31351
31352             propAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
31353             ((ma_AudioObjectAddPropertyListener_proc)pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
31354
31355             propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
31356             ((ma_AudioObjectAddPropertyListener_proc)pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
31357
31358         }
31359         g_DeviceTrackingInitCounter_CoreAudio += 1;
31360     }
31361     ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
31362
31363     return MA_SUCCESS;
31364 }
31365
31366 static ma_result ma_context__uninit_device_tracking__coreaudio(ma_context* pContext)
31367 {
31368     MA_ASSERT(pContext != NULL);
31369
31370     ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio);
31371     {
31372         if (g_DeviceTrackingInitCounter_CoreAudio > 0)
31373             g_DeviceTrackingInitCounter_CoreAudio -= 1;
31374
31375         if (g_DeviceTrackingInitCounter_CoreAudio == 0) {
31376             AudioObjectPropertyAddress propAddress;
31377             propAddress.mScope    = kAudioObjectPropertyScopeGlobal;
31378             propAddress.mElement  = kAudioObjectPropertyElementMaster;
31379
31380             propAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
31381             ((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
31382
31383             propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
31384             ((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
31385
31386             /* At this point there should be no tracked devices. If not there's an error somewhere. */
31387             if (g_ppTrackedDevices_CoreAudio != NULL) {
31388                 ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "You have uninitialized all contexts while an associated device is still active.");
31389                 ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
31390                 return MA_INVALID_OPERATION;
31391             }
31392
31393             ma_mutex_uninit(&g_DeviceTrackingMutex_CoreAudio);
31394         }
31395     }
31396     ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
31397
31398     return MA_SUCCESS;
31399 }
31400
31401 static ma_result ma_device__track__coreaudio(ma_device* pDevice)
31402 {
31403     MA_ASSERT(pDevice != NULL);
31404
31405     ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
31406     {
31407         /* Allocate memory if required. */
31408         if (g_TrackedDeviceCap_CoreAudio <= g_TrackedDeviceCount_CoreAudio) {
31409             ma_uint32 newCap;
31410             ma_device** ppNewDevices;
31411
31412             newCap = g_TrackedDeviceCap_CoreAudio * 2;
31413             if (newCap == 0) {
31414                 newCap = 1;
31415             }
31416
31417             ppNewDevices = (ma_device**)ma_realloc(g_ppTrackedDevices_CoreAudio, sizeof(*g_ppTrackedDevices_CoreAudio)*newCap, &pDevice->pContext->allocationCallbacks);
31418             if (ppNewDevices == NULL) {
31419                 ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
31420                 return MA_OUT_OF_MEMORY;
31421             }
31422
31423             g_ppTrackedDevices_CoreAudio = ppNewDevices;
31424             g_TrackedDeviceCap_CoreAudio = newCap;
31425         }
31426
31427         g_ppTrackedDevices_CoreAudio[g_TrackedDeviceCount_CoreAudio] = pDevice;
31428         g_TrackedDeviceCount_CoreAudio += 1;
31429     }
31430     ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
31431
31432     return MA_SUCCESS;
31433 }
31434
31435 static ma_result ma_device__untrack__coreaudio(ma_device* pDevice)
31436 {
31437     MA_ASSERT(pDevice != NULL);
31438
31439     ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
31440     {
31441         ma_uint32 iDevice;
31442         for (iDevice = 0; iDevice < g_TrackedDeviceCount_CoreAudio; iDevice += 1) {
31443             if (g_ppTrackedDevices_CoreAudio[iDevice] == pDevice) {
31444                 /* We've found the device. We now need to remove it from the list. */
31445                 ma_uint32 jDevice;
31446                 for (jDevice = iDevice; jDevice < g_TrackedDeviceCount_CoreAudio-1; jDevice += 1) {
31447                     g_ppTrackedDevices_CoreAudio[jDevice] = g_ppTrackedDevices_CoreAudio[jDevice+1];
31448                 }
31449
31450                 g_TrackedDeviceCount_CoreAudio -= 1;
31451
31452                 /* If there's nothing else in the list we need to free memory. */
31453                 if (g_TrackedDeviceCount_CoreAudio == 0) {
31454                     ma_free(g_ppTrackedDevices_CoreAudio, &pDevice->pContext->allocationCallbacks);
31455                     g_ppTrackedDevices_CoreAudio = NULL;
31456                     g_TrackedDeviceCap_CoreAudio = 0;
31457                 }
31458
31459                 break;
31460             }
31461         }
31462     }
31463     ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
31464
31465     return MA_SUCCESS;
31466 }
31467 #endif
31468
31469 #if defined(MA_APPLE_MOBILE)
31470 @interface ma_ios_notification_handler:NSObject {
31471     ma_device* m_pDevice;
31472 }
31473 @end
31474
31475 @implementation ma_ios_notification_handler
31476 -(id)init:(ma_device*)pDevice
31477 {
31478     self = [super init];
31479     m_pDevice = pDevice;
31480
31481     /* For route changes. */
31482     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_route_change:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];
31483
31484     /* For interruptions. */
31485     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_interruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
31486
31487     return self;
31488 }
31489
31490 -(void)dealloc
31491 {
31492     [self remove_handler];
31493 }
31494
31495 -(void)remove_handler
31496 {
31497     [[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionRouteChangeNotification object:nil];
31498     [[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionInterruptionNotification object:nil];
31499 }
31500
31501 -(void)handle_interruption:(NSNotification*)pNotification
31502 {
31503     NSInteger type = [[[pNotification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey] integerValue];
31504     switch (type)
31505     {
31506         case AVAudioSessionInterruptionTypeBegan:
31507         {
31508             ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeBegan\n");
31509             ma_device__on_notification_interruption_began(m_pDevice);
31510         } break;
31511         
31512         case AVAudioSessionInterruptionTypeEnded:
31513         {
31514             ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Interruption: AVAudioSessionInterruptionTypeEnded\n");
31515             ma_device__on_notification_interruption_ended(m_pDevice);
31516         } break;
31517     }
31518 }
31519
31520 -(void)handle_route_change:(NSNotification*)pNotification
31521 {
31522     AVAudioSession* pSession = [AVAudioSession sharedInstance];
31523
31524     NSInteger reason = [[[pNotification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
31525     switch (reason)
31526     {
31527         case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
31528         {
31529             ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n");
31530         } break;
31531
31532         case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
31533         {
31534             ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n");
31535         } break;
31536
31537         case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
31538         {
31539             ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory\n");
31540         } break;
31541
31542         case AVAudioSessionRouteChangeReasonWakeFromSleep:
31543         {
31544             ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonWakeFromSleep\n");
31545         } break;
31546
31547         case AVAudioSessionRouteChangeReasonOverride:
31548         {
31549             ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOverride\n");
31550         } break;
31551
31552         case AVAudioSessionRouteChangeReasonCategoryChange:
31553         {
31554             ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n");
31555         } break;
31556
31557         case AVAudioSessionRouteChangeReasonUnknown:
31558         default:
31559         {
31560             ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n");
31561         } break;
31562     }
31563
31564     ma_log_postf(ma_device_get_log(m_pDevice), MA_LOG_LEVEL_DEBUG, "[Core Audio] Changing Route. inputNumberChannels=%d; outputNumberOfChannels=%d\n", (int)pSession.inputNumberOfChannels, (int)pSession.outputNumberOfChannels);
31565     
31566     /* Let the application know about the route change. */
31567     ma_device__on_notification_rerouted(m_pDevice);
31568 }
31569 @end
31570 #endif
31571
31572 static ma_result ma_device_uninit__coreaudio(ma_device* pDevice)
31573 {
31574     MA_ASSERT(pDevice != NULL);
31575     MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_uninitialized);
31576
31577 #if defined(MA_APPLE_DESKTOP)
31578     /*
31579     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
31580     just gracefully ignore it.
31581     */
31582     ma_device__untrack__coreaudio(pDevice);
31583 #endif
31584 #if defined(MA_APPLE_MOBILE)
31585     if (pDevice->coreaudio.pNotificationHandler != NULL) {
31586         ma_ios_notification_handler* pNotificationHandler = (MA_BRIDGE_TRANSFER ma_ios_notification_handler*)pDevice->coreaudio.pNotificationHandler;
31587         [pNotificationHandler remove_handler];
31588     }
31589 #endif
31590
31591     if (pDevice->coreaudio.audioUnitCapture != NULL) {
31592         ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
31593     }
31594     if (pDevice->coreaudio.audioUnitPlayback != NULL) {
31595         ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
31596     }
31597
31598     if (pDevice->coreaudio.pAudioBufferList) {
31599         ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
31600     }
31601
31602     return MA_SUCCESS;
31603 }
31604
31605 typedef struct
31606 {
31607     ma_bool32 allowNominalSampleRateChange;
31608
31609     /* Input. */
31610     ma_format formatIn;
31611     ma_uint32 channelsIn;
31612     ma_uint32 sampleRateIn;
31613     ma_channel channelMapIn[MA_MAX_CHANNELS];
31614     ma_uint32 periodSizeInFramesIn;
31615     ma_uint32 periodSizeInMillisecondsIn;
31616     ma_uint32 periodsIn;
31617     ma_share_mode shareMode;
31618     ma_performance_profile performanceProfile;
31619     ma_bool32 registerStopEvent;
31620
31621     /* Output. */
31622 #if defined(MA_APPLE_DESKTOP)
31623     AudioObjectID deviceObjectID;
31624 #endif
31625     AudioComponent component;
31626     AudioUnit audioUnit;
31627     AudioBufferList* pAudioBufferList;  /* Only used for input devices. */
31628     ma_format formatOut;
31629     ma_uint32 channelsOut;
31630     ma_uint32 sampleRateOut;
31631     ma_channel channelMapOut[MA_MAX_CHANNELS];
31632     ma_uint32 periodSizeInFramesOut;
31633     ma_uint32 periodsOut;
31634     char deviceName[256];
31635 } ma_device_init_internal_data__coreaudio;
31636
31637 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. */
31638 {
31639     ma_result result;
31640     OSStatus status;
31641     UInt32 enableIOFlag;
31642     AudioStreamBasicDescription bestFormat;
31643     UInt32 actualPeriodSizeInFrames;
31644     AURenderCallbackStruct callbackInfo;
31645 #if defined(MA_APPLE_DESKTOP)
31646     AudioObjectID deviceObjectID;
31647 #endif
31648
31649     /* This API should only be used for a single device type: playback or capture. No full-duplex mode. */
31650     if (deviceType == ma_device_type_duplex) {
31651         return MA_INVALID_ARGS;
31652     }
31653
31654     MA_ASSERT(pContext != NULL);
31655     MA_ASSERT(deviceType == ma_device_type_playback || deviceType == ma_device_type_capture);
31656
31657 #if defined(MA_APPLE_DESKTOP)
31658     pData->deviceObjectID = 0;
31659 #endif
31660     pData->component = NULL;
31661     pData->audioUnit = NULL;
31662     pData->pAudioBufferList = NULL;
31663
31664 #if defined(MA_APPLE_DESKTOP)
31665     result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID);
31666     if (result != MA_SUCCESS) {
31667         return result;
31668     }
31669
31670     pData->deviceObjectID = deviceObjectID;
31671 #endif
31672
31673     /* Core audio doesn't really use the notion of a period so we can leave this unmodified, but not too over the top. */
31674     pData->periodsOut = pData->periodsIn;
31675     if (pData->periodsOut == 0) {
31676         pData->periodsOut = MA_DEFAULT_PERIODS;
31677     }
31678     if (pData->periodsOut > 16) {
31679         pData->periodsOut = 16;
31680     }
31681
31682
31683     /* Audio unit. */
31684     status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)((AudioComponent)pContext->coreaudio.component, (AudioUnit*)&pData->audioUnit);
31685     if (status != noErr) {
31686         return ma_result_from_OSStatus(status);
31687     }
31688
31689
31690     /* 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. */
31691     enableIOFlag = 1;
31692     if (deviceType == ma_device_type_capture) {
31693         enableIOFlag = 0;
31694     }
31695
31696     status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));
31697     if (status != noErr) {
31698         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31699         return ma_result_from_OSStatus(status);
31700     }
31701
31702     enableIOFlag = (enableIOFlag == 0) ? 1 : 0;
31703     status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));
31704     if (status != noErr) {
31705         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31706         return ma_result_from_OSStatus(status);
31707     }
31708
31709
31710     /* Set the device to use with this audio unit. This is only used on desktop since we are using defaults on mobile. */
31711 #if defined(MA_APPLE_DESKTOP)
31712     status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceObjectID, sizeof(deviceObjectID));
31713     if (status != noErr) {
31714         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31715         return ma_result_from_OSStatus(result);
31716     }
31717 #else
31718     /*
31719     For some reason it looks like Apple is only allowing selection of the input device. There does not appear to be any way to change
31720     the default output route. I have no idea why this is like this, but for now we'll only be able to configure capture devices.
31721     */
31722     if (pDeviceID != NULL) {
31723         if (deviceType == ma_device_type_capture) {
31724             ma_bool32 found = MA_FALSE;
31725             NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs];
31726             for (AVAudioSessionPortDescription* pPortDesc in pInputs) {
31727                 if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
31728                     [[AVAudioSession sharedInstance] setPreferredInput:pPortDesc error:nil];
31729                     found = MA_TRUE;
31730                     break;
31731                 }
31732             }
31733
31734             if (found == MA_FALSE) {
31735                 return MA_DOES_NOT_EXIST;
31736             }
31737         }
31738     }
31739 #endif
31740
31741     /*
31742     Format. This is the hardest part of initialization because there's a few variables to take into account.
31743       1) The format must be supported by the device.
31744       2) The format must be supported miniaudio.
31745       3) There's a priority that miniaudio prefers.
31746
31747     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
31748     most important property is the sample rate. miniaudio can do format conversion for any sample rate and channel count, but cannot do the same
31749     for the sample data format. If the sample data format is not supported by miniaudio it must be ignored completely.
31750
31751     On mobile platforms this is a bit different. We just force the use of whatever the audio unit's current format is set to.
31752     */
31753     {
31754         AudioStreamBasicDescription origFormat;
31755         UInt32 origFormatSize = sizeof(origFormat);
31756         AudioUnitScope   formatScope   = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
31757         AudioUnitElement formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;
31758
31759         if (deviceType == ma_device_type_playback) {
31760             status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &origFormat, &origFormatSize);
31761         } else {
31762             status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &origFormat, &origFormatSize);
31763         }
31764         if (status != noErr) {
31765             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31766             return ma_result_from_OSStatus(status);
31767         }
31768
31769     #if defined(MA_APPLE_DESKTOP)
31770         result = ma_find_best_format__coreaudio(pContext, deviceObjectID, deviceType, pData->formatIn, pData->channelsIn, pData->sampleRateIn, &origFormat, &bestFormat);
31771         if (result != MA_SUCCESS) {
31772             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31773             return result;
31774         }
31775
31776         /*
31777         Technical Note TN2091: Device input using the HAL Output Audio Unit
31778             https://developer.apple.com/library/archive/technotes/tn2091/_index.html
31779
31780         This documentation says the following:
31781
31782             The internal AudioConverter can handle any *simple* conversion. Typically, this means that a client can specify ANY
31783             variant of the PCM formats. Consequently, the device's sample rate should match the desired sample rate. If sample rate
31784             conversion is needed, it can be accomplished by buffering the input and converting the data on a separate thread with
31785             another AudioConverter.
31786
31787         The important part here is the mention that it can handle *simple* conversions, which does *not* include sample rate. We
31788         therefore want to ensure the sample rate stays consistent. This document is specifically for input, but I'm going to play it
31789         safe and apply the same rule to output as well.
31790
31791         I have tried going against the documentation by setting the sample rate anyway, but this just results in AudioUnitRender()
31792         returning a result code of -10863. I have also tried changing the format directly on the input scope on the input bus, but
31793         this just results in `ca_require: IsStreamFormatWritable(inScope, inElement) NotWritable` when trying to set the format.
31794
31795         Something that does seem to work, however, has been setting the nominal sample rate on the deivce object. The problem with
31796         this, however, is that it actually changes the sample rate at the operating system level and not just the application. This
31797         could be intrusive to the user, however, so I don't think it's wise to make this the default. Instead I'm making this a
31798         configuration option. When the `coreaudio.allowNominalSampleRateChange` config option is set to true, changing the sample
31799         rate will be allowed. Otherwise it'll be fixed to the current sample rate. To check the system-defined sample rate, run
31800         the Audio MIDI Setup program that comes installed on macOS and observe how the sample rate changes as the sample rate is
31801         changed by miniaudio.
31802         */
31803         if (pData->allowNominalSampleRateChange) {
31804             AudioValueRange sampleRateRange;
31805             AudioObjectPropertyAddress propAddress;
31806
31807             sampleRateRange.mMinimum = bestFormat.mSampleRate;
31808             sampleRateRange.mMaximum = bestFormat.mSampleRate;
31809
31810             propAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
31811             propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
31812             propAddress.mElement  = kAudioObjectPropertyElementMaster;
31813
31814             status = ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(sampleRateRange), &sampleRateRange);
31815             if (status != noErr) {
31816                 bestFormat.mSampleRate = origFormat.mSampleRate;
31817             }
31818         } else {
31819             bestFormat.mSampleRate = origFormat.mSampleRate;
31820         }
31821
31822         status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
31823         if (status != noErr) {
31824             /* We failed to set the format, so fall back to the current format of the audio unit. */
31825             bestFormat = origFormat;
31826         }
31827     #else
31828         bestFormat = origFormat;
31829
31830         /*
31831         Sample rate is a little different here because for some reason kAudioUnitProperty_StreamFormat returns 0... Oh well. We need to instead try
31832         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
31833         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
31834         can tell, it looks like the sample rate is shared between playback and capture for everything.
31835         */
31836         @autoreleasepool {
31837             AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
31838             MA_ASSERT(pAudioSession != NULL);
31839
31840             [pAudioSession setPreferredSampleRate:(double)pData->sampleRateIn error:nil];
31841             bestFormat.mSampleRate = pAudioSession.sampleRate;
31842
31843             /*
31844             I've had a report that the channel count returned by AudioUnitGetProperty above is inconsistent with
31845             AVAudioSession outputNumberOfChannels. I'm going to try using the AVAudioSession values instead.
31846             */
31847             if (deviceType == ma_device_type_playback) {
31848                 bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.outputNumberOfChannels;
31849             }
31850             if (deviceType == ma_device_type_capture) {
31851                 bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.inputNumberOfChannels;
31852             }
31853         }
31854
31855         status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
31856         if (status != noErr) {
31857             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31858             return ma_result_from_OSStatus(status);
31859         }
31860     #endif
31861
31862         result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pData->formatOut);
31863         if (result != MA_SUCCESS) {
31864             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31865             return result;
31866         }
31867
31868         if (pData->formatOut == ma_format_unknown) {
31869             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31870             return MA_FORMAT_NOT_SUPPORTED;
31871         }
31872
31873         pData->channelsOut   = bestFormat.mChannelsPerFrame;
31874         pData->sampleRateOut = bestFormat.mSampleRate;
31875     }
31876
31877     /* Clamp the channel count for safety. */
31878     if (pData->channelsOut > MA_MAX_CHANNELS) {
31879         pData->channelsOut = MA_MAX_CHANNELS;
31880     }
31881
31882     /*
31883     Internal channel map. This is weird in my testing. If I use the AudioObject to get the
31884     channel map, the channel descriptions are set to "Unknown" for some reason. To work around
31885     this it looks like retrieving it from the AudioUnit will work. However, and this is where
31886     it gets weird, it doesn't seem to work with capture devices, nor at all on iOS... Therefore
31887     I'm going to fall back to a default assumption in these cases.
31888     */
31889 #if defined(MA_APPLE_DESKTOP)
31890     result = ma_get_AudioUnit_channel_map(pContext, pData->audioUnit, deviceType, pData->channelMapOut, pData->channelsOut);
31891     if (result != MA_SUCCESS) {
31892     #if 0
31893         /* Try falling back to the channel map from the AudioObject. */
31894         result = ma_get_AudioObject_channel_map(pContext, deviceObjectID, deviceType, pData->channelMapOut, pData->channelsOut);
31895         if (result != MA_SUCCESS) {
31896             return result;
31897         }
31898     #else
31899         /* Fall back to default assumptions. */
31900         ma_channel_map_init_standard(ma_standard_channel_map_default, pData->channelMapOut, ma_countof(pData->channelMapOut), pData->channelsOut);
31901     #endif
31902     }
31903 #else
31904     /* TODO: Figure out how to get the channel map using AVAudioSession. */
31905     ma_channel_map_init_standard(ma_standard_channel_map_default, pData->channelMapOut, ma_countof(pData->channelMapOut), pData->channelsOut);
31906 #endif
31907
31908
31909     /* Buffer size. Not allowing this to be configurable on iOS. */
31910     if (pData->periodSizeInFramesIn == 0) {
31911         if (pData->periodSizeInMillisecondsIn == 0) {
31912             if (pData->performanceProfile == ma_performance_profile_low_latency) {
31913                 actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, pData->sampleRateOut);
31914             } else {
31915                 actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, pData->sampleRateOut);
31916             }
31917         } else {
31918             actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, pData->sampleRateOut);
31919         }
31920     } else {
31921         actualPeriodSizeInFrames = pData->periodSizeInFramesIn;
31922     }
31923
31924 #if defined(MA_APPLE_DESKTOP)
31925     result = ma_set_AudioObject_buffer_size_in_frames(pContext, deviceObjectID, deviceType, &actualPeriodSizeInFrames);
31926     if (result != MA_SUCCESS) {
31927         return result;
31928     }
31929 #else
31930     /*
31931     On iOS, the size of the IO buffer needs to be specified in seconds and is a floating point
31932     number. I don't trust any potential truncation errors due to converting from float to integer
31933     so I'm going to explicitly set the actual period size to the next power of 2.
31934     */
31935     @autoreleasepool {
31936         AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
31937         MA_ASSERT(pAudioSession != NULL);
31938         
31939         [pAudioSession setPreferredIOBufferDuration:((float)actualPeriodSizeInFrames / pAudioSession.sampleRate) error:nil];
31940         actualPeriodSizeInFrames = ma_next_power_of_2((ma_uint32)(pAudioSession.IOBufferDuration * pAudioSession.sampleRate));
31941     }
31942 #endif
31943
31944
31945     /*
31946     During testing I discovered that the buffer size can be too big. You'll get an error like this:
31947
31948       kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=4096, mMaxFramesPerSlice=512
31949
31950     Note how inFramesToProcess is smaller than mMaxFramesPerSlice. To fix, we need to set kAudioUnitProperty_MaximumFramesPerSlice to that
31951     of the size of our buffer, or do it the other way around and set our buffer size to the kAudioUnitProperty_MaximumFramesPerSlice.
31952     */
31953     status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &actualPeriodSizeInFrames, sizeof(actualPeriodSizeInFrames));
31954     if (status != noErr) {
31955         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31956         return ma_result_from_OSStatus(status);
31957     }
31958
31959     pData->periodSizeInFramesOut = (ma_uint32)actualPeriodSizeInFrames;
31960
31961     /* We need a buffer list if this is an input device. We render into this in the input callback. */
31962     if (deviceType == ma_device_type_capture) {
31963         ma_bool32 isInterleaved = (bestFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
31964         AudioBufferList* pBufferList;
31965
31966         pBufferList = ma_allocate_AudioBufferList__coreaudio(pData->periodSizeInFramesOut, pData->formatOut, pData->channelsOut, (isInterleaved) ? ma_stream_layout_interleaved : ma_stream_layout_deinterleaved, &pContext->allocationCallbacks);
31967         if (pBufferList == NULL) {
31968             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31969             return MA_OUT_OF_MEMORY;
31970         }
31971
31972         pData->pAudioBufferList = pBufferList;
31973     }
31974
31975     /* Callbacks. */
31976     callbackInfo.inputProcRefCon = pDevice_DoNotReference;
31977     if (deviceType == ma_device_type_playback) {
31978         callbackInfo.inputProc = ma_on_output__coreaudio;
31979         status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &callbackInfo, sizeof(callbackInfo));
31980         if (status != noErr) {
31981             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31982             return ma_result_from_OSStatus(status);
31983         }
31984     } else {
31985         callbackInfo.inputProc = ma_on_input__coreaudio;
31986         status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callbackInfo, sizeof(callbackInfo));
31987         if (status != noErr) {
31988             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31989             return ma_result_from_OSStatus(status);
31990         }
31991     }
31992
31993     /* We need to listen for stop events. */
31994     if (pData->registerStopEvent) {
31995         status = ((ma_AudioUnitAddPropertyListener_proc)pContext->coreaudio.AudioUnitAddPropertyListener)(pData->audioUnit, kAudioOutputUnitProperty_IsRunning, on_start_stop__coreaudio, pDevice_DoNotReference);
31996         if (status != noErr) {
31997             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
31998             return ma_result_from_OSStatus(status);
31999         }
32000     }
32001
32002     /* Initialize the audio unit. */
32003     status = ((ma_AudioUnitInitialize_proc)pContext->coreaudio.AudioUnitInitialize)(pData->audioUnit);
32004     if (status != noErr) {
32005         ma_free(pData->pAudioBufferList, &pContext->allocationCallbacks);
32006         pData->pAudioBufferList = NULL;
32007         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
32008         return ma_result_from_OSStatus(status);
32009     }
32010
32011     /* Grab the name. */
32012 #if defined(MA_APPLE_DESKTOP)
32013     ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(pData->deviceName), pData->deviceName);
32014 #else
32015     if (deviceType == ma_device_type_playback) {
32016         ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_PLAYBACK_DEVICE_NAME);
32017     } else {
32018         ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_CAPTURE_DEVICE_NAME);
32019     }
32020 #endif
32021
32022     return result;
32023 }
32024
32025 #if defined(MA_APPLE_DESKTOP)
32026 static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_device_type deviceType, ma_bool32 disposePreviousAudioUnit)
32027 {
32028     ma_device_init_internal_data__coreaudio data;
32029     ma_result result;
32030
32031     /* This should only be called for playback or capture, not duplex. */
32032     if (deviceType == ma_device_type_duplex) {
32033         return MA_INVALID_ARGS;
32034     }
32035
32036     data.allowNominalSampleRateChange = MA_FALSE;   /* Don't change the nominal sample rate when switching devices. */
32037
32038     if (deviceType == ma_device_type_capture) {
32039         data.formatIn               = pDevice->capture.format;
32040         data.channelsIn             = pDevice->capture.channels;
32041         data.sampleRateIn           = pDevice->sampleRate;
32042         MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
32043         data.shareMode              = pDevice->capture.shareMode;
32044         data.performanceProfile     = pDevice->coreaudio.originalPerformanceProfile;
32045         data.registerStopEvent      = MA_TRUE;
32046
32047         if (disposePreviousAudioUnit) {
32048             ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
32049             ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
32050         }
32051         if (pDevice->coreaudio.pAudioBufferList) {
32052             ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
32053         }
32054     } else if (deviceType == ma_device_type_playback) {
32055         data.formatIn               = pDevice->playback.format;
32056         data.channelsIn             = pDevice->playback.channels;
32057         data.sampleRateIn           = pDevice->sampleRate;
32058         MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
32059         data.shareMode              = pDevice->playback.shareMode;
32060         data.performanceProfile     = pDevice->coreaudio.originalPerformanceProfile;
32061         data.registerStopEvent      = (pDevice->type != ma_device_type_duplex);
32062
32063         if (disposePreviousAudioUnit) {
32064             ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
32065             ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
32066         }
32067     }
32068     data.periodSizeInFramesIn       = pDevice->coreaudio.originalPeriodSizeInFrames;
32069     data.periodSizeInMillisecondsIn = pDevice->coreaudio.originalPeriodSizeInMilliseconds;
32070     data.periodsIn                  = pDevice->coreaudio.originalPeriods;
32071
32072     /* Need at least 3 periods for duplex. */
32073     if (data.periodsIn < 3 && pDevice->type == ma_device_type_duplex) {
32074         data.periodsIn = 3;
32075     }
32076
32077     result = ma_device_init_internal__coreaudio(pDevice->pContext, deviceType, NULL, &data, (void*)pDevice);
32078     if (result != MA_SUCCESS) {
32079         return result;
32080     }
32081
32082     if (deviceType == ma_device_type_capture) {
32083     #if defined(MA_APPLE_DESKTOP)
32084         pDevice->coreaudio.deviceObjectIDCapture     = (ma_uint32)data.deviceObjectID;
32085     #endif
32086         pDevice->coreaudio.audioUnitCapture          = (ma_ptr)data.audioUnit;
32087         pDevice->coreaudio.pAudioBufferList          = (ma_ptr)data.pAudioBufferList;
32088         pDevice->coreaudio.audioBufferCapInFrames    = data.periodSizeInFramesOut;
32089
32090         pDevice->capture.internalFormat              = data.formatOut;
32091         pDevice->capture.internalChannels            = data.channelsOut;
32092         pDevice->capture.internalSampleRate          = data.sampleRateOut;
32093         MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
32094         pDevice->capture.internalPeriodSizeInFrames  = data.periodSizeInFramesOut;
32095         pDevice->capture.internalPeriods             = data.periodsOut;
32096     } else if (deviceType == ma_device_type_playback) {
32097     #if defined(MA_APPLE_DESKTOP)
32098         pDevice->coreaudio.deviceObjectIDPlayback    = (ma_uint32)data.deviceObjectID;
32099     #endif
32100         pDevice->coreaudio.audioUnitPlayback         = (ma_ptr)data.audioUnit;
32101
32102         pDevice->playback.internalFormat             = data.formatOut;
32103         pDevice->playback.internalChannels           = data.channelsOut;
32104         pDevice->playback.internalSampleRate         = data.sampleRateOut;
32105         MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
32106         pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
32107         pDevice->playback.internalPeriods            = data.periodsOut;
32108     }
32109
32110     return MA_SUCCESS;
32111 }
32112 #endif /* MA_APPLE_DESKTOP */
32113
32114 static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
32115 {
32116     ma_result result;
32117
32118     MA_ASSERT(pDevice != NULL);
32119     MA_ASSERT(pConfig != NULL);
32120
32121     if (pConfig->deviceType == ma_device_type_loopback) {
32122         return MA_DEVICE_TYPE_NOT_SUPPORTED;
32123     }
32124
32125     /* No exclusive mode with the Core Audio backend for now. */
32126     if (((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive) ||
32127         ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive)) {
32128         return MA_SHARE_MODE_NOT_SUPPORTED;
32129     }
32130
32131     /* Capture needs to be initialized first. */
32132     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
32133         ma_device_init_internal_data__coreaudio data;
32134         data.allowNominalSampleRateChange = pConfig->coreaudio.allowNominalSampleRateChange;
32135         data.formatIn                     = pDescriptorCapture->format;
32136         data.channelsIn                   = pDescriptorCapture->channels;
32137         data.sampleRateIn                 = pDescriptorCapture->sampleRate;
32138         MA_COPY_MEMORY(data.channelMapIn, pDescriptorCapture->channelMap, sizeof(pDescriptorCapture->channelMap));
32139         data.periodSizeInFramesIn         = pDescriptorCapture->periodSizeInFrames;
32140         data.periodSizeInMillisecondsIn   = pDescriptorCapture->periodSizeInMilliseconds;
32141         data.periodsIn                    = pDescriptorCapture->periodCount;
32142         data.shareMode                    = pDescriptorCapture->shareMode;
32143         data.performanceProfile           = pConfig->performanceProfile;
32144         data.registerStopEvent            = MA_TRUE;
32145
32146         /* Need at least 3 periods for duplex. */
32147         if (data.periodsIn < 3 && pConfig->deviceType == ma_device_type_duplex) {
32148             data.periodsIn = 3;
32149         }
32150
32151         result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_capture, pDescriptorCapture->pDeviceID, &data, (void*)pDevice);
32152         if (result != MA_SUCCESS) {
32153             return result;
32154         }
32155
32156         pDevice->coreaudio.isDefaultCaptureDevice           = (pConfig->capture.pDeviceID == NULL);
32157     #if defined(MA_APPLE_DESKTOP)
32158         pDevice->coreaudio.deviceObjectIDCapture            = (ma_uint32)data.deviceObjectID;
32159     #endif
32160         pDevice->coreaudio.audioUnitCapture                 = (ma_ptr)data.audioUnit;
32161         pDevice->coreaudio.pAudioBufferList                 = (ma_ptr)data.pAudioBufferList;
32162         pDevice->coreaudio.audioBufferCapInFrames           = data.periodSizeInFramesOut;
32163         pDevice->coreaudio.originalPeriodSizeInFrames       = pDescriptorCapture->periodSizeInFrames;
32164         pDevice->coreaudio.originalPeriodSizeInMilliseconds = pDescriptorCapture->periodSizeInMilliseconds;
32165         pDevice->coreaudio.originalPeriods                  = pDescriptorCapture->periodCount;
32166         pDevice->coreaudio.originalPerformanceProfile       = pConfig->performanceProfile;
32167
32168         pDescriptorCapture->format                          = data.formatOut;
32169         pDescriptorCapture->channels                        = data.channelsOut;
32170         pDescriptorCapture->sampleRate                      = data.sampleRateOut;
32171         MA_COPY_MEMORY(pDescriptorCapture->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
32172         pDescriptorCapture->periodSizeInFrames              = data.periodSizeInFramesOut;
32173         pDescriptorCapture->periodCount                     = data.periodsOut;
32174
32175     #if defined(MA_APPLE_DESKTOP)
32176         /*
32177         If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
32178         switch the device in the background.
32179         */
32180         if (pConfig->capture.pDeviceID == NULL) {
32181             ma_device__track__coreaudio(pDevice);
32182         }
32183     #endif
32184     }
32185
32186     /* Playback. */
32187     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
32188         ma_device_init_internal_data__coreaudio data;
32189         data.allowNominalSampleRateChange   = pConfig->coreaudio.allowNominalSampleRateChange;
32190         data.formatIn                       = pDescriptorPlayback->format;
32191         data.channelsIn                     = pDescriptorPlayback->channels;
32192         data.sampleRateIn                   = pDescriptorPlayback->sampleRate;
32193         MA_COPY_MEMORY(data.channelMapIn, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap));
32194         data.shareMode                      = pDescriptorPlayback->shareMode;
32195         data.performanceProfile             = pConfig->performanceProfile;
32196
32197         /* In full-duplex mode we want the playback buffer to be the same size as the capture buffer. */
32198         if (pConfig->deviceType == ma_device_type_duplex) {
32199             data.periodSizeInFramesIn       = pDescriptorCapture->periodSizeInFrames;
32200             data.periodsIn                  = pDescriptorCapture->periodCount;
32201             data.registerStopEvent          = MA_FALSE;
32202         } else {
32203             data.periodSizeInFramesIn       = pDescriptorPlayback->periodSizeInFrames;
32204             data.periodSizeInMillisecondsIn = pDescriptorPlayback->periodSizeInMilliseconds;
32205             data.periodsIn                  = pDescriptorPlayback->periodCount;
32206             data.registerStopEvent          = MA_TRUE;
32207         }
32208
32209         result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_playback, pDescriptorPlayback->pDeviceID, &data, (void*)pDevice);
32210         if (result != MA_SUCCESS) {
32211             if (pConfig->deviceType == ma_device_type_duplex) {
32212                 ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
32213                 if (pDevice->coreaudio.pAudioBufferList) {
32214                     ma_free(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
32215                 }
32216             }
32217             return result;
32218         }
32219
32220         pDevice->coreaudio.isDefaultPlaybackDevice          = (pConfig->playback.pDeviceID == NULL);
32221     #if defined(MA_APPLE_DESKTOP)
32222         pDevice->coreaudio.deviceObjectIDPlayback           = (ma_uint32)data.deviceObjectID;
32223     #endif
32224         pDevice->coreaudio.audioUnitPlayback                = (ma_ptr)data.audioUnit;
32225         pDevice->coreaudio.originalPeriodSizeInFrames       = pDescriptorPlayback->periodSizeInFrames;
32226         pDevice->coreaudio.originalPeriodSizeInMilliseconds = pDescriptorPlayback->periodSizeInMilliseconds;
32227         pDevice->coreaudio.originalPeriods                  = pDescriptorPlayback->periodCount;
32228         pDevice->coreaudio.originalPerformanceProfile       = pConfig->performanceProfile;
32229
32230         pDescriptorPlayback->format                         = data.formatOut;
32231         pDescriptorPlayback->channels                       = data.channelsOut;
32232         pDescriptorPlayback->sampleRate                     = data.sampleRateOut;
32233         MA_COPY_MEMORY(pDescriptorPlayback->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
32234         pDescriptorPlayback->periodSizeInFrames             = data.periodSizeInFramesOut;
32235         pDescriptorPlayback->periodCount                    = data.periodsOut;
32236
32237     #if defined(MA_APPLE_DESKTOP)
32238         /*
32239         If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
32240         switch the device in the background.
32241         */
32242         if (pDescriptorPlayback->pDeviceID == NULL && (pConfig->deviceType != ma_device_type_duplex || pDescriptorCapture->pDeviceID != NULL)) {
32243             ma_device__track__coreaudio(pDevice);
32244         }
32245     #endif
32246     }
32247
32248
32249
32250     /*
32251     When stopping the device, a callback is called on another thread. We need to wait for this callback
32252     before returning from ma_device_stop(). This event is used for this.
32253     */
32254     ma_event_init(&pDevice->coreaudio.stopEvent);
32255
32256     /*
32257     We need to detect when a route has changed so we can update the data conversion pipeline accordingly. This is done
32258     differently on non-Desktop Apple platforms.
32259     */
32260 #if defined(MA_APPLE_MOBILE)
32261     pDevice->coreaudio.pNotificationHandler = (MA_BRIDGE_RETAINED void*)[[ma_ios_notification_handler alloc] init:pDevice];
32262 #endif
32263
32264     return MA_SUCCESS;
32265 }
32266
32267
32268 static ma_result ma_device_start__coreaudio(ma_device* pDevice)
32269 {
32270     MA_ASSERT(pDevice != NULL);
32271
32272     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
32273         OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
32274         if (status != noErr) {
32275             return ma_result_from_OSStatus(status);
32276         }
32277     }
32278
32279     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
32280         OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
32281         if (status != noErr) {
32282             if (pDevice->type == ma_device_type_duplex) {
32283                 ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
32284             }
32285             return ma_result_from_OSStatus(status);
32286         }
32287     }
32288
32289     return MA_SUCCESS;
32290 }
32291
32292 static ma_result ma_device_stop__coreaudio(ma_device* pDevice)
32293 {
32294     MA_ASSERT(pDevice != NULL);
32295
32296     /* It's not clear from the documentation whether or not AudioOutputUnitStop() actually drains the device or not. */
32297
32298     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
32299         OSStatus status = ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
32300         if (status != noErr) {
32301             return ma_result_from_OSStatus(status);
32302         }
32303     }
32304
32305     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
32306         OSStatus status = ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
32307         if (status != noErr) {
32308             return ma_result_from_OSStatus(status);
32309         }
32310     }
32311
32312     /* We need to wait for the callback to finish before returning. */
32313     ma_event_wait(&pDevice->coreaudio.stopEvent);
32314     return MA_SUCCESS;
32315 }
32316
32317
32318 static ma_result ma_context_uninit__coreaudio(ma_context* pContext)
32319 {
32320     MA_ASSERT(pContext != NULL);
32321     MA_ASSERT(pContext->backend == ma_backend_coreaudio);
32322
32323 #if defined(MA_APPLE_MOBILE)
32324     if (!pContext->coreaudio.noAudioSessionDeactivate) {
32325         if (![[AVAudioSession sharedInstance] setActive:false error:nil]) {
32326             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "Failed to deactivate audio session.");
32327             return MA_FAILED_TO_INIT_BACKEND;
32328         }
32329     }
32330 #endif
32331
32332 #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
32333     ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
32334     ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
32335     ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
32336 #endif
32337
32338 #if !defined(MA_APPLE_MOBILE)
32339     ma_context__uninit_device_tracking__coreaudio(pContext);
32340 #endif
32341
32342     (void)pContext;
32343     return MA_SUCCESS;
32344 }
32345
32346 #if defined(MA_APPLE_MOBILE) && defined(__IPHONE_12_0)
32347 static AVAudioSessionCategory ma_to_AVAudioSessionCategory(ma_ios_session_category category)
32348 {
32349     /* The "default" and "none" categories are treated different and should not be used as an input into this function. */
32350     MA_ASSERT(category != ma_ios_session_category_default);
32351     MA_ASSERT(category != ma_ios_session_category_none);
32352
32353     switch (category) {
32354         case ma_ios_session_category_ambient:         return AVAudioSessionCategoryAmbient;
32355         case ma_ios_session_category_solo_ambient:    return AVAudioSessionCategorySoloAmbient;
32356         case ma_ios_session_category_playback:        return AVAudioSessionCategoryPlayback;
32357         case ma_ios_session_category_record:          return AVAudioSessionCategoryRecord;
32358         case ma_ios_session_category_play_and_record: return AVAudioSessionCategoryPlayAndRecord;
32359         case ma_ios_session_category_multi_route:     return AVAudioSessionCategoryMultiRoute;
32360         case ma_ios_session_category_none:            return AVAudioSessionCategoryAmbient;
32361         case ma_ios_session_category_default:         return AVAudioSessionCategoryAmbient;
32362         default:                                      return AVAudioSessionCategoryAmbient;
32363     }
32364 }
32365 #endif
32366
32367 static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
32368 {
32369 #if !defined(MA_APPLE_MOBILE)
32370     ma_result result;
32371 #endif
32372
32373     MA_ASSERT(pConfig != NULL);
32374     MA_ASSERT(pContext != NULL);
32375
32376 #if defined(MA_APPLE_MOBILE)
32377     @autoreleasepool {
32378         AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
32379         AVAudioSessionCategoryOptions options = pConfig->coreaudio.sessionCategoryOptions;
32380
32381         MA_ASSERT(pAudioSession != NULL);
32382
32383         if (pConfig->coreaudio.sessionCategory == ma_ios_session_category_default) {
32384             /*
32385             I'm going to use trial and error to determine our default session category. First we'll try PlayAndRecord. If that fails
32386             we'll try Playback and if that fails we'll try record. If all of these fail we'll just not set the category.
32387             */
32388         #if !defined(MA_APPLE_TV) && !defined(MA_APPLE_WATCH)
32389             options |= AVAudioSessionCategoryOptionDefaultToSpeaker;
32390         #endif
32391
32392             if ([pAudioSession setCategory: AVAudioSessionCategoryPlayAndRecord withOptions:options error:nil]) {
32393                 /* Using PlayAndRecord */
32394             } else if ([pAudioSession setCategory: AVAudioSessionCategoryPlayback withOptions:options error:nil]) {
32395                 /* Using Playback */
32396             } else if ([pAudioSession setCategory: AVAudioSessionCategoryRecord withOptions:options error:nil]) {
32397                 /* Using Record */
32398             } else {
32399                 /* Leave as default? */
32400             }
32401         } else {
32402             if (pConfig->coreaudio.sessionCategory != ma_ios_session_category_none) {
32403             #if defined(__IPHONE_12_0)
32404                 if (![pAudioSession setCategory: ma_to_AVAudioSessionCategory(pConfig->coreaudio.sessionCategory) withOptions:options error:nil]) {
32405                     return MA_INVALID_OPERATION;    /* Failed to set session category. */
32406                 }
32407             #else
32408                 /* Ignore the session category on version 11 and older, but post a warning. */
32409                 ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Session category only supported in iOS 12 and newer.");
32410             #endif
32411             }
32412         }
32413
32414         if (!pConfig->coreaudio.noAudioSessionActivate) {
32415             if (![pAudioSession setActive:true error:nil]) {
32416                 ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "Failed to activate audio session.");
32417                 return MA_FAILED_TO_INIT_BACKEND;
32418             }
32419         }
32420     }
32421 #endif
32422
32423 #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
32424     pContext->coreaudio.hCoreFoundation = ma_dlopen(pContext, "CoreFoundation.framework/CoreFoundation");
32425     if (pContext->coreaudio.hCoreFoundation == NULL) {
32426         return MA_API_NOT_FOUND;
32427     }
32428
32429     pContext->coreaudio.CFStringGetCString = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFStringGetCString");
32430     pContext->coreaudio.CFRelease          = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFRelease");
32431
32432
32433     pContext->coreaudio.hCoreAudio = ma_dlopen(pContext, "CoreAudio.framework/CoreAudio");
32434     if (pContext->coreaudio.hCoreAudio == NULL) {
32435         ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
32436         return MA_API_NOT_FOUND;
32437     }
32438
32439     pContext->coreaudio.AudioObjectGetPropertyData        = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyData");
32440     pContext->coreaudio.AudioObjectGetPropertyDataSize    = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize");
32441     pContext->coreaudio.AudioObjectSetPropertyData        = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectSetPropertyData");
32442     pContext->coreaudio.AudioObjectAddPropertyListener    = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener");
32443     pContext->coreaudio.AudioObjectRemovePropertyListener = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectRemovePropertyListener");
32444
32445     /*
32446     It looks like Apple has moved some APIs from AudioUnit into AudioToolbox on more recent versions of macOS. They are still
32447     defined in AudioUnit, but just in case they decide to remove them from there entirely I'm going to implement a fallback.
32448     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
32449     AudioToolbox.
32450     */
32451     pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioUnit.framework/AudioUnit");
32452     if (pContext->coreaudio.hAudioUnit == NULL) {
32453         ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
32454         ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
32455         return MA_API_NOT_FOUND;
32456     }
32457
32458     if (ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext") == NULL) {
32459         /* Couldn't find the required symbols in AudioUnit, so fall back to AudioToolbox. */
32460         ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
32461         pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioToolbox.framework/AudioToolbox");
32462         if (pContext->coreaudio.hAudioUnit == NULL) {
32463             ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
32464             ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
32465             return MA_API_NOT_FOUND;
32466         }
32467     }
32468
32469     pContext->coreaudio.AudioComponentFindNext            = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext");
32470     pContext->coreaudio.AudioComponentInstanceDispose     = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceDispose");
32471     pContext->coreaudio.AudioComponentInstanceNew         = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceNew");
32472     pContext->coreaudio.AudioOutputUnitStart              = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStart");
32473     pContext->coreaudio.AudioOutputUnitStop               = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStop");
32474     pContext->coreaudio.AudioUnitAddPropertyListener      = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitAddPropertyListener");
32475     pContext->coreaudio.AudioUnitGetPropertyInfo          = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetPropertyInfo");
32476     pContext->coreaudio.AudioUnitGetProperty              = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetProperty");
32477     pContext->coreaudio.AudioUnitSetProperty              = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitSetProperty");
32478     pContext->coreaudio.AudioUnitInitialize               = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitInitialize");
32479     pContext->coreaudio.AudioUnitRender                   = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitRender");
32480 #else
32481     pContext->coreaudio.CFStringGetCString                = (ma_proc)CFStringGetCString;
32482     pContext->coreaudio.CFRelease                         = (ma_proc)CFRelease;
32483
32484     #if defined(MA_APPLE_DESKTOP)
32485     pContext->coreaudio.AudioObjectGetPropertyData        = (ma_proc)AudioObjectGetPropertyData;
32486     pContext->coreaudio.AudioObjectGetPropertyDataSize    = (ma_proc)AudioObjectGetPropertyDataSize;
32487     pContext->coreaudio.AudioObjectSetPropertyData        = (ma_proc)AudioObjectSetPropertyData;
32488     pContext->coreaudio.AudioObjectAddPropertyListener    = (ma_proc)AudioObjectAddPropertyListener;
32489     pContext->coreaudio.AudioObjectRemovePropertyListener = (ma_proc)AudioObjectRemovePropertyListener;
32490     #endif
32491
32492     pContext->coreaudio.AudioComponentFindNext            = (ma_proc)AudioComponentFindNext;
32493     pContext->coreaudio.AudioComponentInstanceDispose     = (ma_proc)AudioComponentInstanceDispose;
32494     pContext->coreaudio.AudioComponentInstanceNew         = (ma_proc)AudioComponentInstanceNew;
32495     pContext->coreaudio.AudioOutputUnitStart              = (ma_proc)AudioOutputUnitStart;
32496     pContext->coreaudio.AudioOutputUnitStop               = (ma_proc)AudioOutputUnitStop;
32497     pContext->coreaudio.AudioUnitAddPropertyListener      = (ma_proc)AudioUnitAddPropertyListener;
32498     pContext->coreaudio.AudioUnitGetPropertyInfo          = (ma_proc)AudioUnitGetPropertyInfo;
32499     pContext->coreaudio.AudioUnitGetProperty              = (ma_proc)AudioUnitGetProperty;
32500     pContext->coreaudio.AudioUnitSetProperty              = (ma_proc)AudioUnitSetProperty;
32501     pContext->coreaudio.AudioUnitInitialize               = (ma_proc)AudioUnitInitialize;
32502     pContext->coreaudio.AudioUnitRender                   = (ma_proc)AudioUnitRender;
32503 #endif
32504
32505     /* Audio component. */
32506     {
32507         AudioComponentDescription desc;
32508         desc.componentType         = kAudioUnitType_Output;
32509     #if defined(MA_APPLE_DESKTOP)
32510         desc.componentSubType      = kAudioUnitSubType_HALOutput;
32511     #else
32512         desc.componentSubType      = kAudioUnitSubType_RemoteIO;
32513     #endif
32514         desc.componentManufacturer = kAudioUnitManufacturer_Apple;
32515         desc.componentFlags        = 0;
32516         desc.componentFlagsMask    = 0;
32517
32518         pContext->coreaudio.component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc);
32519         if (pContext->coreaudio.component == NULL) {
32520         #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
32521             ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
32522             ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
32523             ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
32524         #endif
32525             return MA_FAILED_TO_INIT_BACKEND;
32526         }
32527     }
32528
32529 #if !defined(MA_APPLE_MOBILE)
32530     result = ma_context__init_device_tracking__coreaudio(pContext);
32531     if (result != MA_SUCCESS) {
32532     #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
32533         ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
32534         ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
32535         ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
32536     #endif
32537         return result;
32538     }
32539 #endif
32540
32541     pContext->coreaudio.noAudioSessionDeactivate = pConfig->coreaudio.noAudioSessionDeactivate;
32542
32543     pCallbacks->onContextInit             = ma_context_init__coreaudio;
32544     pCallbacks->onContextUninit           = ma_context_uninit__coreaudio;
32545     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__coreaudio;
32546     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__coreaudio;
32547     pCallbacks->onDeviceInit              = ma_device_init__coreaudio;
32548     pCallbacks->onDeviceUninit            = ma_device_uninit__coreaudio;
32549     pCallbacks->onDeviceStart             = ma_device_start__coreaudio;
32550     pCallbacks->onDeviceStop              = ma_device_stop__coreaudio;
32551     pCallbacks->onDeviceRead              = NULL;
32552     pCallbacks->onDeviceWrite             = NULL;
32553     pCallbacks->onDeviceDataLoop          = NULL;
32554
32555     return MA_SUCCESS;
32556 }
32557 #endif  /* Core Audio */
32558
32559
32560
32561 /******************************************************************************
32562
32563 sndio Backend
32564
32565 ******************************************************************************/
32566 #ifdef MA_HAS_SNDIO
32567 #include <fcntl.h>
32568
32569 /*
32570 Only supporting OpenBSD. This did not work very well at all on FreeBSD when I tried it. Not sure if this is due
32571 to miniaudio's implementation or if it's some kind of system configuration issue, but basically the default device
32572 just doesn't emit any sound, or at times you'll hear tiny pieces. I will consider enabling this when there's
32573 demand for it or if I can get it tested and debugged more thoroughly.
32574 */
32575 #if 0
32576 #if defined(__NetBSD__) || defined(__OpenBSD__)
32577 #include <sys/audioio.h>
32578 #endif
32579 #if defined(__FreeBSD__) || defined(__DragonFly__)
32580 #include <sys/soundcard.h>
32581 #endif
32582 #endif
32583
32584 #define MA_SIO_DEVANY   "default"
32585 #define MA_SIO_PLAY     1
32586 #define MA_SIO_REC      2
32587 #define MA_SIO_NENC     8
32588 #define MA_SIO_NCHAN    8
32589 #define MA_SIO_NRATE    16
32590 #define MA_SIO_NCONF    4
32591
32592 struct ma_sio_hdl; /* <-- Opaque */
32593
32594 struct ma_sio_par
32595 {
32596     unsigned int bits;
32597     unsigned int bps;
32598     unsigned int sig;
32599     unsigned int le;
32600     unsigned int msb;
32601     unsigned int rchan;
32602     unsigned int pchan;
32603     unsigned int rate;
32604     unsigned int bufsz;
32605     unsigned int xrun;
32606     unsigned int round;
32607     unsigned int appbufsz;
32608     int __pad[3];
32609     unsigned int __magic;
32610 };
32611
32612 struct ma_sio_enc
32613 {
32614     unsigned int bits;
32615     unsigned int bps;
32616     unsigned int sig;
32617     unsigned int le;
32618     unsigned int msb;
32619 };
32620
32621 struct ma_sio_conf
32622 {
32623     unsigned int enc;
32624     unsigned int rchan;
32625     unsigned int pchan;
32626     unsigned int rate;
32627 };
32628
32629 struct ma_sio_cap
32630 {
32631     struct ma_sio_enc enc[MA_SIO_NENC];
32632     unsigned int rchan[MA_SIO_NCHAN];
32633     unsigned int pchan[MA_SIO_NCHAN];
32634     unsigned int rate[MA_SIO_NRATE];
32635     int __pad[7];
32636     unsigned int nconf;
32637     struct ma_sio_conf confs[MA_SIO_NCONF];
32638 };
32639
32640 typedef struct ma_sio_hdl* (* ma_sio_open_proc)   (const char*, unsigned int, int);
32641 typedef void               (* ma_sio_close_proc)  (struct ma_sio_hdl*);
32642 typedef int                (* ma_sio_setpar_proc) (struct ma_sio_hdl*, struct ma_sio_par*);
32643 typedef int                (* ma_sio_getpar_proc) (struct ma_sio_hdl*, struct ma_sio_par*);
32644 typedef int                (* ma_sio_getcap_proc) (struct ma_sio_hdl*, struct ma_sio_cap*);
32645 typedef size_t             (* ma_sio_write_proc)  (struct ma_sio_hdl*, const void*, size_t);
32646 typedef size_t             (* ma_sio_read_proc)   (struct ma_sio_hdl*, void*, size_t);
32647 typedef int                (* ma_sio_start_proc)  (struct ma_sio_hdl*);
32648 typedef int                (* ma_sio_stop_proc)   (struct ma_sio_hdl*);
32649 typedef int                (* ma_sio_initpar_proc)(struct ma_sio_par*);
32650
32651 static ma_uint32 ma_get_standard_sample_rate_priority_index__sndio(ma_uint32 sampleRate)   /* Lower = higher priority */
32652 {
32653     ma_uint32 i;
32654     for (i = 0; i < ma_countof(g_maStandardSampleRatePriorities); ++i) {
32655         if (g_maStandardSampleRatePriorities[i] == sampleRate) {
32656             return i;
32657         }
32658     }
32659
32660     return (ma_uint32)-1;
32661 }
32662
32663 static ma_format ma_format_from_sio_enc__sndio(unsigned int bits, unsigned int bps, unsigned int sig, unsigned int le, unsigned int msb)
32664 {
32665     /* We only support native-endian right now. */
32666     if ((ma_is_little_endian() && le == 0) || (ma_is_big_endian() && le == 1)) {
32667         return ma_format_unknown;
32668     }
32669
32670     if (bits ==  8 && bps == 1 && sig == 0) {
32671         return ma_format_u8;
32672     }
32673     if (bits == 16 && bps == 2 && sig == 1) {
32674         return ma_format_s16;
32675     }
32676     if (bits == 24 && bps == 3 && sig == 1) {
32677         return ma_format_s24;
32678     }
32679     if (bits == 24 && bps == 4 && sig == 1 && msb == 0) {
32680         /*return ma_format_s24_32;*/
32681     }
32682     if (bits == 32 && bps == 4 && sig == 1) {
32683         return ma_format_s32;
32684     }
32685
32686     return ma_format_unknown;
32687 }
32688
32689 static ma_format ma_find_best_format_from_sio_cap__sndio(struct ma_sio_cap* caps)
32690 {
32691     ma_format bestFormat;
32692     unsigned int iConfig;
32693
32694     MA_ASSERT(caps != NULL);
32695
32696     bestFormat = ma_format_unknown;
32697     for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) {
32698         unsigned int iEncoding;
32699         for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
32700             unsigned int bits;
32701             unsigned int bps;
32702             unsigned int sig;
32703             unsigned int le;
32704             unsigned int msb;
32705             ma_format format;
32706
32707             if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) {
32708                 continue;
32709             }
32710
32711             bits = caps->enc[iEncoding].bits;
32712             bps  = caps->enc[iEncoding].bps;
32713             sig  = caps->enc[iEncoding].sig;
32714             le   = caps->enc[iEncoding].le;
32715             msb  = caps->enc[iEncoding].msb;
32716             format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
32717             if (format == ma_format_unknown) {
32718                 continue;   /* Format not supported. */
32719             }
32720
32721             if (bestFormat == ma_format_unknown) {
32722                 bestFormat = format;
32723             } else {
32724                 if (ma_get_format_priority_index(bestFormat) > ma_get_format_priority_index(format)) {    /* <-- Lower = better. */
32725                     bestFormat = format;
32726                 }
32727             }
32728         }
32729     }
32730
32731     return bestFormat;
32732 }
32733
32734 static ma_uint32 ma_find_best_channels_from_sio_cap__sndio(struct ma_sio_cap* caps, ma_device_type deviceType, ma_format requiredFormat)
32735 {
32736     ma_uint32 maxChannels;
32737     unsigned int iConfig;
32738
32739     MA_ASSERT(caps != NULL);
32740     MA_ASSERT(requiredFormat != ma_format_unknown);
32741
32742     /* Just pick whatever configuration has the most channels. */
32743     maxChannels = 0;
32744     for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) {
32745         /* The encoding should be of requiredFormat. */
32746         unsigned int iEncoding;
32747         for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
32748             unsigned int iChannel;
32749             unsigned int bits;
32750             unsigned int bps;
32751             unsigned int sig;
32752             unsigned int le;
32753             unsigned int msb;
32754             ma_format format;
32755
32756             if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) {
32757                 continue;
32758             }
32759
32760             bits = caps->enc[iEncoding].bits;
32761             bps  = caps->enc[iEncoding].bps;
32762             sig  = caps->enc[iEncoding].sig;
32763             le   = caps->enc[iEncoding].le;
32764             msb  = caps->enc[iEncoding].msb;
32765             format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
32766             if (format != requiredFormat) {
32767                 continue;
32768             }
32769
32770             /* Getting here means the format is supported. Iterate over each channel count and grab the biggest one. */
32771             for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) {
32772                 unsigned int chan = 0;
32773                 unsigned int channels;
32774
32775                 if (deviceType == ma_device_type_playback) {
32776                     chan = caps->confs[iConfig].pchan;
32777                 } else {
32778                     chan = caps->confs[iConfig].rchan;
32779                 }
32780
32781                 if ((chan & (1UL << iChannel)) == 0) {
32782                     continue;
32783                 }
32784
32785                 if (deviceType == ma_device_type_playback) {
32786                     channels = caps->pchan[iChannel];
32787                 } else {
32788                     channels = caps->rchan[iChannel];
32789                 }
32790
32791                 if (maxChannels < channels) {
32792                     maxChannels = channels;
32793                 }
32794             }
32795         }
32796     }
32797
32798     return maxChannels;
32799 }
32800
32801 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)
32802 {
32803     ma_uint32 firstSampleRate;
32804     ma_uint32 bestSampleRate;
32805     unsigned int iConfig;
32806
32807     MA_ASSERT(caps != NULL);
32808     MA_ASSERT(requiredFormat != ma_format_unknown);
32809     MA_ASSERT(requiredChannels > 0);
32810     MA_ASSERT(requiredChannels <= MA_MAX_CHANNELS);
32811
32812     firstSampleRate = 0; /* <-- If the device does not support a standard rate we'll fall back to the first one that's found. */
32813     bestSampleRate  = 0;
32814
32815     for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) {
32816         /* The encoding should be of requiredFormat. */
32817         unsigned int iEncoding;
32818         for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
32819             unsigned int iChannel;
32820             unsigned int bits;
32821             unsigned int bps;
32822             unsigned int sig;
32823             unsigned int le;
32824             unsigned int msb;
32825             ma_format format;
32826
32827             if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) {
32828                 continue;
32829             }
32830
32831             bits = caps->enc[iEncoding].bits;
32832             bps  = caps->enc[iEncoding].bps;
32833             sig  = caps->enc[iEncoding].sig;
32834             le   = caps->enc[iEncoding].le;
32835             msb  = caps->enc[iEncoding].msb;
32836             format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
32837             if (format != requiredFormat) {
32838                 continue;
32839             }
32840
32841             /* Getting here means the format is supported. Iterate over each channel count and grab the biggest one. */
32842             for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) {
32843                 unsigned int chan = 0;
32844                 unsigned int channels;
32845                 unsigned int iRate;
32846
32847                 if (deviceType == ma_device_type_playback) {
32848                     chan = caps->confs[iConfig].pchan;
32849                 } else {
32850                     chan = caps->confs[iConfig].rchan;
32851                 }
32852
32853                 if ((chan & (1UL << iChannel)) == 0) {
32854                     continue;
32855                 }
32856
32857                 if (deviceType == ma_device_type_playback) {
32858                     channels = caps->pchan[iChannel];
32859                 } else {
32860                     channels = caps->rchan[iChannel];
32861                 }
32862
32863                 if (channels != requiredChannels) {
32864                     continue;
32865                 }
32866
32867                 /* Getting here means we have found a compatible encoding/channel pair. */
32868                 for (iRate = 0; iRate < MA_SIO_NRATE; iRate += 1) {
32869                     ma_uint32 rate = (ma_uint32)caps->rate[iRate];
32870                     ma_uint32 ratePriority;
32871
32872                     if (firstSampleRate == 0) {
32873                         firstSampleRate = rate;
32874                     }
32875
32876                     /* Disregard this rate if it's not a standard one. */
32877                     ratePriority = ma_get_standard_sample_rate_priority_index__sndio(rate);
32878                     if (ratePriority == (ma_uint32)-1) {
32879                         continue;
32880                     }
32881
32882                     if (ma_get_standard_sample_rate_priority_index__sndio(bestSampleRate) > ratePriority) {   /* Lower = better. */
32883                         bestSampleRate = rate;
32884                     }
32885                 }
32886             }
32887         }
32888     }
32889
32890     /* If a standard sample rate was not found just fall back to the first one that was iterated. */
32891     if (bestSampleRate == 0) {
32892         bestSampleRate = firstSampleRate;
32893     }
32894
32895     return bestSampleRate;
32896 }
32897
32898
32899 static ma_result ma_context_enumerate_devices__sndio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
32900 {
32901     ma_bool32 isTerminating = MA_FALSE;
32902     struct ma_sio_hdl* handle;
32903
32904     MA_ASSERT(pContext != NULL);
32905     MA_ASSERT(callback != NULL);
32906
32907     /* sndio doesn't seem to have a good device enumeration API, so I'm therefore only enumerating over default devices for now. */
32908
32909     /* Playback. */
32910     if (!isTerminating) {
32911         handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(MA_SIO_DEVANY, MA_SIO_PLAY, 0);
32912         if (handle != NULL) {
32913             /* Supports playback. */
32914             ma_device_info deviceInfo;
32915             MA_ZERO_OBJECT(&deviceInfo);
32916             ma_strcpy_s(deviceInfo.id.sndio, sizeof(deviceInfo.id.sndio), MA_SIO_DEVANY);
32917             ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME);
32918
32919             isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
32920
32921             ((ma_sio_close_proc)pContext->sndio.sio_close)(handle);
32922         }
32923     }
32924
32925     /* Capture. */
32926     if (!isTerminating) {
32927         handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(MA_SIO_DEVANY, MA_SIO_REC, 0);
32928         if (handle != NULL) {
32929             /* Supports capture. */
32930             ma_device_info deviceInfo;
32931             MA_ZERO_OBJECT(&deviceInfo);
32932             ma_strcpy_s(deviceInfo.id.sndio, sizeof(deviceInfo.id.sndio), "default");
32933             ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME);
32934
32935             isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
32936
32937             ((ma_sio_close_proc)pContext->sndio.sio_close)(handle);
32938         }
32939     }
32940
32941     return MA_SUCCESS;
32942 }
32943
32944 static ma_result ma_context_get_device_info__sndio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
32945 {
32946     char devid[256];
32947     struct ma_sio_hdl* handle;
32948     struct ma_sio_cap caps;
32949     unsigned int iConfig;
32950
32951     MA_ASSERT(pContext != NULL);
32952
32953     /* We need to open the device before we can get information about it. */
32954     if (pDeviceID == NULL) {
32955         ma_strcpy_s(devid, sizeof(devid), MA_SIO_DEVANY);
32956         ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (deviceType == ma_device_type_playback) ? MA_DEFAULT_PLAYBACK_DEVICE_NAME : MA_DEFAULT_CAPTURE_DEVICE_NAME);
32957     } else {
32958         ma_strcpy_s(devid, sizeof(devid), pDeviceID->sndio);
32959         ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), devid);
32960     }
32961
32962     handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(devid, (deviceType == ma_device_type_playback) ? MA_SIO_PLAY : MA_SIO_REC, 0);
32963     if (handle == NULL) {
32964         return MA_NO_DEVICE;
32965     }
32966
32967     if (((ma_sio_getcap_proc)pContext->sndio.sio_getcap)(handle, &caps) == 0) {
32968         return MA_ERROR;
32969     }
32970
32971     pDeviceInfo->nativeDataFormatCount = 0;
32972
32973     for (iConfig = 0; iConfig < caps.nconf; iConfig += 1) {
32974         /*
32975         The main thing we care about is that the encoding is supported by miniaudio. If it is, we want to give
32976         preference to some formats over others.
32977         */
32978         unsigned int iEncoding;
32979         unsigned int iChannel;
32980         unsigned int iRate;
32981
32982         for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
32983             unsigned int bits;
32984             unsigned int bps;
32985             unsigned int sig;
32986             unsigned int le;
32987             unsigned int msb;
32988             ma_format format;
32989
32990             if ((caps.confs[iConfig].enc & (1UL << iEncoding)) == 0) {
32991                 continue;
32992             }
32993
32994             bits = caps.enc[iEncoding].bits;
32995             bps  = caps.enc[iEncoding].bps;
32996             sig  = caps.enc[iEncoding].sig;
32997             le   = caps.enc[iEncoding].le;
32998             msb  = caps.enc[iEncoding].msb;
32999             format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
33000             if (format == ma_format_unknown) {
33001                 continue;   /* Format not supported. */
33002             }
33003
33004
33005             /* Channels. */
33006             for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) {
33007                 unsigned int chan = 0;
33008                 unsigned int channels;
33009
33010                 if (deviceType == ma_device_type_playback) {
33011                     chan = caps.confs[iConfig].pchan;
33012                 } else {
33013                     chan = caps.confs[iConfig].rchan;
33014                 }
33015
33016                 if ((chan & (1UL << iChannel)) == 0) {
33017                     continue;
33018                 }
33019
33020                 if (deviceType == ma_device_type_playback) {
33021                     channels = caps.pchan[iChannel];
33022                 } else {
33023                     channels = caps.rchan[iChannel];
33024                 }
33025
33026
33027                 /* Sample Rates. */
33028                 for (iRate = 0; iRate < MA_SIO_NRATE; iRate += 1) {
33029                     if ((caps.confs[iConfig].rate & (1UL << iRate)) != 0) {
33030                         ma_device_info_add_native_data_format(pDeviceInfo, format, channels, caps.rate[iRate], 0);
33031                     }
33032                 }
33033             }
33034         }
33035     }
33036
33037     ((ma_sio_close_proc)pContext->sndio.sio_close)(handle);
33038     return MA_SUCCESS;
33039 }
33040
33041 static ma_result ma_device_uninit__sndio(ma_device* pDevice)
33042 {
33043     MA_ASSERT(pDevice != NULL);
33044
33045     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
33046         ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handleCapture);
33047     }
33048
33049     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
33050         ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback);
33051     }
33052
33053     return MA_SUCCESS;
33054 }
33055
33056 static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType)
33057 {
33058     const char* pDeviceName;
33059     ma_ptr handle;
33060     int openFlags = 0;
33061     struct ma_sio_cap caps;
33062     struct ma_sio_par par;
33063     const ma_device_id* pDeviceID;
33064     ma_format format;
33065     ma_uint32 channels;
33066     ma_uint32 sampleRate;
33067     ma_format internalFormat;
33068     ma_uint32 internalChannels;
33069     ma_uint32 internalSampleRate;
33070     ma_uint32 internalPeriodSizeInFrames;
33071     ma_uint32 internalPeriods;
33072
33073     MA_ASSERT(pConfig    != NULL);
33074     MA_ASSERT(deviceType != ma_device_type_duplex);
33075     MA_ASSERT(pDevice    != NULL);
33076
33077     if (deviceType == ma_device_type_capture) {
33078         openFlags = MA_SIO_REC;
33079     } else {
33080         openFlags = MA_SIO_PLAY;
33081     }
33082
33083     pDeviceID  = pDescriptor->pDeviceID;
33084     format     = pDescriptor->format;
33085     channels   = pDescriptor->channels;
33086     sampleRate = pDescriptor->sampleRate;
33087
33088     pDeviceName = MA_SIO_DEVANY;
33089     if (pDeviceID != NULL) {
33090         pDeviceName = pDeviceID->sndio;
33091     }
33092
33093     handle = (ma_ptr)((ma_sio_open_proc)pDevice->pContext->sndio.sio_open)(pDeviceName, openFlags, 0);
33094     if (handle == NULL) {
33095         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to open device.");
33096         return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
33097     }
33098
33099     /* We need to retrieve the device caps to determine the most appropriate format to use. */
33100     if (((ma_sio_getcap_proc)pDevice->pContext->sndio.sio_getcap)((struct ma_sio_hdl*)handle, &caps) == 0) {
33101         ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle);
33102         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve device caps.");
33103         return MA_ERROR;
33104     }
33105
33106     /*
33107     Note: sndio reports a huge range of available channels. This is inconvenient for us because there's no real
33108     way, as far as I can tell, to get the _actual_ channel count of the device. I'm therefore restricting this
33109     to the requested channels, regardless of whether or not the default channel count is requested.
33110
33111     For hardware devices, I'm suspecting only a single channel count will be reported and we can safely use the
33112     value returned by ma_find_best_channels_from_sio_cap__sndio().
33113     */
33114     if (deviceType == ma_device_type_capture) {
33115         if (format == ma_format_unknown) {
33116             format = ma_find_best_format_from_sio_cap__sndio(&caps);
33117         }
33118
33119         if (channels == 0) {
33120             if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) {
33121                 channels = ma_find_best_channels_from_sio_cap__sndio(&caps, deviceType, format);
33122             } else {
33123                 channels = MA_DEFAULT_CHANNELS;
33124             }
33125         }
33126     } else {
33127         if (format == ma_format_unknown) {
33128             format = ma_find_best_format_from_sio_cap__sndio(&caps);
33129         }
33130
33131         if (channels == 0) {
33132             if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) {
33133                 channels = ma_find_best_channels_from_sio_cap__sndio(&caps, deviceType, format);
33134             } else {
33135                 channels = MA_DEFAULT_CHANNELS;
33136             }
33137         }
33138     }
33139
33140     if (sampleRate == 0) {
33141         sampleRate = ma_find_best_sample_rate_from_sio_cap__sndio(&caps, pConfig->deviceType, format, channels);
33142     }
33143
33144
33145     ((ma_sio_initpar_proc)pDevice->pContext->sndio.sio_initpar)(&par);
33146     par.msb = 0;
33147     par.le  = ma_is_little_endian();
33148
33149     switch (format) {
33150         case ma_format_u8:
33151         {
33152             par.bits = 8;
33153             par.bps  = 1;
33154             par.sig  = 0;
33155         } break;
33156
33157         case ma_format_s24:
33158         {
33159             par.bits = 24;
33160             par.bps  = 3;
33161             par.sig  = 1;
33162         } break;
33163
33164         case ma_format_s32:
33165         {
33166             par.bits = 32;
33167             par.bps  = 4;
33168             par.sig  = 1;
33169         } break;
33170
33171         case ma_format_s16:
33172         case ma_format_f32:
33173         case ma_format_unknown:
33174         default:
33175         {
33176             par.bits = 16;
33177             par.bps  = 2;
33178             par.sig  = 1;
33179         } break;
33180     }
33181
33182     if (deviceType == ma_device_type_capture) {
33183         par.rchan = channels;
33184     } else {
33185         par.pchan = channels;
33186     }
33187
33188     par.rate = sampleRate;
33189
33190     internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, par.rate, pConfig->performanceProfile);
33191
33192     par.round    = internalPeriodSizeInFrames;
33193     par.appbufsz = par.round * pDescriptor->periodCount;
33194
33195     if (((ma_sio_setpar_proc)pDevice->pContext->sndio.sio_setpar)((struct ma_sio_hdl*)handle, &par) == 0) {
33196         ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle);
33197         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to set buffer size.");
33198         return MA_ERROR;
33199     }
33200
33201     if (((ma_sio_getpar_proc)pDevice->pContext->sndio.sio_getpar)((struct ma_sio_hdl*)handle, &par) == 0) {
33202         ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle);
33203         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve buffer size.");
33204         return MA_ERROR;
33205     }
33206
33207     internalFormat             = ma_format_from_sio_enc__sndio(par.bits, par.bps, par.sig, par.le, par.msb);
33208     internalChannels           = (deviceType == ma_device_type_capture) ? par.rchan : par.pchan;
33209     internalSampleRate         = par.rate;
33210     internalPeriods            = par.appbufsz / par.round;
33211     internalPeriodSizeInFrames = par.round;
33212
33213     if (deviceType == ma_device_type_capture) {
33214         pDevice->sndio.handleCapture  = handle;
33215     } else {
33216         pDevice->sndio.handlePlayback = handle;
33217     }
33218
33219     pDescriptor->format             = internalFormat;
33220     pDescriptor->channels           = internalChannels;
33221     pDescriptor->sampleRate         = internalSampleRate;
33222     ma_channel_map_init_standard(ma_standard_channel_map_sndio, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), internalChannels);
33223     pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames;
33224     pDescriptor->periodCount        = internalPeriods;
33225
33226     #ifdef MA_DEBUG_OUTPUT
33227     {
33228         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "DEVICE INFO\n");
33229         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Format:      %s\n", ma_get_format_name(internalFormat));
33230         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Channels:    %d\n", internalChannels);
33231         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Sample Rate: %d\n", internalSampleRate);
33232         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Period Size: %d\n", internalPeriodSizeInFrames);
33233         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Periods:     %d\n", internalPeriods);
33234         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    appbufsz:    %d\n", par.appbufsz);
33235         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    round:       %d\n", par.round);
33236     }
33237     #endif
33238
33239     return MA_SUCCESS;
33240 }
33241
33242 static ma_result ma_device_init__sndio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
33243 {
33244     MA_ASSERT(pDevice != NULL);
33245
33246     MA_ZERO_OBJECT(&pDevice->sndio);
33247
33248     if (pConfig->deviceType == ma_device_type_loopback) {
33249         return MA_DEVICE_TYPE_NOT_SUPPORTED;
33250     }
33251
33252     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
33253         ma_result result = ma_device_init_handle__sndio(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
33254         if (result != MA_SUCCESS) {
33255             return result;
33256         }
33257     }
33258
33259     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
33260         ma_result result = ma_device_init_handle__sndio(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
33261         if (result != MA_SUCCESS) {
33262             return result;
33263         }
33264     }
33265
33266     return MA_SUCCESS;
33267 }
33268
33269 static ma_result ma_device_start__sndio(ma_device* pDevice)
33270 {
33271     MA_ASSERT(pDevice != NULL);
33272
33273     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
33274         ((ma_sio_start_proc)pDevice->pContext->sndio.sio_start)((struct ma_sio_hdl*)pDevice->sndio.handleCapture);
33275     }
33276
33277     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
33278         ((ma_sio_start_proc)pDevice->pContext->sndio.sio_start)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback);   /* <-- Doesn't actually playback until data is written. */
33279     }
33280
33281     return MA_SUCCESS;
33282 }
33283
33284 static ma_result ma_device_stop__sndio(ma_device* pDevice)
33285 {
33286     MA_ASSERT(pDevice != NULL);
33287
33288     /*
33289     From the documentation:
33290
33291         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
33292         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
33293         buffer is drained. In no case are samples in the play buffer discarded.
33294
33295     Therefore, sio_stop() performs all of the necessary draining for us.
33296     */
33297
33298     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
33299         ((ma_sio_stop_proc)pDevice->pContext->sndio.sio_stop)((struct ma_sio_hdl*)pDevice->sndio.handleCapture);
33300     }
33301
33302     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
33303         ((ma_sio_stop_proc)pDevice->pContext->sndio.sio_stop)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback);
33304     }
33305
33306     return MA_SUCCESS;
33307 }
33308
33309 static ma_result ma_device_write__sndio(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
33310 {
33311     int result;
33312
33313     if (pFramesWritten != NULL) {
33314         *pFramesWritten = 0;
33315     }
33316
33317     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));
33318     if (result == 0) {
33319         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to send data from the client to the device.");
33320         return MA_IO_ERROR;
33321     }
33322
33323     if (pFramesWritten != NULL) {
33324         *pFramesWritten = frameCount;
33325     }
33326
33327     return MA_SUCCESS;
33328 }
33329
33330 static ma_result ma_device_read__sndio(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
33331 {
33332     int result;
33333
33334     if (pFramesRead != NULL) {
33335         *pFramesRead = 0;
33336     }
33337
33338     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));
33339     if (result == 0) {
33340         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[sndio] Failed to read data from the device to be sent to the device.");
33341         return MA_IO_ERROR;
33342     }
33343
33344     if (pFramesRead != NULL) {
33345         *pFramesRead = frameCount;
33346     }
33347
33348     return MA_SUCCESS;
33349 }
33350
33351 static ma_result ma_context_uninit__sndio(ma_context* pContext)
33352 {
33353     MA_ASSERT(pContext != NULL);
33354     MA_ASSERT(pContext->backend == ma_backend_sndio);
33355
33356     (void)pContext;
33357     return MA_SUCCESS;
33358 }
33359
33360 static ma_result ma_context_init__sndio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
33361 {
33362 #ifndef MA_NO_RUNTIME_LINKING
33363     const char* libsndioNames[] = {
33364         "libsndio.so"
33365     };
33366     size_t i;
33367
33368     for (i = 0; i < ma_countof(libsndioNames); ++i) {
33369         pContext->sndio.sndioSO = ma_dlopen(pContext, libsndioNames[i]);
33370         if (pContext->sndio.sndioSO != NULL) {
33371             break;
33372         }
33373     }
33374
33375     if (pContext->sndio.sndioSO == NULL) {
33376         return MA_NO_BACKEND;
33377     }
33378
33379     pContext->sndio.sio_open    = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_open");
33380     pContext->sndio.sio_close   = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_close");
33381     pContext->sndio.sio_setpar  = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_setpar");
33382     pContext->sndio.sio_getpar  = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getpar");
33383     pContext->sndio.sio_getcap  = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getcap");
33384     pContext->sndio.sio_write   = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_write");
33385     pContext->sndio.sio_read    = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_read");
33386     pContext->sndio.sio_start   = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_start");
33387     pContext->sndio.sio_stop    = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_stop");
33388     pContext->sndio.sio_initpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_initpar");
33389 #else
33390     pContext->sndio.sio_open    = sio_open;
33391     pContext->sndio.sio_close   = sio_close;
33392     pContext->sndio.sio_setpar  = sio_setpar;
33393     pContext->sndio.sio_getpar  = sio_getpar;
33394     pContext->sndio.sio_getcap  = sio_getcap;
33395     pContext->sndio.sio_write   = sio_write;
33396     pContext->sndio.sio_read    = sio_read;
33397     pContext->sndio.sio_start   = sio_start;
33398     pContext->sndio.sio_stop    = sio_stop;
33399     pContext->sndio.sio_initpar = sio_initpar;
33400 #endif
33401
33402     pCallbacks->onContextInit             = ma_context_init__sndio;
33403     pCallbacks->onContextUninit           = ma_context_uninit__sndio;
33404     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__sndio;
33405     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__sndio;
33406     pCallbacks->onDeviceInit              = ma_device_init__sndio;
33407     pCallbacks->onDeviceUninit            = ma_device_uninit__sndio;
33408     pCallbacks->onDeviceStart             = ma_device_start__sndio;
33409     pCallbacks->onDeviceStop              = ma_device_stop__sndio;
33410     pCallbacks->onDeviceRead              = ma_device_read__sndio;
33411     pCallbacks->onDeviceWrite             = ma_device_write__sndio;
33412     pCallbacks->onDeviceDataLoop          = NULL;
33413
33414     (void)pConfig;
33415     return MA_SUCCESS;
33416 }
33417 #endif  /* sndio */
33418
33419
33420
33421 /******************************************************************************
33422
33423 audio(4) Backend
33424
33425 ******************************************************************************/
33426 #ifdef MA_HAS_AUDIO4
33427 #include <fcntl.h>
33428 #include <poll.h>
33429 #include <errno.h>
33430 #include <sys/stat.h>
33431 #include <sys/types.h>
33432 #include <sys/ioctl.h>
33433 #include <sys/audioio.h>
33434
33435 #if defined(__OpenBSD__)
33436     #include <sys/param.h>
33437     #if defined(OpenBSD) && OpenBSD >= 201709
33438         #define MA_AUDIO4_USE_NEW_API
33439     #endif
33440 #endif
33441
33442 static void ma_construct_device_id__audio4(char* id, size_t idSize, const char* base, int deviceIndex)
33443 {
33444     size_t baseLen;
33445
33446     MA_ASSERT(id != NULL);
33447     MA_ASSERT(idSize > 0);
33448     MA_ASSERT(deviceIndex >= 0);
33449
33450     baseLen = strlen(base);
33451     MA_ASSERT(idSize > baseLen);
33452
33453     ma_strcpy_s(id, idSize, base);
33454     ma_itoa_s(deviceIndex, id+baseLen, idSize-baseLen, 10);
33455 }
33456
33457 static ma_result ma_extract_device_index_from_id__audio4(const char* id, const char* base, int* pIndexOut)
33458 {
33459     size_t idLen;
33460     size_t baseLen;
33461     const char* deviceIndexStr;
33462
33463     MA_ASSERT(id != NULL);
33464     MA_ASSERT(base != NULL);
33465     MA_ASSERT(pIndexOut != NULL);
33466
33467     idLen = strlen(id);
33468     baseLen = strlen(base);
33469     if (idLen <= baseLen) {
33470         return MA_ERROR;   /* Doesn't look like the id starts with the base. */
33471     }
33472
33473     if (strncmp(id, base, baseLen) != 0) {
33474         return MA_ERROR;   /* ID does not begin with base. */
33475     }
33476
33477     deviceIndexStr = id + baseLen;
33478     if (deviceIndexStr[0] == '\0') {
33479         return MA_ERROR;   /* No index specified in the ID. */
33480     }
33481
33482     if (pIndexOut) {
33483         *pIndexOut = atoi(deviceIndexStr);
33484     }
33485
33486     return MA_SUCCESS;
33487 }
33488
33489
33490 #if !defined(MA_AUDIO4_USE_NEW_API)    /* Old API */
33491 static ma_format ma_format_from_encoding__audio4(unsigned int encoding, unsigned int precision)
33492 {
33493     if (precision == 8 && (encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR_LE || encoding == AUDIO_ENCODING_ULINEAR_BE)) {
33494         return ma_format_u8;
33495     } else {
33496         if (ma_is_little_endian() && encoding == AUDIO_ENCODING_SLINEAR_LE) {
33497             if (precision == 16) {
33498                 return ma_format_s16;
33499             } else if (precision == 24) {
33500                 return ma_format_s24;
33501             } else if (precision == 32) {
33502                 return ma_format_s32;
33503             }
33504         } else if (ma_is_big_endian() && encoding == AUDIO_ENCODING_SLINEAR_BE) {
33505             if (precision == 16) {
33506                 return ma_format_s16;
33507             } else if (precision == 24) {
33508                 return ma_format_s24;
33509             } else if (precision == 32) {
33510                 return ma_format_s32;
33511             }
33512         }
33513     }
33514
33515     return ma_format_unknown;  /* Encoding not supported. */
33516 }
33517
33518 static void ma_encoding_from_format__audio4(ma_format format, unsigned int* pEncoding, unsigned int* pPrecision)
33519 {
33520     MA_ASSERT(pEncoding  != NULL);
33521     MA_ASSERT(pPrecision != NULL);
33522
33523     switch (format)
33524     {
33525         case ma_format_u8:
33526         {
33527             *pEncoding = AUDIO_ENCODING_ULINEAR;
33528             *pPrecision = 8;
33529         } break;
33530
33531         case ma_format_s24:
33532         {
33533             *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
33534             *pPrecision = 24;
33535         } break;
33536
33537         case ma_format_s32:
33538         {
33539             *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
33540             *pPrecision = 32;
33541         } break;
33542
33543         case ma_format_s16:
33544         case ma_format_f32:
33545         case ma_format_unknown:
33546         default:
33547         {
33548             *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
33549             *pPrecision = 16;
33550         } break;
33551     }
33552 }
33553
33554 static ma_format ma_format_from_prinfo__audio4(struct audio_prinfo* prinfo)
33555 {
33556     return ma_format_from_encoding__audio4(prinfo->encoding, prinfo->precision);
33557 }
33558
33559 static ma_format ma_best_format_from_fd__audio4(int fd, ma_format preferredFormat)
33560 {
33561     audio_encoding_t encoding;
33562     ma_uint32 iFormat;
33563     int counter = 0;
33564
33565     /* First check to see if the preferred format is supported. */
33566     if (preferredFormat != ma_format_unknown) {
33567         counter = 0;
33568         for (;;) {
33569             MA_ZERO_OBJECT(&encoding);
33570             encoding.index = counter;
33571             if (ioctl(fd, AUDIO_GETENC, &encoding) < 0) {
33572                 break;
33573             }
33574
33575             if (preferredFormat == ma_format_from_encoding__audio4(encoding.encoding, encoding.precision)) {
33576                 return preferredFormat;  /* Found the preferred format. */
33577             }
33578
33579             /* Getting here means this encoding does not match our preferred format so we need to more on to the next encoding. */
33580             counter += 1;
33581         }
33582     }
33583
33584     /* Getting here means our preferred format is not supported, so fall back to our standard priorities. */
33585     for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); iFormat += 1) {
33586         ma_format format = g_maFormatPriorities[iFormat];
33587
33588         counter = 0;
33589         for (;;) {
33590             MA_ZERO_OBJECT(&encoding);
33591             encoding.index = counter;
33592             if (ioctl(fd, AUDIO_GETENC, &encoding) < 0) {
33593                 break;
33594             }
33595
33596             if (format == ma_format_from_encoding__audio4(encoding.encoding, encoding.precision)) {
33597                 return format;  /* Found a workable format. */
33598             }
33599
33600             /* Getting here means this encoding does not match our preferred format so we need to more on to the next encoding. */
33601             counter += 1;
33602         }
33603     }
33604
33605     /* Getting here means not appropriate format was found. */
33606     return ma_format_unknown;
33607 }
33608 #else
33609 static ma_format ma_format_from_swpar__audio4(struct audio_swpar* par)
33610 {
33611     if (par->bits == 8 && par->bps == 1 && par->sig == 0) {
33612         return ma_format_u8;
33613     }
33614     if (par->bits == 16 && par->bps == 2 && par->sig == 1 && par->le == ma_is_little_endian()) {
33615         return ma_format_s16;
33616     }
33617     if (par->bits == 24 && par->bps == 3 && par->sig == 1 && par->le == ma_is_little_endian()) {
33618         return ma_format_s24;
33619     }
33620     if (par->bits == 32 && par->bps == 4 && par->sig == 1 && par->le == ma_is_little_endian()) {
33621         return ma_format_f32;
33622     }
33623
33624     /* Format not supported. */
33625     return ma_format_unknown;
33626 }
33627 #endif
33628
33629 static ma_result ma_context_get_device_info_from_fd__audio4(ma_context* pContext, ma_device_type deviceType, int fd, ma_device_info* pDeviceInfo)
33630 {
33631     audio_device_t fdDevice;
33632
33633     MA_ASSERT(pContext != NULL);
33634     MA_ASSERT(fd >= 0);
33635     MA_ASSERT(pDeviceInfo != NULL);
33636
33637     (void)pContext;
33638     (void)deviceType;
33639
33640     if (ioctl(fd, AUDIO_GETDEV, &fdDevice) < 0) {
33641         return MA_ERROR;   /* Failed to retrieve device info. */
33642     }
33643
33644     /* Name. */
33645     ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), fdDevice.name);
33646
33647     #if !defined(MA_AUDIO4_USE_NEW_API)
33648     {
33649         audio_info_t fdInfo;
33650         int counter = 0;
33651         ma_uint32 channels;
33652         ma_uint32 sampleRate;
33653
33654         if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) {
33655             return MA_ERROR;
33656         }
33657
33658         if (deviceType == ma_device_type_playback) {
33659             channels   = fdInfo.play.channels;
33660             sampleRate = fdInfo.play.sample_rate;
33661         } else {
33662             channels   = fdInfo.record.channels;
33663             sampleRate = fdInfo.record.sample_rate;
33664         }
33665
33666         /* Supported formats. We get this by looking at the encodings. */
33667         pDeviceInfo->nativeDataFormatCount = 0;
33668         for (;;) {
33669             audio_encoding_t encoding;
33670             ma_format format;
33671
33672             MA_ZERO_OBJECT(&encoding);
33673             encoding.index = counter;
33674             if (ioctl(fd, AUDIO_GETENC, &encoding) < 0) {
33675                 break;
33676             }
33677
33678             format = ma_format_from_encoding__audio4(encoding.encoding, encoding.precision);
33679             if (format != ma_format_unknown) {
33680                 ma_device_info_add_native_data_format(pDeviceInfo, format, channels, sampleRate, 0);
33681             }
33682
33683             counter += 1;
33684         }
33685     }
33686     #else
33687     {
33688         struct audio_swpar fdPar;
33689         ma_format format;
33690         ma_uint32 channels;
33691         ma_uint32 sampleRate;
33692
33693         if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) {
33694             return MA_ERROR;
33695         }
33696
33697         format = ma_format_from_swpar__audio4(&fdPar);
33698         if (format == ma_format_unknown) {
33699             return MA_FORMAT_NOT_SUPPORTED;
33700         }
33701
33702         if (deviceType == ma_device_type_playback) {
33703             channels = fdPar.pchan;
33704         } else {
33705             channels = fdPar.rchan;
33706         }
33707
33708         sampleRate = fdPar.rate;
33709
33710         pDeviceInfo->nativeDataFormatCount = 0;
33711         ma_device_info_add_native_data_format(pDeviceInfo, format, channels, sampleRate, 0);
33712     }
33713     #endif
33714
33715     return MA_SUCCESS;
33716 }
33717
33718 static ma_result ma_context_enumerate_devices__audio4(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
33719 {
33720     const int maxDevices = 64;
33721     char devpath[256];
33722     int iDevice;
33723
33724     MA_ASSERT(pContext != NULL);
33725     MA_ASSERT(callback != NULL);
33726
33727     /*
33728     Every device will be named "/dev/audioN", with a "/dev/audioctlN" equivalent. We use the "/dev/audioctlN"
33729     version here since we can open it even when another process has control of the "/dev/audioN" device.
33730     */
33731     for (iDevice = 0; iDevice < maxDevices; ++iDevice) {
33732         struct stat st;
33733         int fd;
33734         ma_bool32 isTerminating = MA_FALSE;
33735
33736         ma_strcpy_s(devpath, sizeof(devpath), "/dev/audioctl");
33737         ma_itoa_s(iDevice, devpath+strlen(devpath), sizeof(devpath)-strlen(devpath), 10);
33738
33739         if (stat(devpath, &st) < 0) {
33740             break;
33741         }
33742
33743         /* The device exists, but we need to check if it's usable as playback and/or capture. */
33744
33745         /* Playback. */
33746         if (!isTerminating) {
33747             fd = open(devpath, O_RDONLY, 0);
33748             if (fd >= 0) {
33749                 /* Supports playback. */
33750                 ma_device_info deviceInfo;
33751                 MA_ZERO_OBJECT(&deviceInfo);
33752                 ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice);
33753                 if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_playback, fd, &deviceInfo) == MA_SUCCESS) {
33754                     isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
33755                 }
33756
33757                 close(fd);
33758             }
33759         }
33760
33761         /* Capture. */
33762         if (!isTerminating) {
33763             fd = open(devpath, O_WRONLY, 0);
33764             if (fd >= 0) {
33765                 /* Supports capture. */
33766                 ma_device_info deviceInfo;
33767                 MA_ZERO_OBJECT(&deviceInfo);
33768                 ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice);
33769                 if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_capture, fd, &deviceInfo) == MA_SUCCESS) {
33770                     isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
33771                 }
33772
33773                 close(fd);
33774             }
33775         }
33776
33777         if (isTerminating) {
33778             break;
33779         }
33780     }
33781
33782     return MA_SUCCESS;
33783 }
33784
33785 static ma_result ma_context_get_device_info__audio4(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
33786 {
33787     int fd = -1;
33788     int deviceIndex = -1;
33789     char ctlid[256];
33790     ma_result result;
33791
33792     MA_ASSERT(pContext != NULL);
33793
33794     /*
33795     We need to open the "/dev/audioctlN" device to get the info. To do this we need to extract the number
33796     from the device ID which will be in "/dev/audioN" format.
33797     */
33798     if (pDeviceID == NULL) {
33799         /* Default device. */
33800         ma_strcpy_s(ctlid, sizeof(ctlid), "/dev/audioctl");
33801     } else {
33802         /* Specific device. We need to convert from "/dev/audioN" to "/dev/audioctlN". */
33803         result = ma_extract_device_index_from_id__audio4(pDeviceID->audio4, "/dev/audio", &deviceIndex);
33804         if (result != MA_SUCCESS) {
33805             return result;
33806         }
33807
33808         ma_construct_device_id__audio4(ctlid, sizeof(ctlid), "/dev/audioctl", deviceIndex);
33809     }
33810
33811     fd = open(ctlid, (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY, 0);
33812     if (fd == -1) {
33813         return MA_NO_DEVICE;
33814     }
33815
33816     if (deviceIndex == -1) {
33817         ma_strcpy_s(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio");
33818     } else {
33819         ma_construct_device_id__audio4(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio", deviceIndex);
33820     }
33821
33822     result = ma_context_get_device_info_from_fd__audio4(pContext, deviceType, fd, pDeviceInfo);
33823
33824     close(fd);
33825     return result;
33826 }
33827
33828 static ma_result ma_device_uninit__audio4(ma_device* pDevice)
33829 {
33830     MA_ASSERT(pDevice != NULL);
33831
33832     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
33833         close(pDevice->audio4.fdCapture);
33834     }
33835
33836     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
33837         close(pDevice->audio4.fdPlayback);
33838     }
33839
33840     return MA_SUCCESS;
33841 }
33842
33843 static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType)
33844 {
33845     const char* pDefaultDeviceNames[] = {
33846         "/dev/audio",
33847         "/dev/audio0"
33848     };
33849     int fd;
33850     int fdFlags = 0;
33851     ma_format internalFormat;
33852     ma_uint32 internalChannels;
33853     ma_uint32 internalSampleRate;
33854     ma_uint32 internalPeriodSizeInFrames;
33855     ma_uint32 internalPeriods;
33856
33857     MA_ASSERT(pConfig    != NULL);
33858     MA_ASSERT(deviceType != ma_device_type_duplex);
33859     MA_ASSERT(pDevice    != NULL);
33860
33861     /* The first thing to do is open the file. */
33862     if (deviceType == ma_device_type_capture) {
33863         fdFlags = O_RDONLY;
33864     } else {
33865         fdFlags = O_WRONLY;
33866     }
33867     /*fdFlags |= O_NONBLOCK;*/
33868
33869     if (pDescriptor->pDeviceID == NULL) {
33870         /* Default device. */
33871         size_t iDevice;
33872         for (iDevice = 0; iDevice < ma_countof(pDefaultDeviceNames); ++iDevice) {
33873             fd = open(pDefaultDeviceNames[iDevice], fdFlags, 0);
33874             if (fd != -1) {
33875                 break;
33876             }
33877         }
33878     } else {
33879         /* Specific device. */
33880         fd = open(pDescriptor->pDeviceID->audio4, fdFlags, 0);
33881     }
33882
33883     if (fd == -1) {
33884         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to open device.");
33885         return ma_result_from_errno(errno);
33886     }
33887
33888     #if !defined(MA_AUDIO4_USE_NEW_API)    /* Old API */
33889     {
33890         audio_info_t fdInfo;
33891
33892         /*
33893         The documentation is a little bit unclear to me as to how it handles formats. It says the
33894         following:
33895
33896             Regardless of formats supported by underlying driver, the audio driver accepts the
33897             following formats.
33898
33899         By then the next sentence says this:
33900
33901             `encoding` and `precision` are one of the values obtained by AUDIO_GETENC.
33902
33903         It sounds like a direct contradiction to me. I'm going to play this safe any only use the
33904         best sample format returned by AUDIO_GETENC. If the requested format is supported we'll
33905         use that, but otherwise we'll just use our standard format priorities to pick an
33906         appropriate one.
33907         */
33908         AUDIO_INITINFO(&fdInfo);
33909
33910         /* We get the driver to do as much of the data conversion as possible. */
33911         if (deviceType == ma_device_type_capture) {
33912             fdInfo.mode = AUMODE_RECORD;
33913             ma_encoding_from_format__audio4(ma_best_format_from_fd__audio4(fd, pDescriptor->format), &fdInfo.record.encoding, &fdInfo.record.precision);
33914
33915             if (pDescriptor->channels != 0) {
33916                 fdInfo.record.channels = ma_clamp(pDescriptor->channels, 1, 12);    /* From the documentation: `channels` ranges from 1 to 12. */
33917             }
33918
33919             if (pDescriptor->sampleRate != 0) {
33920                 fdInfo.record.sample_rate = ma_clamp(pDescriptor->sampleRate, 1000, 192000);    /* From the documentation: `frequency` ranges from 1000Hz to 192000Hz. (They mean `sample_rate` instead of `frequency`.) */
33921             }
33922         } else {
33923             fdInfo.mode = AUMODE_PLAY;
33924             ma_encoding_from_format__audio4(ma_best_format_from_fd__audio4(fd, pDescriptor->format), &fdInfo.play.encoding, &fdInfo.play.precision);
33925
33926             if (pDescriptor->channels != 0) {
33927                 fdInfo.play.channels = ma_clamp(pDescriptor->channels, 1, 12);    /* From the documentation: `channels` ranges from 1 to 12. */
33928             }
33929
33930             if (pDescriptor->sampleRate != 0) {
33931                 fdInfo.play.sample_rate = ma_clamp(pDescriptor->sampleRate, 1000, 192000);    /* From the documentation: `frequency` ranges from 1000Hz to 192000Hz. (They mean `sample_rate` instead of `frequency`.) */
33932             }
33933         }
33934
33935         if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) {
33936             close(fd);
33937             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device format. AUDIO_SETINFO failed.");
33938             return ma_result_from_errno(errno);
33939         }
33940
33941         if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) {
33942             close(fd);
33943             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed.");
33944             return ma_result_from_errno(errno);
33945         }
33946
33947         if (deviceType == ma_device_type_capture) {
33948             internalFormat     = ma_format_from_prinfo__audio4(&fdInfo.record);
33949             internalChannels   = fdInfo.record.channels;
33950             internalSampleRate = fdInfo.record.sample_rate;
33951         } else {
33952             internalFormat     = ma_format_from_prinfo__audio4(&fdInfo.play);
33953             internalChannels   = fdInfo.play.channels;
33954             internalSampleRate = fdInfo.play.sample_rate;
33955         }
33956
33957         if (internalFormat == ma_format_unknown) {
33958             close(fd);
33959             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.");
33960             return MA_FORMAT_NOT_SUPPORTED;
33961         }
33962
33963         /* Buffer. */
33964         {
33965             ma_uint32 internalPeriodSizeInBytes;
33966
33967             internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, internalSampleRate, pConfig->performanceProfile);
33968
33969             internalPeriodSizeInBytes = internalPeriodSizeInFrames * ma_get_bytes_per_frame(internalFormat, internalChannels);
33970             if (internalPeriodSizeInBytes < 16) {
33971                 internalPeriodSizeInBytes = 16;
33972             }
33973
33974             internalPeriods = pDescriptor->periodCount;
33975             if (internalPeriods < 2) {
33976                 internalPeriods = 2;
33977             }
33978
33979             /* What miniaudio calls a period, audio4 calls a block. */
33980             AUDIO_INITINFO(&fdInfo);
33981             fdInfo.hiwat     = internalPeriods;
33982             fdInfo.lowat     = internalPeriods-1;
33983             fdInfo.blocksize = internalPeriodSizeInBytes;
33984             if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) {
33985                 close(fd);
33986                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set internal buffer size. AUDIO_SETINFO failed.");
33987                 return ma_result_from_errno(errno);
33988             }
33989
33990             internalPeriods            = fdInfo.hiwat;
33991             internalPeriodSizeInFrames = fdInfo.blocksize / ma_get_bytes_per_frame(internalFormat, internalChannels);
33992         }
33993     }
33994     #else
33995     {
33996         struct audio_swpar fdPar;
33997
33998         /* 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. */
33999         if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) {
34000             close(fd);
34001             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve initial device parameters.");
34002             return ma_result_from_errno(errno);
34003         }
34004
34005         internalFormat     = ma_format_from_swpar__audio4(&fdPar);
34006         internalChannels   = (deviceType == ma_device_type_capture) ? fdPar.rchan : fdPar.pchan;
34007         internalSampleRate = fdPar.rate;
34008
34009         if (internalFormat == ma_format_unknown) {
34010             close(fd);
34011             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.");
34012             return MA_FORMAT_NOT_SUPPORTED;
34013         }
34014
34015         /* Buffer. */
34016         {
34017             ma_uint32 internalPeriodSizeInBytes;
34018
34019             internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, internalSampleRate, pConfig->performanceProfile);
34020
34021             /* What miniaudio calls a period, audio4 calls a block. */
34022             internalPeriodSizeInBytes = internalPeriodSizeInFrames * ma_get_bytes_per_frame(internalFormat, internalChannels);
34023             if (internalPeriodSizeInBytes < 16) {
34024                 internalPeriodSizeInBytes = 16;
34025             }
34026
34027             fdPar.nblks = pDescriptor->periodCount;
34028             fdPar.round = internalPeriodSizeInBytes;
34029
34030             if (ioctl(fd, AUDIO_SETPAR, &fdPar) < 0) {
34031                 close(fd);
34032                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device parameters.");
34033                 return ma_result_from_errno(errno);
34034             }
34035
34036             if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) {
34037                 close(fd);
34038                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve actual device parameters.");
34039                 return ma_result_from_errno(errno);
34040             }
34041         }
34042
34043         internalFormat             = ma_format_from_swpar__audio4(&fdPar);
34044         internalChannels           = (deviceType == ma_device_type_capture) ? fdPar.rchan : fdPar.pchan;
34045         internalSampleRate         = fdPar.rate;
34046         internalPeriods            = fdPar.nblks;
34047         internalPeriodSizeInFrames = fdPar.round / ma_get_bytes_per_frame(internalFormat, internalChannels);
34048     }
34049     #endif
34050
34051     if (internalFormat == ma_format_unknown) {
34052         close(fd);
34053         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.");
34054         return MA_FORMAT_NOT_SUPPORTED;
34055     }
34056
34057     if (deviceType == ma_device_type_capture) {
34058         pDevice->audio4.fdCapture  = fd;
34059     } else {
34060         pDevice->audio4.fdPlayback = fd;
34061     }
34062
34063     pDescriptor->format             = internalFormat;
34064     pDescriptor->channels           = internalChannels;
34065     pDescriptor->sampleRate         = internalSampleRate;
34066     ma_channel_map_init_standard(ma_standard_channel_map_sound4, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), internalChannels);
34067     pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames;
34068     pDescriptor->periodCount        = internalPeriods;
34069
34070     return MA_SUCCESS;
34071 }
34072
34073 static ma_result ma_device_init__audio4(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
34074 {
34075     MA_ASSERT(pDevice != NULL);
34076
34077     MA_ZERO_OBJECT(&pDevice->audio4);
34078
34079     if (pConfig->deviceType == ma_device_type_loopback) {
34080         return MA_DEVICE_TYPE_NOT_SUPPORTED;
34081     }
34082
34083     pDevice->audio4.fdCapture  = -1;
34084     pDevice->audio4.fdPlayback = -1;
34085
34086     /*
34087     The version of the operating system dictates whether or not the device is exclusive or shared. NetBSD
34088     introduced in-kernel mixing which means it's shared. All other BSD flavours are exclusive as far as
34089     I'm aware.
34090     */
34091 #if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 800000000
34092     /* NetBSD 8.0+ */
34093     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
34094         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive)) {
34095         return MA_SHARE_MODE_NOT_SUPPORTED;
34096     }
34097 #else
34098     /* All other flavors. */
34099 #endif
34100
34101     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
34102         ma_result result = ma_device_init_fd__audio4(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
34103         if (result != MA_SUCCESS) {
34104             return result;
34105         }
34106     }
34107
34108     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
34109         ma_result result = ma_device_init_fd__audio4(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
34110         if (result != MA_SUCCESS) {
34111             if (pConfig->deviceType == ma_device_type_duplex) {
34112                 close(pDevice->audio4.fdCapture);
34113             }
34114             return result;
34115         }
34116     }
34117
34118     return MA_SUCCESS;
34119 }
34120
34121 static ma_result ma_device_start__audio4(ma_device* pDevice)
34122 {
34123     MA_ASSERT(pDevice != NULL);
34124
34125     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
34126         if (pDevice->audio4.fdCapture == -1) {
34127             return MA_INVALID_ARGS;
34128         }
34129     }
34130
34131     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
34132         if (pDevice->audio4.fdPlayback == -1) {
34133             return MA_INVALID_ARGS;
34134         }
34135     }
34136
34137     return MA_SUCCESS;
34138 }
34139
34140 static ma_result ma_device_stop_fd__audio4(ma_device* pDevice, int fd)
34141 {
34142     if (fd == -1) {
34143         return MA_INVALID_ARGS;
34144     }
34145
34146 #if !defined(MA_AUDIO4_USE_NEW_API)
34147     if (ioctl(fd, AUDIO_FLUSH, 0) < 0) {
34148         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_FLUSH failed.");
34149         return ma_result_from_errno(errno);
34150     }
34151 #else
34152     if (ioctl(fd, AUDIO_STOP, 0) < 0) {
34153         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_STOP failed.");
34154         return ma_result_from_errno(errno);
34155     }
34156 #endif
34157
34158     return MA_SUCCESS;
34159 }
34160
34161 static ma_result ma_device_stop__audio4(ma_device* pDevice)
34162 {
34163     MA_ASSERT(pDevice != NULL);
34164
34165     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
34166         ma_result result;
34167
34168         result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdCapture);
34169         if (result != MA_SUCCESS) {
34170             return result;
34171         }
34172     }
34173
34174     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
34175         ma_result result;
34176
34177         /* 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. */
34178     #if !defined(MA_AUDIO4_USE_NEW_API)
34179         ioctl(pDevice->audio4.fdPlayback, AUDIO_DRAIN, 0);
34180     #endif
34181
34182         /* Here is where the device is stopped immediately. */
34183         result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdPlayback);
34184         if (result != MA_SUCCESS) {
34185             return result;
34186         }
34187     }
34188
34189     return MA_SUCCESS;
34190 }
34191
34192 static ma_result ma_device_write__audio4(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
34193 {
34194     int result;
34195
34196     if (pFramesWritten != NULL) {
34197         *pFramesWritten = 0;
34198     }
34199
34200     result = write(pDevice->audio4.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
34201     if (result < 0) {
34202         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to write data to the device.");
34203         return ma_result_from_errno(errno);
34204     }
34205
34206     if (pFramesWritten != NULL) {
34207         *pFramesWritten = (ma_uint32)result / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
34208     }
34209
34210     return MA_SUCCESS;
34211 }
34212
34213 static ma_result ma_device_read__audio4(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
34214 {
34215     int result;
34216
34217     if (pFramesRead != NULL) {
34218         *pFramesRead = 0;
34219     }
34220
34221     result = read(pDevice->audio4.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
34222     if (result < 0) {
34223         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[audio4] Failed to read data from the device.");
34224         return ma_result_from_errno(errno);
34225     }
34226
34227     if (pFramesRead != NULL) {
34228         *pFramesRead = (ma_uint32)result / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
34229     }
34230
34231     return MA_SUCCESS;
34232 }
34233
34234 static ma_result ma_context_uninit__audio4(ma_context* pContext)
34235 {
34236     MA_ASSERT(pContext != NULL);
34237     MA_ASSERT(pContext->backend == ma_backend_audio4);
34238
34239     (void)pContext;
34240     return MA_SUCCESS;
34241 }
34242
34243 static ma_result ma_context_init__audio4(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
34244 {
34245     MA_ASSERT(pContext != NULL);
34246
34247     (void)pConfig;
34248
34249     pCallbacks->onContextInit             = ma_context_init__audio4;
34250     pCallbacks->onContextUninit           = ma_context_uninit__audio4;
34251     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__audio4;
34252     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__audio4;
34253     pCallbacks->onDeviceInit              = ma_device_init__audio4;
34254     pCallbacks->onDeviceUninit            = ma_device_uninit__audio4;
34255     pCallbacks->onDeviceStart             = ma_device_start__audio4;
34256     pCallbacks->onDeviceStop              = ma_device_stop__audio4;
34257     pCallbacks->onDeviceRead              = ma_device_read__audio4;
34258     pCallbacks->onDeviceWrite             = ma_device_write__audio4;
34259     pCallbacks->onDeviceDataLoop          = NULL;
34260
34261     return MA_SUCCESS;
34262 }
34263 #endif  /* audio4 */
34264
34265
34266 /******************************************************************************
34267
34268 OSS Backend
34269
34270 ******************************************************************************/
34271 #ifdef MA_HAS_OSS
34272 #include <sys/ioctl.h>
34273 #include <unistd.h>
34274 #include <fcntl.h>
34275 #include <sys/soundcard.h>
34276
34277 #ifndef SNDCTL_DSP_HALT
34278 #define SNDCTL_DSP_HALT SNDCTL_DSP_RESET
34279 #endif
34280
34281 #define MA_OSS_DEFAULT_DEVICE_NAME  "/dev/dsp"
34282
34283 static int ma_open_temp_device__oss()
34284 {
34285     /* The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. */
34286     int fd = open("/dev/mixer", O_RDONLY, 0);
34287     if (fd >= 0) {
34288         return fd;
34289     }
34290
34291     return -1;
34292 }
34293
34294 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)
34295 {
34296     const char* deviceName;
34297     int flags;
34298
34299     MA_ASSERT(pContext != NULL);
34300     MA_ASSERT(pfd != NULL);
34301     (void)pContext;
34302
34303     *pfd = -1;
34304
34305     /* This function should only be called for playback or capture, not duplex. */
34306     if (deviceType == ma_device_type_duplex) {
34307         return MA_INVALID_ARGS;
34308     }
34309
34310     deviceName = MA_OSS_DEFAULT_DEVICE_NAME;
34311     if (pDeviceID != NULL) {
34312         deviceName = pDeviceID->oss;
34313     }
34314
34315     flags = (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY;
34316     if (shareMode == ma_share_mode_exclusive) {
34317         flags |= O_EXCL;
34318     }
34319
34320     *pfd = open(deviceName, flags, 0);
34321     if (*pfd == -1) {
34322         return ma_result_from_errno(errno);
34323     }
34324
34325     return MA_SUCCESS;
34326 }
34327
34328 static ma_result ma_context_enumerate_devices__oss(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
34329 {
34330     int fd;
34331     oss_sysinfo si;
34332     int result;
34333
34334     MA_ASSERT(pContext != NULL);
34335     MA_ASSERT(callback != NULL);
34336
34337     fd = ma_open_temp_device__oss();
34338     if (fd == -1) {
34339         ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.");
34340         return MA_NO_BACKEND;
34341     }
34342
34343     result = ioctl(fd, SNDCTL_SYSINFO, &si);
34344     if (result != -1) {
34345         int iAudioDevice;
34346         for (iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) {
34347             oss_audioinfo ai;
34348             ai.dev = iAudioDevice;
34349             result = ioctl(fd, SNDCTL_AUDIOINFO, &ai);
34350             if (result != -1) {
34351                 if (ai.devnode[0] != '\0') {    /* <-- Can be blank, according to documentation. */
34352                     ma_device_info deviceInfo;
34353                     ma_bool32 isTerminating = MA_FALSE;
34354
34355                     MA_ZERO_OBJECT(&deviceInfo);
34356
34357                     /* ID */
34358                     ma_strncpy_s(deviceInfo.id.oss, sizeof(deviceInfo.id.oss), ai.devnode, (size_t)-1);
34359
34360                     /*
34361                     The human readable device name should be in the "ai.handle" variable, but it can
34362                     sometimes be empty in which case we just fall back to "ai.name" which is less user
34363                     friendly, but usually has a value.
34364                     */
34365                     if (ai.handle[0] != '\0') {
34366                         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ai.handle, (size_t)-1);
34367                     } else {
34368                         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ai.name, (size_t)-1);
34369                     }
34370
34371                     /* The device can be both playback and capture. */
34372                     if (!isTerminating && (ai.caps & PCM_CAP_OUTPUT) != 0) {
34373                         isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
34374                     }
34375                     if (!isTerminating && (ai.caps & PCM_CAP_INPUT) != 0) {
34376                         isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
34377                     }
34378
34379                     if (isTerminating) {
34380                         break;
34381                     }
34382                 }
34383             }
34384         }
34385     } else {
34386         close(fd);
34387         ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.");
34388         return MA_NO_BACKEND;
34389     }
34390
34391     close(fd);
34392     return MA_SUCCESS;
34393 }
34394
34395 static void ma_context_add_native_data_format__oss(ma_context* pContext, oss_audioinfo* pAudioInfo, ma_format format, ma_device_info* pDeviceInfo)
34396 {
34397     unsigned int minChannels;
34398     unsigned int maxChannels;
34399     unsigned int iRate;
34400
34401     MA_ASSERT(pContext    != NULL);
34402     MA_ASSERT(pAudioInfo  != NULL);
34403     MA_ASSERT(pDeviceInfo != NULL);
34404
34405     /* If we support all channels we just report 0. */
34406     minChannels = ma_clamp(pAudioInfo->min_channels, MA_MIN_CHANNELS, MA_MAX_CHANNELS);
34407     maxChannels = ma_clamp(pAudioInfo->max_channels, MA_MIN_CHANNELS, MA_MAX_CHANNELS);
34408
34409     /*
34410     OSS has this annoying thing where sample rates can be reported in two ways. We prefer explicitness,
34411     which OSS has in the form of nrates/rates, however there are times where nrates can be 0, in which
34412     case we'll need to use min_rate and max_rate and report only standard rates.
34413     */
34414     if (pAudioInfo->nrates > 0) {
34415         for (iRate = 0; iRate < pAudioInfo->nrates; iRate += 1) {
34416             unsigned int rate = pAudioInfo->rates[iRate];
34417
34418             if (minChannels == MA_MIN_CHANNELS && maxChannels == MA_MAX_CHANNELS) {
34419                 ma_device_info_add_native_data_format(pDeviceInfo, format, 0, rate, 0);   /* Set the channel count to 0 to indicate that all channel counts are supported. */
34420             } else {
34421                 unsigned int iChannel;
34422                 for (iChannel = minChannels; iChannel <= maxChannels; iChannel += 1) {
34423                      ma_device_info_add_native_data_format(pDeviceInfo, format, iChannel, rate, 0);
34424                 }
34425             }
34426         }
34427     } else {
34428         for (iRate = 0; iRate < ma_countof(g_maStandardSampleRatePriorities); iRate += 1) {
34429             ma_uint32 standardRate = g_maStandardSampleRatePriorities[iRate];
34430
34431             if (standardRate >= (ma_uint32)pAudioInfo->min_rate && standardRate <= (ma_uint32)pAudioInfo->max_rate) {
34432                 if (minChannels == MA_MIN_CHANNELS && maxChannels == MA_MAX_CHANNELS) {
34433                     ma_device_info_add_native_data_format(pDeviceInfo, format, 0, standardRate, 0);   /* Set the channel count to 0 to indicate that all channel counts are supported. */
34434                 } else {
34435                     unsigned int iChannel;
34436                     for (iChannel = minChannels; iChannel <= maxChannels; iChannel += 1) {
34437                          ma_device_info_add_native_data_format(pDeviceInfo, format, iChannel, standardRate, 0);
34438                     }
34439                 }
34440             }
34441         }
34442     }
34443 }
34444
34445 static ma_result ma_context_get_device_info__oss(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
34446 {
34447     ma_bool32 foundDevice;
34448     int fdTemp;
34449     oss_sysinfo si;
34450     int result;
34451
34452     MA_ASSERT(pContext != NULL);
34453
34454     /* Handle the default device a little differently. */
34455     if (pDeviceID == NULL) {
34456         if (deviceType == ma_device_type_playback) {
34457             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
34458         } else {
34459             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
34460         }
34461
34462         return MA_SUCCESS;
34463     }
34464
34465
34466     /* If we get here it means we are _not_ using the default device. */
34467     foundDevice = MA_FALSE;
34468
34469     fdTemp = ma_open_temp_device__oss();
34470     if (fdTemp == -1) {
34471         ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.");
34472         return MA_NO_BACKEND;
34473     }
34474
34475     result = ioctl(fdTemp, SNDCTL_SYSINFO, &si);
34476     if (result != -1) {
34477         int iAudioDevice;
34478         for (iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) {
34479             oss_audioinfo ai;
34480             ai.dev = iAudioDevice;
34481             result = ioctl(fdTemp, SNDCTL_AUDIOINFO, &ai);
34482             if (result != -1) {
34483                 if (ma_strcmp(ai.devnode, pDeviceID->oss) == 0) {
34484                     /* It has the same name, so now just confirm the type. */
34485                     if ((deviceType == ma_device_type_playback && ((ai.caps & PCM_CAP_OUTPUT) != 0)) ||
34486                         (deviceType == ma_device_type_capture  && ((ai.caps & PCM_CAP_INPUT)  != 0))) {
34487                         unsigned int formatMask;
34488
34489                         /* ID */
34490                         ma_strncpy_s(pDeviceInfo->id.oss, sizeof(pDeviceInfo->id.oss), ai.devnode, (size_t)-1);
34491
34492                         /*
34493                         The human readable device name should be in the "ai.handle" variable, but it can
34494                         sometimes be empty in which case we just fall back to "ai.name" which is less user
34495                         friendly, but usually has a value.
34496                         */
34497                         if (ai.handle[0] != '\0') {
34498                             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.handle, (size_t)-1);
34499                         } else {
34500                             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.name, (size_t)-1);
34501                         }
34502
34503
34504                         pDeviceInfo->nativeDataFormatCount = 0;
34505
34506                         if (deviceType == ma_device_type_playback) {
34507                             formatMask = ai.oformats;
34508                         } else {
34509                             formatMask = ai.iformats;
34510                         }
34511
34512                         if (((formatMask & AFMT_S16_LE) != 0 && ma_is_little_endian()) || (AFMT_S16_BE && ma_is_big_endian())) {
34513                             ma_context_add_native_data_format__oss(pContext, &ai, ma_format_s16, pDeviceInfo);
34514                         }
34515                         if (((formatMask & AFMT_S32_LE) != 0 && ma_is_little_endian()) || (AFMT_S32_BE && ma_is_big_endian())) {
34516                             ma_context_add_native_data_format__oss(pContext, &ai, ma_format_s32, pDeviceInfo);
34517                         }
34518                         if ((formatMask & AFMT_U8) != 0) {
34519                             ma_context_add_native_data_format__oss(pContext, &ai, ma_format_u8, pDeviceInfo);
34520                         }
34521
34522                         foundDevice = MA_TRUE;
34523                         break;
34524                     }
34525                 }
34526             }
34527         }
34528     } else {
34529         close(fdTemp);
34530         ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.");
34531         return MA_NO_BACKEND;
34532     }
34533
34534
34535     close(fdTemp);
34536
34537     if (!foundDevice) {
34538         return MA_NO_DEVICE;
34539     }
34540
34541     return MA_SUCCESS;
34542 }
34543
34544 static ma_result ma_device_uninit__oss(ma_device* pDevice)
34545 {
34546     MA_ASSERT(pDevice != NULL);
34547
34548     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
34549         close(pDevice->oss.fdCapture);
34550     }
34551
34552     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
34553         close(pDevice->oss.fdPlayback);
34554     }
34555
34556     return MA_SUCCESS;
34557 }
34558
34559 static int ma_format_to_oss(ma_format format)
34560 {
34561     int ossFormat = AFMT_U8;
34562     switch (format) {
34563         case ma_format_s16: ossFormat = (ma_is_little_endian()) ? AFMT_S16_LE : AFMT_S16_BE; break;
34564         case ma_format_s24: ossFormat = (ma_is_little_endian()) ? AFMT_S32_LE : AFMT_S32_BE; break;
34565         case ma_format_s32: ossFormat = (ma_is_little_endian()) ? AFMT_S32_LE : AFMT_S32_BE; break;
34566         case ma_format_f32: ossFormat = (ma_is_little_endian()) ? AFMT_S16_LE : AFMT_S16_BE; break;
34567         case ma_format_u8:
34568         default: ossFormat = AFMT_U8; break;
34569     }
34570
34571     return ossFormat;
34572 }
34573
34574 static ma_format ma_format_from_oss(int ossFormat)
34575 {
34576     if (ossFormat == AFMT_U8) {
34577         return ma_format_u8;
34578     } else {
34579         if (ma_is_little_endian()) {
34580             switch (ossFormat) {
34581                 case AFMT_S16_LE: return ma_format_s16;
34582                 case AFMT_S32_LE: return ma_format_s32;
34583                 default: return ma_format_unknown;
34584             }
34585         } else {
34586             switch (ossFormat) {
34587                 case AFMT_S16_BE: return ma_format_s16;
34588                 case AFMT_S32_BE: return ma_format_s32;
34589                 default: return ma_format_unknown;
34590             }
34591         }
34592     }
34593
34594     return ma_format_unknown;
34595 }
34596
34597 static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType)
34598 {
34599     ma_result result;
34600     int ossResult;
34601     int fd;
34602     const ma_device_id* pDeviceID = NULL;
34603     ma_share_mode shareMode;
34604     int ossFormat;
34605     int ossChannels;
34606     int ossSampleRate;
34607     int ossFragment;
34608
34609     MA_ASSERT(pDevice != NULL);
34610     MA_ASSERT(pConfig != NULL);
34611     MA_ASSERT(deviceType != ma_device_type_duplex);
34612
34613     pDeviceID     = pDescriptor->pDeviceID;
34614     shareMode     = pDescriptor->shareMode;
34615     ossFormat     = ma_format_to_oss((pDescriptor->format != ma_format_unknown) ? pDescriptor->format : ma_format_s16); /* Use s16 by default because OSS doesn't like floating point. */
34616     ossChannels   = (int)(pDescriptor->channels   > 0) ? pDescriptor->channels   : MA_DEFAULT_CHANNELS;
34617     ossSampleRate = (int)(pDescriptor->sampleRate > 0) ? pDescriptor->sampleRate : MA_DEFAULT_SAMPLE_RATE;
34618
34619     result = ma_context_open_device__oss(pDevice->pContext, deviceType, pDeviceID, shareMode, &fd);
34620     if (result != MA_SUCCESS) {
34621         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.");
34622         return result;
34623     }
34624
34625     /*
34626     The OSS documantation is very clear about the order we should be initializing the device's properties:
34627       1) Format
34628       2) Channels
34629       3) Sample rate.
34630     */
34631
34632     /* Format. */
34633     ossResult = ioctl(fd, SNDCTL_DSP_SETFMT, &ossFormat);
34634     if (ossResult == -1) {
34635         close(fd);
34636         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set format.");
34637         return ma_result_from_errno(errno);
34638     }
34639
34640     /* Channels. */
34641     ossResult = ioctl(fd, SNDCTL_DSP_CHANNELS, &ossChannels);
34642     if (ossResult == -1) {
34643         close(fd);
34644         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set channel count.");
34645         return ma_result_from_errno(errno);
34646     }
34647
34648     /* Sample Rate. */
34649     ossResult = ioctl(fd, SNDCTL_DSP_SPEED, &ossSampleRate);
34650     if (ossResult == -1) {
34651         close(fd);
34652         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set sample rate.");
34653         return ma_result_from_errno(errno);
34654     }
34655
34656     /*
34657     Buffer.
34658
34659     The documentation says that the fragment settings should be set as soon as possible, but I'm not sure if
34660     it should be done before or after format/channels/rate.
34661
34662     OSS wants the fragment size in bytes and a power of 2. When setting, we specify the power, not the actual
34663     value.
34664     */
34665     {
34666         ma_uint32 periodSizeInFrames;
34667         ma_uint32 periodSizeInBytes;
34668         ma_uint32 ossFragmentSizePower;
34669
34670         periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, (ma_uint32)ossSampleRate, pConfig->performanceProfile);
34671
34672         periodSizeInBytes = ma_round_to_power_of_2(periodSizeInFrames * ma_get_bytes_per_frame(ma_format_from_oss(ossFormat), ossChannels));
34673         if (periodSizeInBytes < 16) {
34674             periodSizeInBytes = 16;
34675         }
34676
34677         ossFragmentSizePower = 4;
34678         periodSizeInBytes >>= 4;
34679         while (periodSizeInBytes >>= 1) {
34680             ossFragmentSizePower += 1;
34681         }
34682
34683         ossFragment = (int)((pConfig->periods << 16) | ossFragmentSizePower);
34684         ossResult = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &ossFragment);
34685         if (ossResult == -1) {
34686             close(fd);
34687             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to set fragment size and period count.");
34688             return ma_result_from_errno(errno);
34689         }
34690     }
34691
34692     /* Internal settings. */
34693     if (deviceType == ma_device_type_capture) {
34694         pDevice->oss.fdCapture  = fd;
34695     } else {
34696         pDevice->oss.fdPlayback = fd;
34697     }
34698
34699     pDescriptor->format             = ma_format_from_oss(ossFormat);
34700     pDescriptor->channels           = ossChannels;
34701     pDescriptor->sampleRate         = ossSampleRate;
34702     ma_channel_map_init_standard(ma_standard_channel_map_sound4, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels);
34703     pDescriptor->periodCount        = (ma_uint32)(ossFragment >> 16);
34704     pDescriptor->periodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDescriptor->format, pDescriptor->channels);
34705
34706     if (pDescriptor->format == ma_format_unknown) {
34707         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.");
34708         return MA_FORMAT_NOT_SUPPORTED;
34709     }
34710
34711     return MA_SUCCESS;
34712 }
34713
34714 static ma_result ma_device_init__oss(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
34715 {
34716     MA_ASSERT(pDevice  != NULL);
34717     MA_ASSERT(pConfig  != NULL);
34718
34719     MA_ZERO_OBJECT(&pDevice->oss);
34720
34721     if (pConfig->deviceType == ma_device_type_loopback) {
34722         return MA_DEVICE_TYPE_NOT_SUPPORTED;
34723     }
34724
34725     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
34726         ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
34727         if (result != MA_SUCCESS) {
34728             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.");
34729             return result;
34730         }
34731     }
34732
34733     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
34734         ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
34735         if (result != MA_SUCCESS) {
34736             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.");
34737             return result;
34738         }
34739     }
34740
34741     return MA_SUCCESS;
34742 }
34743
34744 /*
34745 Note on Starting and Stopping
34746 =============================
34747 In the past I was using SNDCTL_DSP_HALT to stop the device, however this results in issues when
34748 trying to resume the device again. If we use SNDCTL_DSP_HALT, the next write() or read() will
34749 fail. Instead what we need to do is just not write or read to and from the device when the
34750 device is not running.
34751
34752 As a result, both the start and stop functions for OSS are just empty stubs. The starting and
34753 stopping logic is handled by ma_device_write__oss() and ma_device_read__oss(). These will check
34754 the device state, and if the device is stopped they will simply not do any kind of processing.
34755
34756 The downside to this technique is that I've noticed a fairly lengthy delay in stopping the
34757 device, up to a second. This is on a virtual machine, and as such might just be due to the
34758 virtual drivers, but I'm not fully sure. I am not sure how to work around this problem so for
34759 the moment that's just how it's going to have to be.
34760
34761 When starting the device, OSS will automatically start it when write() or read() is called.
34762 */
34763 static ma_result ma_device_start__oss(ma_device* pDevice)
34764 {
34765     MA_ASSERT(pDevice != NULL);
34766
34767     /* The device is automatically started with reading and writing. */
34768     (void)pDevice;
34769
34770     return MA_SUCCESS;
34771 }
34772
34773 static ma_result ma_device_stop__oss(ma_device* pDevice)
34774 {
34775     MA_ASSERT(pDevice != NULL);
34776
34777     /* See note above on why this is empty. */
34778     (void)pDevice;
34779
34780     return MA_SUCCESS;
34781 }
34782
34783 static ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
34784 {
34785     int resultOSS;
34786     ma_uint32 deviceState;
34787
34788     if (pFramesWritten != NULL) {
34789         *pFramesWritten = 0;
34790     }
34791
34792     /* Don't do any processing if the device is stopped. */
34793     deviceState = ma_device_get_state(pDevice);
34794     if (deviceState != ma_device_state_started && deviceState != ma_device_state_starting) {
34795         return MA_SUCCESS;
34796     }
34797
34798     resultOSS = write(pDevice->oss.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
34799     if (resultOSS < 0) {
34800         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device.");
34801         return ma_result_from_errno(errno);
34802     }
34803
34804     if (pFramesWritten != NULL) {
34805         *pFramesWritten = (ma_uint32)resultOSS / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
34806     }
34807
34808     return MA_SUCCESS;
34809 }
34810
34811 static ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
34812 {
34813     int resultOSS;
34814     ma_uint32 deviceState;
34815
34816     if (pFramesRead != NULL) {
34817         *pFramesRead = 0;
34818     }
34819
34820     /* Don't do any processing if the device is stopped. */
34821     deviceState = ma_device_get_state(pDevice);
34822     if (deviceState != ma_device_state_started && deviceState != ma_device_state_starting) {
34823         return MA_SUCCESS;
34824     }
34825
34826     resultOSS = read(pDevice->oss.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
34827     if (resultOSS < 0) {
34828         ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client.");
34829         return ma_result_from_errno(errno);
34830     }
34831
34832     if (pFramesRead != NULL) {
34833         *pFramesRead = (ma_uint32)resultOSS / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
34834     }
34835
34836     return MA_SUCCESS;
34837 }
34838
34839 static ma_result ma_context_uninit__oss(ma_context* pContext)
34840 {
34841     MA_ASSERT(pContext != NULL);
34842     MA_ASSERT(pContext->backend == ma_backend_oss);
34843
34844     (void)pContext;
34845     return MA_SUCCESS;
34846 }
34847
34848 static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
34849 {
34850     int fd;
34851     int ossVersion;
34852     int result;
34853
34854     MA_ASSERT(pContext != NULL);
34855
34856     (void)pConfig;
34857
34858     /* Try opening a temporary device first so we can get version information. This is closed at the end. */
34859     fd = ma_open_temp_device__oss();
34860     if (fd == -1) {
34861         ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to open temporary device for retrieving system properties.");   /* Looks liks OSS isn't installed, or there are no available devices. */
34862         return MA_NO_BACKEND;
34863     }
34864
34865     /* Grab the OSS version. */
34866     ossVersion = 0;
34867     result = ioctl(fd, OSS_GETVERSION, &ossVersion);
34868     if (result == -1) {
34869         close(fd);
34870         ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve OSS version.");
34871         return MA_NO_BACKEND;
34872     }
34873
34874     /* The file handle to temp device is no longer needed. Close ASAP. */
34875     close(fd);
34876
34877     pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16);
34878     pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8);
34879
34880     pCallbacks->onContextInit             = ma_context_init__oss;
34881     pCallbacks->onContextUninit           = ma_context_uninit__oss;
34882     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__oss;
34883     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__oss;
34884     pCallbacks->onDeviceInit              = ma_device_init__oss;
34885     pCallbacks->onDeviceUninit            = ma_device_uninit__oss;
34886     pCallbacks->onDeviceStart             = ma_device_start__oss;
34887     pCallbacks->onDeviceStop              = ma_device_stop__oss;
34888     pCallbacks->onDeviceRead              = ma_device_read__oss;
34889     pCallbacks->onDeviceWrite             = ma_device_write__oss;
34890     pCallbacks->onDeviceDataLoop          = NULL;
34891
34892     return MA_SUCCESS;
34893 }
34894 #endif  /* OSS */
34895
34896
34897 /******************************************************************************
34898
34899 AAudio Backend
34900
34901 ******************************************************************************/
34902 #ifdef MA_HAS_AAUDIO
34903
34904 /*#include <AAudio/AAudio.h>*/
34905
34906 typedef int32_t                                         ma_aaudio_result_t;
34907 typedef int32_t                                         ma_aaudio_direction_t;
34908 typedef int32_t                                         ma_aaudio_sharing_mode_t;
34909 typedef int32_t                                         ma_aaudio_format_t;
34910 typedef int32_t                                         ma_aaudio_stream_state_t;
34911 typedef int32_t                                         ma_aaudio_performance_mode_t;
34912 typedef int32_t                                         ma_aaudio_usage_t;
34913 typedef int32_t                                         ma_aaudio_content_type_t;
34914 typedef int32_t                                         ma_aaudio_input_preset_t;
34915 typedef int32_t                                         ma_aaudio_data_callback_result_t;
34916 typedef struct ma_AAudioStreamBuilder_t*                ma_AAudioStreamBuilder;
34917 typedef struct ma_AAudioStream_t*                       ma_AAudioStream;
34918
34919 #define MA_AAUDIO_UNSPECIFIED                           0
34920
34921 /* Result codes. miniaudio only cares about the success code. */
34922 #define MA_AAUDIO_OK                                    0
34923
34924 /* Directions. */
34925 #define MA_AAUDIO_DIRECTION_OUTPUT                      0
34926 #define MA_AAUDIO_DIRECTION_INPUT                       1
34927
34928 /* Sharing modes. */
34929 #define MA_AAUDIO_SHARING_MODE_EXCLUSIVE                0
34930 #define MA_AAUDIO_SHARING_MODE_SHARED                   1
34931
34932 /* Formats. */
34933 #define MA_AAUDIO_FORMAT_PCM_I16                        1
34934 #define MA_AAUDIO_FORMAT_PCM_FLOAT                      2
34935
34936 /* Stream states. */
34937 #define MA_AAUDIO_STREAM_STATE_UNINITIALIZED            0
34938 #define MA_AAUDIO_STREAM_STATE_UNKNOWN                  1
34939 #define MA_AAUDIO_STREAM_STATE_OPEN                     2
34940 #define MA_AAUDIO_STREAM_STATE_STARTING                 3
34941 #define MA_AAUDIO_STREAM_STATE_STARTED                  4
34942 #define MA_AAUDIO_STREAM_STATE_PAUSING                  5
34943 #define MA_AAUDIO_STREAM_STATE_PAUSED                   6
34944 #define MA_AAUDIO_STREAM_STATE_FLUSHING                 7
34945 #define MA_AAUDIO_STREAM_STATE_FLUSHED                  8
34946 #define MA_AAUDIO_STREAM_STATE_STOPPING                 9
34947 #define MA_AAUDIO_STREAM_STATE_STOPPED                  10
34948 #define MA_AAUDIO_STREAM_STATE_CLOSING                  11
34949 #define MA_AAUDIO_STREAM_STATE_CLOSED                   12
34950 #define MA_AAUDIO_STREAM_STATE_DISCONNECTED             13
34951
34952 /* Performance modes. */
34953 #define MA_AAUDIO_PERFORMANCE_MODE_NONE                 10
34954 #define MA_AAUDIO_PERFORMANCE_MODE_POWER_SAVING         11
34955 #define MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY          12
34956
34957 /* Usage types. */
34958 #define MA_AAUDIO_USAGE_MEDIA                           1
34959 #define MA_AAUDIO_USAGE_VOICE_COMMUNICATION             2
34960 #define MA_AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING  3
34961 #define MA_AAUDIO_USAGE_ALARM                           4
34962 #define MA_AAUDIO_USAGE_NOTIFICATION                    5
34963 #define MA_AAUDIO_USAGE_NOTIFICATION_RINGTONE           6
34964 #define MA_AAUDIO_USAGE_NOTIFICATION_EVENT              10
34965 #define MA_AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY        11
34966 #define MA_AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE  12
34967 #define MA_AAUDIO_USAGE_ASSISTANCE_SONIFICATION         13
34968 #define MA_AAUDIO_USAGE_GAME                            14
34969 #define MA_AAUDIO_USAGE_ASSISTANT                       16
34970 #define MA_AAUDIO_SYSTEM_USAGE_EMERGENCY                1000
34971 #define MA_AAUDIO_SYSTEM_USAGE_SAFETY                   1001
34972 #define MA_AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS           1002
34973 #define MA_AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT             1003
34974
34975 /* Content types. */
34976 #define MA_AAUDIO_CONTENT_TYPE_SPEECH                   1
34977 #define MA_AAUDIO_CONTENT_TYPE_MUSIC                    2
34978 #define MA_AAUDIO_CONTENT_TYPE_MOVIE                    3
34979 #define MA_AAUDIO_CONTENT_TYPE_SONIFICATION             4
34980
34981 /* Input presets. */
34982 #define MA_AAUDIO_INPUT_PRESET_GENERIC                  1
34983 #define MA_AAUDIO_INPUT_PRESET_CAMCORDER                5
34984 #define MA_AAUDIO_INPUT_PRESET_VOICE_RECOGNITION        6
34985 #define MA_AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION      7
34986 #define MA_AAUDIO_INPUT_PRESET_UNPROCESSED              9
34987 #define MA_AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE        10
34988
34989 /* Callback results. */
34990 #define MA_AAUDIO_CALLBACK_RESULT_CONTINUE              0
34991 #define MA_AAUDIO_CALLBACK_RESULT_STOP                  1
34992
34993
34994 typedef ma_aaudio_data_callback_result_t (* ma_AAudioStream_dataCallback) (ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t numFrames);
34995 typedef void                             (* ma_AAudioStream_errorCallback)(ma_AAudioStream *pStream, void *pUserData, ma_aaudio_result_t error);
34996
34997 typedef ma_aaudio_result_t       (* MA_PFN_AAudio_createStreamBuilder)                   (ma_AAudioStreamBuilder** ppBuilder);
34998 typedef ma_aaudio_result_t       (* MA_PFN_AAudioStreamBuilder_delete)                   (ma_AAudioStreamBuilder* pBuilder);
34999 typedef void                     (* MA_PFN_AAudioStreamBuilder_setDeviceId)              (ma_AAudioStreamBuilder* pBuilder, int32_t deviceId);
35000 typedef void                     (* MA_PFN_AAudioStreamBuilder_setDirection)             (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_direction_t direction);
35001 typedef void                     (* MA_PFN_AAudioStreamBuilder_setSharingMode)           (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_sharing_mode_t sharingMode);
35002 typedef void                     (* MA_PFN_AAudioStreamBuilder_setFormat)                (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_format_t format);
35003 typedef void                     (* MA_PFN_AAudioStreamBuilder_setChannelCount)          (ma_AAudioStreamBuilder* pBuilder, int32_t channelCount);
35004 typedef void                     (* MA_PFN_AAudioStreamBuilder_setSampleRate)            (ma_AAudioStreamBuilder* pBuilder, int32_t sampleRate);
35005 typedef void                     (* MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)(ma_AAudioStreamBuilder* pBuilder, int32_t numFrames);
35006 typedef void                     (* MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback) (ma_AAudioStreamBuilder* pBuilder, int32_t numFrames);
35007 typedef void                     (* MA_PFN_AAudioStreamBuilder_setDataCallback)          (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream_dataCallback callback, void* pUserData);
35008 typedef void                     (* MA_PFN_AAudioStreamBuilder_setErrorCallback)         (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream_errorCallback callback, void* pUserData);
35009 typedef void                     (* MA_PFN_AAudioStreamBuilder_setPerformanceMode)       (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_performance_mode_t mode);
35010 typedef void                     (* MA_PFN_AAudioStreamBuilder_setUsage)                 (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_usage_t contentType);
35011 typedef void                     (* MA_PFN_AAudioStreamBuilder_setContentType)           (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_content_type_t contentType);
35012 typedef void                     (* MA_PFN_AAudioStreamBuilder_setInputPreset)           (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_input_preset_t inputPreset);
35013 typedef ma_aaudio_result_t       (* MA_PFN_AAudioStreamBuilder_openStream)               (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream** ppStream);
35014 typedef ma_aaudio_result_t       (* MA_PFN_AAudioStream_close)                           (ma_AAudioStream* pStream);
35015 typedef ma_aaudio_stream_state_t (* MA_PFN_AAudioStream_getState)                        (ma_AAudioStream* pStream);
35016 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);
35017 typedef ma_aaudio_format_t       (* MA_PFN_AAudioStream_getFormat)                       (ma_AAudioStream* pStream);
35018 typedef int32_t                  (* MA_PFN_AAudioStream_getChannelCount)                 (ma_AAudioStream* pStream);
35019 typedef int32_t                  (* MA_PFN_AAudioStream_getSampleRate)                   (ma_AAudioStream* pStream);
35020 typedef int32_t                  (* MA_PFN_AAudioStream_getBufferCapacityInFrames)       (ma_AAudioStream* pStream);
35021 typedef int32_t                  (* MA_PFN_AAudioStream_getFramesPerDataCallback)        (ma_AAudioStream* pStream);
35022 typedef int32_t                  (* MA_PFN_AAudioStream_getFramesPerBurst)               (ma_AAudioStream* pStream);
35023 typedef ma_aaudio_result_t       (* MA_PFN_AAudioStream_requestStart)                    (ma_AAudioStream* pStream);
35024 typedef ma_aaudio_result_t       (* MA_PFN_AAudioStream_requestStop)                     (ma_AAudioStream* pStream);
35025
35026 static ma_result ma_result_from_aaudio(ma_aaudio_result_t resultAA)
35027 {
35028     switch (resultAA)
35029     {
35030         case MA_AAUDIO_OK: return MA_SUCCESS;
35031         default: break;
35032     }
35033
35034     return MA_ERROR;
35035 }
35036
35037 static ma_aaudio_usage_t ma_to_usage__aaudio(ma_aaudio_usage usage)
35038 {
35039     switch (usage) {
35040         case ma_aaudio_usage_announcement:                   return MA_AAUDIO_USAGE_MEDIA;
35041         case ma_aaudio_usage_emergency:                      return MA_AAUDIO_USAGE_VOICE_COMMUNICATION;
35042         case ma_aaudio_usage_safety:                         return MA_AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
35043         case ma_aaudio_usage_vehicle_status:                 return MA_AAUDIO_USAGE_ALARM;
35044         case ma_aaudio_usage_alarm:                          return MA_AAUDIO_USAGE_NOTIFICATION;
35045         case ma_aaudio_usage_assistance_accessibility:       return MA_AAUDIO_USAGE_NOTIFICATION_RINGTONE;
35046         case ma_aaudio_usage_assistance_navigation_guidance: return MA_AAUDIO_USAGE_NOTIFICATION_EVENT;
35047         case ma_aaudio_usage_assistance_sonification:        return MA_AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
35048         case ma_aaudio_usage_assitant:                       return MA_AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
35049         case ma_aaudio_usage_game:                           return MA_AAUDIO_USAGE_ASSISTANCE_SONIFICATION;
35050         case ma_aaudio_usage_media:                          return MA_AAUDIO_USAGE_GAME;
35051         case ma_aaudio_usage_notification:                   return MA_AAUDIO_USAGE_ASSISTANT;
35052         case ma_aaudio_usage_notification_event:             return MA_AAUDIO_SYSTEM_USAGE_EMERGENCY;
35053         case ma_aaudio_usage_notification_ringtone:          return MA_AAUDIO_SYSTEM_USAGE_SAFETY;
35054         case ma_aaudio_usage_voice_communication:            return MA_AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS;
35055         case ma_aaudio_usage_voice_communication_signalling: return MA_AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT;
35056         default: break;
35057     }
35058
35059     return MA_AAUDIO_USAGE_MEDIA;
35060 }
35061
35062 static ma_aaudio_content_type_t ma_to_content_type__aaudio(ma_aaudio_content_type contentType)
35063 {
35064     switch (contentType) {
35065         case ma_aaudio_content_type_movie:        return MA_AAUDIO_CONTENT_TYPE_MOVIE;
35066         case ma_aaudio_content_type_music:        return MA_AAUDIO_CONTENT_TYPE_MUSIC;
35067         case ma_aaudio_content_type_sonification: return MA_AAUDIO_CONTENT_TYPE_SONIFICATION;
35068         case ma_aaudio_content_type_speech:       return MA_AAUDIO_CONTENT_TYPE_SPEECH;
35069         default: break;
35070     }
35071
35072     return MA_AAUDIO_CONTENT_TYPE_SPEECH;
35073 }
35074
35075 static ma_aaudio_input_preset_t ma_to_input_preset__aaudio(ma_aaudio_input_preset inputPreset)
35076 {
35077     switch (inputPreset) {
35078         case ma_aaudio_input_preset_generic:             return MA_AAUDIO_INPUT_PRESET_GENERIC;
35079         case ma_aaudio_input_preset_camcorder:           return MA_AAUDIO_INPUT_PRESET_CAMCORDER;
35080         case ma_aaudio_input_preset_unprocessed:         return MA_AAUDIO_INPUT_PRESET_UNPROCESSED;
35081         case ma_aaudio_input_preset_voice_recognition:   return MA_AAUDIO_INPUT_PRESET_VOICE_RECOGNITION;
35082         case ma_aaudio_input_preset_voice_communication: return MA_AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION;
35083         case ma_aaudio_input_preset_voice_performance:   return MA_AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE;
35084         default: break;
35085     }
35086
35087     return MA_AAUDIO_INPUT_PRESET_GENERIC;
35088 }
35089
35090 static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUserData, ma_aaudio_result_t error)
35091 {
35092     ma_device* pDevice = (ma_device*)pUserData;
35093     MA_ASSERT(pDevice != NULL);
35094
35095     (void)error;
35096
35097     ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream));
35098
35099     /*
35100     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
35101     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.
35102     */
35103     if (((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream) == MA_AAUDIO_STREAM_STATE_DISCONNECTED) {
35104         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[AAudio] Device Disconnected.\n");
35105     }
35106 }
35107
35108 static ma_aaudio_data_callback_result_t ma_stream_data_callback_capture__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount)
35109 {
35110     ma_device* pDevice = (ma_device*)pUserData;
35111     MA_ASSERT(pDevice != NULL);
35112
35113     ma_device_handle_backend_data_callback(pDevice, NULL, pAudioData, frameCount);
35114
35115     (void)pStream;
35116     return MA_AAUDIO_CALLBACK_RESULT_CONTINUE;
35117 }
35118
35119 static ma_aaudio_data_callback_result_t ma_stream_data_callback_playback__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount)
35120 {
35121     ma_device* pDevice = (ma_device*)pUserData;
35122     MA_ASSERT(pDevice != NULL);
35123
35124     ma_device_handle_backend_data_callback(pDevice, pAudioData, NULL, frameCount);
35125
35126     (void)pStream;
35127     return MA_AAUDIO_CALLBACK_RESULT_CONTINUE;
35128 }
35129
35130 static ma_result ma_create_and_configure_AAudioStreamBuilder__aaudio(ma_context* pContext, const ma_device_id* pDeviceID, ma_device_type deviceType, ma_share_mode shareMode, const ma_device_descriptor* pDescriptor, const ma_device_config* pConfig, ma_device* pDevice, ma_AAudioStreamBuilder** ppBuilder)
35131 {
35132     ma_AAudioStreamBuilder* pBuilder;
35133     ma_aaudio_result_t resultAA;
35134     ma_uint32 bufferCapacityInFrames;
35135
35136     /* Safety. */
35137     *ppBuilder = NULL;
35138
35139     resultAA = ((MA_PFN_AAudio_createStreamBuilder)pContext->aaudio.AAudio_createStreamBuilder)(&pBuilder);
35140     if (resultAA != MA_AAUDIO_OK) {
35141         return ma_result_from_aaudio(resultAA);
35142     }
35143
35144     if (pDeviceID != NULL) {
35145         ((MA_PFN_AAudioStreamBuilder_setDeviceId)pContext->aaudio.AAudioStreamBuilder_setDeviceId)(pBuilder, pDeviceID->aaudio);
35146     }
35147
35148     ((MA_PFN_AAudioStreamBuilder_setDirection)pContext->aaudio.AAudioStreamBuilder_setDirection)(pBuilder, (deviceType == ma_device_type_playback) ? MA_AAUDIO_DIRECTION_OUTPUT : MA_AAUDIO_DIRECTION_INPUT);
35149     ((MA_PFN_AAudioStreamBuilder_setSharingMode)pContext->aaudio.AAudioStreamBuilder_setSharingMode)(pBuilder, (shareMode == ma_share_mode_shared) ? MA_AAUDIO_SHARING_MODE_SHARED : MA_AAUDIO_SHARING_MODE_EXCLUSIVE);
35150
35151
35152     /* If we have a device descriptor make sure we configure the stream builder to take our requested parameters. */
35153     if (pDescriptor != NULL) {
35154         MA_ASSERT(pConfig != NULL); /* We must have a device config if we also have a descriptor. The config is required for AAudio specific configuration options. */
35155
35156         if (pDescriptor->sampleRate != 0) {
35157             ((MA_PFN_AAudioStreamBuilder_setSampleRate)pContext->aaudio.AAudioStreamBuilder_setSampleRate)(pBuilder, pDescriptor->sampleRate);
35158         }
35159
35160         if (deviceType == ma_device_type_capture) {
35161             if (pDescriptor->channels != 0) {
35162                 ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pDescriptor->channels);
35163             }
35164             if (pDescriptor->format != ma_format_unknown) {
35165                 ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pDescriptor->format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT);
35166             }
35167         } else {
35168             if (pDescriptor->channels != 0) {
35169                 ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pDescriptor->channels);
35170             }
35171             if (pDescriptor->format != ma_format_unknown) {
35172                 ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pDescriptor->format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT);
35173             }
35174         }
35175
35176         /*
35177         AAudio is annoying when it comes to it's buffer calculation stuff because it doesn't let you
35178         retrieve the actual sample rate until after you've opened the stream. But you need to configure
35179         the buffer capacity before you open the stream... :/
35180
35181         To solve, we're just going to assume MA_DEFAULT_SAMPLE_RATE (48000) and move on.
35182         */
35183         bufferCapacityInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, pDescriptor->sampleRate, pConfig->performanceProfile) * pDescriptor->periodCount;
35184
35185         ((MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames)(pBuilder, bufferCapacityInFrames);
35186         ((MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback)pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback)(pBuilder, bufferCapacityInFrames / pDescriptor->periodCount);
35187
35188         if (deviceType == ma_device_type_capture) {
35189             if (pConfig->aaudio.inputPreset != ma_aaudio_input_preset_default && pContext->aaudio.AAudioStreamBuilder_setInputPreset != NULL) {
35190                 ((MA_PFN_AAudioStreamBuilder_setInputPreset)pContext->aaudio.AAudioStreamBuilder_setInputPreset)(pBuilder, ma_to_input_preset__aaudio(pConfig->aaudio.inputPreset));
35191             }
35192
35193             ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_capture__aaudio, (void*)pDevice);
35194         } else {
35195             if (pConfig->aaudio.usage != ma_aaudio_usage_default && pContext->aaudio.AAudioStreamBuilder_setUsage != NULL) {
35196                 ((MA_PFN_AAudioStreamBuilder_setUsage)pContext->aaudio.AAudioStreamBuilder_setUsage)(pBuilder, ma_to_usage__aaudio(pConfig->aaudio.usage));
35197             }
35198
35199             if (pConfig->aaudio.contentType != ma_aaudio_content_type_default && pContext->aaudio.AAudioStreamBuilder_setContentType != NULL) {
35200                 ((MA_PFN_AAudioStreamBuilder_setContentType)pContext->aaudio.AAudioStreamBuilder_setContentType)(pBuilder, ma_to_content_type__aaudio(pConfig->aaudio.contentType));
35201             }
35202
35203             ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_playback__aaudio, (void*)pDevice);
35204         }
35205
35206         /* 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. */
35207         ((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);
35208
35209         /* We need to set an error callback to detect device changes. */
35210         if (pDevice != NULL) {  /* <-- pDevice should never be null if pDescriptor is not null, which is always the case if we hit this branch. Check anyway for safety. */
35211             ((MA_PFN_AAudioStreamBuilder_setErrorCallback)pContext->aaudio.AAudioStreamBuilder_setErrorCallback)(pBuilder, ma_stream_error_callback__aaudio, (void*)pDevice);
35212         }
35213     }
35214
35215     *ppBuilder = pBuilder;
35216
35217     return MA_SUCCESS;
35218 }
35219
35220 static ma_result ma_open_stream_and_close_builder__aaudio(ma_context* pContext, ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream** ppStream)
35221 {
35222     ma_result result;
35223
35224     result = ma_result_from_aaudio(((MA_PFN_AAudioStreamBuilder_openStream)pContext->aaudio.AAudioStreamBuilder_openStream)(pBuilder, ppStream));
35225     ((MA_PFN_AAudioStreamBuilder_delete)pContext->aaudio.AAudioStreamBuilder_delete)(pBuilder);
35226
35227     return result;
35228 }
35229
35230 static ma_result ma_open_stream_basic__aaudio(ma_context* pContext, const ma_device_id* pDeviceID, ma_device_type deviceType, ma_share_mode shareMode, ma_AAudioStream** ppStream)
35231 {
35232     ma_result result;
35233     ma_AAudioStreamBuilder* pBuilder;
35234
35235     *ppStream = NULL;
35236
35237     result = ma_create_and_configure_AAudioStreamBuilder__aaudio(pContext, pDeviceID, deviceType, shareMode, NULL, NULL, NULL, &pBuilder);
35238     if (result != MA_SUCCESS) {
35239         return result;
35240     }
35241
35242     return ma_open_stream_and_close_builder__aaudio(pContext, pBuilder, ppStream);
35243 }
35244
35245 static ma_result ma_open_stream__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_type deviceType, const ma_device_descriptor* pDescriptor, ma_AAudioStream** ppStream)
35246 {
35247     ma_result result;
35248     ma_AAudioStreamBuilder* pBuilder;
35249
35250     MA_ASSERT(pDevice != NULL);
35251     MA_ASSERT(pDescriptor != NULL);
35252     MA_ASSERT(deviceType != ma_device_type_duplex);   /* This function should not be called for a full-duplex device type. */
35253
35254     *ppStream = NULL;
35255
35256     result = ma_create_and_configure_AAudioStreamBuilder__aaudio(pDevice->pContext, pDescriptor->pDeviceID, deviceType, pDescriptor->shareMode, pDescriptor, pConfig, pDevice, &pBuilder);
35257     if (result != MA_SUCCESS) {
35258         return result;
35259     }
35260
35261     return ma_open_stream_and_close_builder__aaudio(pDevice->pContext, pBuilder, ppStream);
35262 }
35263
35264 static ma_result ma_close_stream__aaudio(ma_context* pContext, ma_AAudioStream* pStream)
35265 {
35266     return ma_result_from_aaudio(((MA_PFN_AAudioStream_close)pContext->aaudio.AAudioStream_close)(pStream));
35267 }
35268
35269 static ma_bool32 ma_has_default_device__aaudio(ma_context* pContext, ma_device_type deviceType)
35270 {
35271     /* The only way to know this is to try creating a stream. */
35272     ma_AAudioStream* pStream;
35273     ma_result result = ma_open_stream_basic__aaudio(pContext, NULL, deviceType, ma_share_mode_shared, &pStream);
35274     if (result != MA_SUCCESS) {
35275         return MA_FALSE;
35276     }
35277
35278     ma_close_stream__aaudio(pContext, pStream);
35279     return MA_TRUE;
35280 }
35281
35282 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)
35283 {
35284     ma_aaudio_stream_state_t actualNewState;
35285     ma_aaudio_result_t resultAA = ((MA_PFN_AAudioStream_waitForStateChange)pContext->aaudio.AAudioStream_waitForStateChange)(pStream, oldState, &actualNewState, 5000000000); /* 5 second timeout. */
35286     if (resultAA != MA_AAUDIO_OK) {
35287         return ma_result_from_aaudio(resultAA);
35288     }
35289
35290     if (newState != actualNewState) {
35291         return MA_ERROR;   /* Failed to transition into the expected state. */
35292     }
35293
35294     return MA_SUCCESS;
35295 }
35296
35297
35298 static ma_result ma_context_enumerate_devices__aaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
35299 {
35300     ma_bool32 cbResult = MA_TRUE;
35301
35302     MA_ASSERT(pContext != NULL);
35303     MA_ASSERT(callback != NULL);
35304
35305     /* 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. */
35306
35307     /* Playback. */
35308     if (cbResult) {
35309         ma_device_info deviceInfo;
35310         MA_ZERO_OBJECT(&deviceInfo);
35311         deviceInfo.id.aaudio = MA_AAUDIO_UNSPECIFIED;
35312         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
35313
35314         if (ma_has_default_device__aaudio(pContext, ma_device_type_playback)) {
35315             cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
35316         }
35317     }
35318
35319     /* Capture. */
35320     if (cbResult) {
35321         ma_device_info deviceInfo;
35322         MA_ZERO_OBJECT(&deviceInfo);
35323         deviceInfo.id.aaudio = MA_AAUDIO_UNSPECIFIED;
35324         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
35325
35326         if (ma_has_default_device__aaudio(pContext, ma_device_type_capture)) {
35327             cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
35328         }
35329     }
35330
35331     return MA_SUCCESS;
35332 }
35333
35334 static void ma_context_add_native_data_format_from_AAudioStream_ex__aaudio(ma_context* pContext, ma_AAudioStream* pStream, ma_format format, ma_uint32 flags, ma_device_info* pDeviceInfo)
35335 {
35336     MA_ASSERT(pContext    != NULL);
35337     MA_ASSERT(pStream     != NULL);
35338     MA_ASSERT(pDeviceInfo != NULL);
35339
35340     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = format;
35341     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = ((MA_PFN_AAudioStream_getChannelCount)pContext->aaudio.AAudioStream_getChannelCount)(pStream);
35342     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = ((MA_PFN_AAudioStream_getSampleRate)pContext->aaudio.AAudioStream_getSampleRate)(pStream);
35343     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = flags;
35344     pDeviceInfo->nativeDataFormatCount += 1;
35345 }
35346
35347 static void ma_context_add_native_data_format_from_AAudioStream__aaudio(ma_context* pContext, ma_AAudioStream* pStream, ma_uint32 flags, ma_device_info* pDeviceInfo)
35348 {
35349     /* AAudio supports s16 and f32. */
35350     ma_context_add_native_data_format_from_AAudioStream_ex__aaudio(pContext, pStream, ma_format_f32, flags, pDeviceInfo);
35351     ma_context_add_native_data_format_from_AAudioStream_ex__aaudio(pContext, pStream, ma_format_s16, flags, pDeviceInfo);
35352 }
35353
35354 static ma_result ma_context_get_device_info__aaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
35355 {
35356     ma_AAudioStream* pStream;
35357     ma_result result;
35358
35359     MA_ASSERT(pContext != NULL);
35360
35361     /* ID */
35362     if (pDeviceID != NULL) {
35363         pDeviceInfo->id.aaudio = pDeviceID->aaudio;
35364     } else {
35365         pDeviceInfo->id.aaudio = MA_AAUDIO_UNSPECIFIED;
35366     }
35367
35368     /* Name */
35369     if (deviceType == ma_device_type_playback) {
35370         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
35371     } else {
35372         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
35373     }
35374
35375
35376     pDeviceInfo->nativeDataFormatCount = 0;
35377
35378     /* We'll need to open the device to get accurate sample rate and channel count information. */
35379     result = ma_open_stream_basic__aaudio(pContext, pDeviceID, deviceType, ma_share_mode_shared, &pStream);
35380     if (result != MA_SUCCESS) {
35381         return result;
35382     }
35383
35384     ma_context_add_native_data_format_from_AAudioStream__aaudio(pContext, pStream, 0, pDeviceInfo);
35385
35386     ma_close_stream__aaudio(pContext, pStream);
35387     pStream = NULL;
35388
35389     return MA_SUCCESS;
35390 }
35391
35392
35393 static ma_result ma_device_uninit__aaudio(ma_device* pDevice)
35394 {
35395     MA_ASSERT(pDevice != NULL);
35396
35397     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
35398         ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
35399         pDevice->aaudio.pStreamCapture = NULL;
35400     }
35401
35402     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
35403         ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
35404         pDevice->aaudio.pStreamPlayback = NULL;
35405     }
35406
35407     return MA_SUCCESS;
35408 }
35409
35410 static ma_result ma_device_init_by_type__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_type deviceType, ma_device_descriptor* pDescriptor, ma_AAudioStream** ppStream)
35411 {
35412     ma_result result;
35413     int32_t bufferCapacityInFrames;
35414     int32_t framesPerDataCallback;
35415     ma_AAudioStream* pStream;
35416
35417     MA_ASSERT(pDevice     != NULL);
35418     MA_ASSERT(pConfig     != NULL);
35419     MA_ASSERT(pDescriptor != NULL);
35420
35421     *ppStream = NULL;   /* Safety. */
35422
35423     /* First step is to open the stream. From there we'll be able to extract the internal configuration. */
35424     result = ma_open_stream__aaudio(pDevice, pConfig, deviceType, pDescriptor, &pStream);
35425     if (result != MA_SUCCESS) {
35426         return result;  /* Failed to open the AAudio stream. */
35427     }
35428
35429     /* Now extract the internal configuration. */
35430     pDescriptor->format     = (((MA_PFN_AAudioStream_getFormat)pDevice->pContext->aaudio.AAudioStream_getFormat)(pStream) == MA_AAUDIO_FORMAT_PCM_I16) ? ma_format_s16 : ma_format_f32;
35431     pDescriptor->channels   = ((MA_PFN_AAudioStream_getChannelCount)pDevice->pContext->aaudio.AAudioStream_getChannelCount)(pStream);
35432     pDescriptor->sampleRate = ((MA_PFN_AAudioStream_getSampleRate)pDevice->pContext->aaudio.AAudioStream_getSampleRate)(pStream);
35433
35434     /* For the channel map we need to be sure we don't overflow any buffers. */
35435     if (pDescriptor->channels <= MA_MAX_CHANNELS) {
35436         ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels); /* <-- Cannot find info on channel order, so assuming a default. */
35437     } else {
35438         ma_channel_map_init_blank(pDescriptor->channelMap, MA_MAX_CHANNELS); /* Too many channels. Use a blank channel map. */
35439     }
35440
35441     bufferCapacityInFrames = ((MA_PFN_AAudioStream_getBufferCapacityInFrames)pDevice->pContext->aaudio.AAudioStream_getBufferCapacityInFrames)(pStream);
35442     framesPerDataCallback = ((MA_PFN_AAudioStream_getFramesPerDataCallback)pDevice->pContext->aaudio.AAudioStream_getFramesPerDataCallback)(pStream);
35443
35444     if (framesPerDataCallback > 0) {
35445         pDescriptor->periodSizeInFrames = framesPerDataCallback;
35446         pDescriptor->periodCount        = bufferCapacityInFrames / framesPerDataCallback;
35447     } else {
35448         pDescriptor->periodSizeInFrames = bufferCapacityInFrames;
35449         pDescriptor->periodCount        = 1;
35450     }
35451
35452     *ppStream = pStream;
35453
35454     return MA_SUCCESS;
35455 }
35456
35457 static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
35458 {
35459     ma_result result;
35460
35461     MA_ASSERT(pDevice != NULL);
35462
35463     if (pConfig->deviceType == ma_device_type_loopback) {
35464         return MA_DEVICE_TYPE_NOT_SUPPORTED;
35465     }
35466
35467     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
35468         result = ma_device_init_by_type__aaudio(pDevice, pConfig, ma_device_type_capture, pDescriptorCapture, (ma_AAudioStream**)&pDevice->aaudio.pStreamCapture);
35469         if (result != MA_SUCCESS) {
35470             return result;
35471         }
35472     }
35473
35474     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
35475         result = ma_device_init_by_type__aaudio(pDevice, pConfig, ma_device_type_playback, pDescriptorPlayback, (ma_AAudioStream**)&pDevice->aaudio.pStreamPlayback);
35476         if (result != MA_SUCCESS) {
35477             return result;
35478         }
35479     }
35480
35481     return MA_SUCCESS;
35482 }
35483
35484 static ma_result ma_device_start_stream__aaudio(ma_device* pDevice, ma_AAudioStream* pStream)
35485 {
35486     ma_aaudio_result_t resultAA;
35487     ma_aaudio_stream_state_t currentState;
35488
35489     MA_ASSERT(pDevice != NULL);
35490
35491     resultAA = ((MA_PFN_AAudioStream_requestStart)pDevice->pContext->aaudio.AAudioStream_requestStart)(pStream);
35492     if (resultAA != MA_AAUDIO_OK) {
35493         return ma_result_from_aaudio(resultAA);
35494     }
35495
35496     /* Do we actually need to wait for the device to transition into it's started state? */
35497
35498     /* 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. */
35499     currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream);
35500     if (currentState != MA_AAUDIO_STREAM_STATE_STARTED) {
35501         ma_result result;
35502
35503         if (currentState != MA_AAUDIO_STREAM_STATE_STARTING) {
35504             return MA_ERROR;   /* Expecting the stream to be a starting or started state. */
35505         }
35506
35507         result = ma_wait_for_simple_state_transition__aaudio(pDevice->pContext, pStream, currentState, MA_AAUDIO_STREAM_STATE_STARTED);
35508         if (result != MA_SUCCESS) {
35509             return result;
35510         }
35511     }
35512
35513     return MA_SUCCESS;
35514 }
35515
35516 static ma_result ma_device_stop_stream__aaudio(ma_device* pDevice, ma_AAudioStream* pStream)
35517 {
35518     ma_aaudio_result_t resultAA;
35519     ma_aaudio_stream_state_t currentState;
35520
35521     MA_ASSERT(pDevice != NULL);
35522
35523     /*
35524     From the AAudio documentation:
35525
35526         The stream will stop after all of the data currently buffered has been played.
35527
35528     This maps with miniaudio's requirement that device's be drained which means we don't need to implement any draining logic.
35529     */
35530
35531     resultAA = ((MA_PFN_AAudioStream_requestStop)pDevice->pContext->aaudio.AAudioStream_requestStop)(pStream);
35532     if (resultAA != MA_AAUDIO_OK) {
35533         return ma_result_from_aaudio(resultAA);
35534     }
35535
35536     /* 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. */
35537     currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream);
35538     if (currentState != MA_AAUDIO_STREAM_STATE_STOPPED) {
35539         ma_result result;
35540
35541         if (currentState != MA_AAUDIO_STREAM_STATE_STOPPING) {
35542             return MA_ERROR;   /* Expecting the stream to be a stopping or stopped state. */
35543         }
35544
35545         result = ma_wait_for_simple_state_transition__aaudio(pDevice->pContext, pStream, currentState, MA_AAUDIO_STREAM_STATE_STOPPED);
35546         if (result != MA_SUCCESS) {
35547             return result;
35548         }
35549     }
35550
35551     return MA_SUCCESS;
35552 }
35553
35554 static ma_result ma_device_start__aaudio(ma_device* pDevice)
35555 {
35556     MA_ASSERT(pDevice != NULL);
35557
35558     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
35559         ma_result result = ma_device_start_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
35560         if (result != MA_SUCCESS) {
35561             return result;
35562         }
35563     }
35564
35565     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
35566         ma_result result = ma_device_start_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
35567         if (result != MA_SUCCESS) {
35568             if (pDevice->type == ma_device_type_duplex) {
35569                 ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
35570             }
35571             return result;
35572         }
35573     }
35574
35575     return MA_SUCCESS;
35576 }
35577
35578 static ma_result ma_device_stop__aaudio(ma_device* pDevice)
35579 {
35580     MA_ASSERT(pDevice != NULL);
35581
35582     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
35583         ma_result result = ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
35584         if (result != MA_SUCCESS) {
35585             return result;
35586         }
35587     }
35588
35589     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
35590         ma_result result = ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
35591         if (result != MA_SUCCESS) {
35592             return result;
35593         }
35594     }
35595
35596     ma_device__on_notification_stopped(pDevice);
35597
35598     return MA_SUCCESS;
35599 }
35600
35601 static ma_result ma_device_get_info__aaudio(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo)
35602 {
35603     ma_AAudioStream* pStream = NULL;
35604
35605     MA_ASSERT(pDevice     != NULL);
35606     MA_ASSERT(type        != ma_device_type_duplex);
35607     MA_ASSERT(pDeviceInfo != NULL);
35608
35609     if (type == ma_device_type_playback) {
35610         pStream = (ma_AAudioStream*)pDevice->aaudio.pStreamCapture;
35611         pDeviceInfo->id.aaudio = pDevice->capture.id.aaudio;
35612         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);     /* Only supporting default devices. */
35613     }
35614     if (type == ma_device_type_capture) {
35615         pStream = (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback;
35616         pDeviceInfo->id.aaudio = pDevice->playback.id.aaudio;
35617         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);    /* Only supporting default devices. */
35618     }
35619
35620     /* Safety. Should never happen. */
35621     if (pStream == NULL) {
35622         return MA_INVALID_OPERATION;
35623     }
35624
35625     pDeviceInfo->nativeDataFormatCount = 0;
35626     ma_context_add_native_data_format_from_AAudioStream__aaudio(pDevice->pContext, pStream, 0, pDeviceInfo);
35627
35628     return MA_SUCCESS;
35629 }
35630
35631
35632 static ma_result ma_context_uninit__aaudio(ma_context* pContext)
35633 {
35634     MA_ASSERT(pContext != NULL);
35635     MA_ASSERT(pContext->backend == ma_backend_aaudio);
35636
35637     ma_dlclose(pContext, pContext->aaudio.hAAudio);
35638     pContext->aaudio.hAAudio = NULL;
35639
35640     return MA_SUCCESS;
35641 }
35642
35643 static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
35644 {
35645     size_t i;
35646     const char* libNames[] = {
35647         "libaaudio.so"
35648     };
35649
35650     for (i = 0; i < ma_countof(libNames); ++i) {
35651         pContext->aaudio.hAAudio = ma_dlopen(pContext, libNames[i]);
35652         if (pContext->aaudio.hAAudio != NULL) {
35653             break;
35654         }
35655     }
35656
35657     if (pContext->aaudio.hAAudio == NULL) {
35658         return MA_FAILED_TO_INIT_BACKEND;
35659     }
35660
35661     pContext->aaudio.AAudio_createStreamBuilder                    = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudio_createStreamBuilder");
35662     pContext->aaudio.AAudioStreamBuilder_delete                    = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_delete");
35663     pContext->aaudio.AAudioStreamBuilder_setDeviceId               = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDeviceId");
35664     pContext->aaudio.AAudioStreamBuilder_setDirection              = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDirection");
35665     pContext->aaudio.AAudioStreamBuilder_setSharingMode            = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSharingMode");
35666     pContext->aaudio.AAudioStreamBuilder_setFormat                 = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFormat");
35667     pContext->aaudio.AAudioStreamBuilder_setChannelCount           = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setChannelCount");
35668     pContext->aaudio.AAudioStreamBuilder_setSampleRate             = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSampleRate");
35669     pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setBufferCapacityInFrames");
35670     pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback  = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFramesPerDataCallback");
35671     pContext->aaudio.AAudioStreamBuilder_setDataCallback           = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDataCallback");
35672     pContext->aaudio.AAudioStreamBuilder_setErrorCallback          = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setErrorCallback");
35673     pContext->aaudio.AAudioStreamBuilder_setPerformanceMode        = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setPerformanceMode");
35674     pContext->aaudio.AAudioStreamBuilder_setUsage                  = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setUsage");
35675     pContext->aaudio.AAudioStreamBuilder_setContentType            = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setContentType");
35676     pContext->aaudio.AAudioStreamBuilder_setInputPreset            = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setInputPreset");
35677     pContext->aaudio.AAudioStreamBuilder_openStream                = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_openStream");
35678     pContext->aaudio.AAudioStream_close                            = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_close");
35679     pContext->aaudio.AAudioStream_getState                         = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getState");
35680     pContext->aaudio.AAudioStream_waitForStateChange               = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_waitForStateChange");
35681     pContext->aaudio.AAudioStream_getFormat                        = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFormat");
35682     pContext->aaudio.AAudioStream_getChannelCount                  = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getChannelCount");
35683     pContext->aaudio.AAudioStream_getSampleRate                    = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getSampleRate");
35684     pContext->aaudio.AAudioStream_getBufferCapacityInFrames        = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getBufferCapacityInFrames");
35685     pContext->aaudio.AAudioStream_getFramesPerDataCallback         = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerDataCallback");
35686     pContext->aaudio.AAudioStream_getFramesPerBurst                = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerBurst");
35687     pContext->aaudio.AAudioStream_requestStart                     = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStart");
35688     pContext->aaudio.AAudioStream_requestStop                      = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStop");
35689
35690
35691     pCallbacks->onContextInit             = ma_context_init__aaudio;
35692     pCallbacks->onContextUninit           = ma_context_uninit__aaudio;
35693     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__aaudio;
35694     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__aaudio;
35695     pCallbacks->onDeviceInit              = ma_device_init__aaudio;
35696     pCallbacks->onDeviceUninit            = ma_device_uninit__aaudio;
35697     pCallbacks->onDeviceStart             = ma_device_start__aaudio;
35698     pCallbacks->onDeviceStop              = ma_device_stop__aaudio;
35699     pCallbacks->onDeviceRead              = NULL;   /* Not used because AAudio is asynchronous. */
35700     pCallbacks->onDeviceWrite             = NULL;   /* Not used because AAudio is asynchronous. */
35701     pCallbacks->onDeviceDataLoop          = NULL;   /* Not used because AAudio is asynchronous. */
35702     pCallbacks->onDeviceGetInfo           = ma_device_get_info__aaudio;
35703
35704     (void)pConfig;
35705     return MA_SUCCESS;
35706 }
35707 #endif  /* AAudio */
35708
35709
35710 /******************************************************************************
35711
35712 OpenSL|ES Backend
35713
35714 ******************************************************************************/
35715 #ifdef MA_HAS_OPENSL
35716 #include <SLES/OpenSLES.h>
35717 #ifdef MA_ANDROID
35718 #include <SLES/OpenSLES_Android.h>
35719 #endif
35720
35721 typedef SLresult (SLAPIENTRY * ma_slCreateEngine_proc)(SLObjectItf* pEngine, SLuint32 numOptions, SLEngineOption* pEngineOptions, SLuint32 numInterfaces, SLInterfaceID* pInterfaceIds, SLboolean* pInterfaceRequired);
35722
35723 /* OpenSL|ES has one-per-application objects :( */
35724 static SLObjectItf g_maEngineObjectSL    = NULL;
35725 static SLEngineItf g_maEngineSL          = NULL;
35726 static ma_uint32   g_maOpenSLInitCounter = 0;
35727 static ma_spinlock g_maOpenSLSpinlock    = 0;   /* For init/uninit. */
35728
35729 #define MA_OPENSL_OBJ(p)         (*((SLObjectItf)(p)))
35730 #define MA_OPENSL_OUTPUTMIX(p)   (*((SLOutputMixItf)(p)))
35731 #define MA_OPENSL_PLAY(p)        (*((SLPlayItf)(p)))
35732 #define MA_OPENSL_RECORD(p)      (*((SLRecordItf)(p)))
35733
35734 #ifdef MA_ANDROID
35735 #define MA_OPENSL_BUFFERQUEUE(p) (*((SLAndroidSimpleBufferQueueItf)(p)))
35736 #else
35737 #define MA_OPENSL_BUFFERQUEUE(p) (*((SLBufferQueueItf)(p)))
35738 #endif
35739
35740 static ma_result ma_result_from_OpenSL(SLuint32 result)
35741 {
35742     switch (result)
35743     {
35744         case SL_RESULT_SUCCESS:                 return MA_SUCCESS;
35745         case SL_RESULT_PRECONDITIONS_VIOLATED:  return MA_ERROR;
35746         case SL_RESULT_PARAMETER_INVALID:       return MA_INVALID_ARGS;
35747         case SL_RESULT_MEMORY_FAILURE:          return MA_OUT_OF_MEMORY;
35748         case SL_RESULT_RESOURCE_ERROR:          return MA_INVALID_DATA;
35749         case SL_RESULT_RESOURCE_LOST:           return MA_ERROR;
35750         case SL_RESULT_IO_ERROR:                return MA_IO_ERROR;
35751         case SL_RESULT_BUFFER_INSUFFICIENT:     return MA_NO_SPACE;
35752         case SL_RESULT_CONTENT_CORRUPTED:       return MA_INVALID_DATA;
35753         case SL_RESULT_CONTENT_UNSUPPORTED:     return MA_FORMAT_NOT_SUPPORTED;
35754         case SL_RESULT_CONTENT_NOT_FOUND:       return MA_ERROR;
35755         case SL_RESULT_PERMISSION_DENIED:       return MA_ACCESS_DENIED;
35756         case SL_RESULT_FEATURE_UNSUPPORTED:     return MA_NOT_IMPLEMENTED;
35757         case SL_RESULT_INTERNAL_ERROR:          return MA_ERROR;
35758         case SL_RESULT_UNKNOWN_ERROR:           return MA_ERROR;
35759         case SL_RESULT_OPERATION_ABORTED:       return MA_ERROR;
35760         case SL_RESULT_CONTROL_LOST:            return MA_ERROR;
35761         default:                                return MA_ERROR;
35762     }
35763 }
35764
35765 /* Converts an individual OpenSL-style channel identifier (SL_SPEAKER_FRONT_LEFT, etc.) to miniaudio. */
35766 static ma_uint8 ma_channel_id_to_ma__opensl(SLuint32 id)
35767 {
35768     switch (id)
35769     {
35770         case SL_SPEAKER_FRONT_LEFT:            return MA_CHANNEL_FRONT_LEFT;
35771         case SL_SPEAKER_FRONT_RIGHT:           return MA_CHANNEL_FRONT_RIGHT;
35772         case SL_SPEAKER_FRONT_CENTER:          return MA_CHANNEL_FRONT_CENTER;
35773         case SL_SPEAKER_LOW_FREQUENCY:         return MA_CHANNEL_LFE;
35774         case SL_SPEAKER_BACK_LEFT:             return MA_CHANNEL_BACK_LEFT;
35775         case SL_SPEAKER_BACK_RIGHT:            return MA_CHANNEL_BACK_RIGHT;
35776         case SL_SPEAKER_FRONT_LEFT_OF_CENTER:  return MA_CHANNEL_FRONT_LEFT_CENTER;
35777         case SL_SPEAKER_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER;
35778         case SL_SPEAKER_BACK_CENTER:           return MA_CHANNEL_BACK_CENTER;
35779         case SL_SPEAKER_SIDE_LEFT:             return MA_CHANNEL_SIDE_LEFT;
35780         case SL_SPEAKER_SIDE_RIGHT:            return MA_CHANNEL_SIDE_RIGHT;
35781         case SL_SPEAKER_TOP_CENTER:            return MA_CHANNEL_TOP_CENTER;
35782         case SL_SPEAKER_TOP_FRONT_LEFT:        return MA_CHANNEL_TOP_FRONT_LEFT;
35783         case SL_SPEAKER_TOP_FRONT_CENTER:      return MA_CHANNEL_TOP_FRONT_CENTER;
35784         case SL_SPEAKER_TOP_FRONT_RIGHT:       return MA_CHANNEL_TOP_FRONT_RIGHT;
35785         case SL_SPEAKER_TOP_BACK_LEFT:         return MA_CHANNEL_TOP_BACK_LEFT;
35786         case SL_SPEAKER_TOP_BACK_CENTER:       return MA_CHANNEL_TOP_BACK_CENTER;
35787         case SL_SPEAKER_TOP_BACK_RIGHT:        return MA_CHANNEL_TOP_BACK_RIGHT;
35788         default: return 0;
35789     }
35790 }
35791
35792 /* Converts an individual miniaudio channel identifier (MA_CHANNEL_FRONT_LEFT, etc.) to OpenSL-style. */
35793 static SLuint32 ma_channel_id_to_opensl(ma_uint8 id)
35794 {
35795     switch (id)
35796     {
35797         case MA_CHANNEL_MONO:               return SL_SPEAKER_FRONT_CENTER;
35798         case MA_CHANNEL_FRONT_LEFT:         return SL_SPEAKER_FRONT_LEFT;
35799         case MA_CHANNEL_FRONT_RIGHT:        return SL_SPEAKER_FRONT_RIGHT;
35800         case MA_CHANNEL_FRONT_CENTER:       return SL_SPEAKER_FRONT_CENTER;
35801         case MA_CHANNEL_LFE:                return SL_SPEAKER_LOW_FREQUENCY;
35802         case MA_CHANNEL_BACK_LEFT:          return SL_SPEAKER_BACK_LEFT;
35803         case MA_CHANNEL_BACK_RIGHT:         return SL_SPEAKER_BACK_RIGHT;
35804         case MA_CHANNEL_FRONT_LEFT_CENTER:  return SL_SPEAKER_FRONT_LEFT_OF_CENTER;
35805         case MA_CHANNEL_FRONT_RIGHT_CENTER: return SL_SPEAKER_FRONT_RIGHT_OF_CENTER;
35806         case MA_CHANNEL_BACK_CENTER:        return SL_SPEAKER_BACK_CENTER;
35807         case MA_CHANNEL_SIDE_LEFT:          return SL_SPEAKER_SIDE_LEFT;
35808         case MA_CHANNEL_SIDE_RIGHT:         return SL_SPEAKER_SIDE_RIGHT;
35809         case MA_CHANNEL_TOP_CENTER:         return SL_SPEAKER_TOP_CENTER;
35810         case MA_CHANNEL_TOP_FRONT_LEFT:     return SL_SPEAKER_TOP_FRONT_LEFT;
35811         case MA_CHANNEL_TOP_FRONT_CENTER:   return SL_SPEAKER_TOP_FRONT_CENTER;
35812         case MA_CHANNEL_TOP_FRONT_RIGHT:    return SL_SPEAKER_TOP_FRONT_RIGHT;
35813         case MA_CHANNEL_TOP_BACK_LEFT:      return SL_SPEAKER_TOP_BACK_LEFT;
35814         case MA_CHANNEL_TOP_BACK_CENTER:    return SL_SPEAKER_TOP_BACK_CENTER;
35815         case MA_CHANNEL_TOP_BACK_RIGHT:     return SL_SPEAKER_TOP_BACK_RIGHT;
35816         default: return 0;
35817     }
35818 }
35819
35820 /* Converts a channel mapping to an OpenSL-style channel mask. */
35821 static SLuint32 ma_channel_map_to_channel_mask__opensl(const ma_channel* pChannelMap, ma_uint32 channels)
35822 {
35823     SLuint32 channelMask = 0;
35824     ma_uint32 iChannel;
35825     for (iChannel = 0; iChannel < channels; ++iChannel) {
35826         channelMask |= ma_channel_id_to_opensl(pChannelMap[iChannel]);
35827     }
35828
35829     return channelMask;
35830 }
35831
35832 /* Converts an OpenSL-style channel mask to a miniaudio channel map. */
35833 static void ma_channel_mask_to_channel_map__opensl(SLuint32 channelMask, ma_uint32 channels, ma_channel* pChannelMap)
35834 {
35835     if (channels == 1 && channelMask == 0) {
35836         pChannelMap[0] = MA_CHANNEL_MONO;
35837     } else if (channels == 2 && channelMask == 0) {
35838         pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
35839         pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
35840     } else {
35841         if (channels == 1 && (channelMask & SL_SPEAKER_FRONT_CENTER) != 0) {
35842             pChannelMap[0] = MA_CHANNEL_MONO;
35843         } else {
35844             /* Just iterate over each bit. */
35845             ma_uint32 iChannel = 0;
35846             ma_uint32 iBit;
35847             for (iBit = 0; iBit < 32 && iChannel < channels; ++iBit) {
35848                 SLuint32 bitValue = (channelMask & (1UL << iBit));
35849                 if (bitValue != 0) {
35850                     /* The bit is set. */
35851                     pChannelMap[iChannel] = ma_channel_id_to_ma__opensl(bitValue);
35852                     iChannel += 1;
35853                 }
35854             }
35855         }
35856     }
35857 }
35858
35859 static SLuint32 ma_round_to_standard_sample_rate__opensl(SLuint32 samplesPerSec)
35860 {
35861     if (samplesPerSec <= SL_SAMPLINGRATE_8) {
35862         return SL_SAMPLINGRATE_8;
35863     }
35864     if (samplesPerSec <= SL_SAMPLINGRATE_11_025) {
35865         return SL_SAMPLINGRATE_11_025;
35866     }
35867     if (samplesPerSec <= SL_SAMPLINGRATE_12) {
35868         return SL_SAMPLINGRATE_12;
35869     }
35870     if (samplesPerSec <= SL_SAMPLINGRATE_16) {
35871         return SL_SAMPLINGRATE_16;
35872     }
35873     if (samplesPerSec <= SL_SAMPLINGRATE_22_05) {
35874         return SL_SAMPLINGRATE_22_05;
35875     }
35876     if (samplesPerSec <= SL_SAMPLINGRATE_24) {
35877         return SL_SAMPLINGRATE_24;
35878     }
35879     if (samplesPerSec <= SL_SAMPLINGRATE_32) {
35880         return SL_SAMPLINGRATE_32;
35881     }
35882     if (samplesPerSec <= SL_SAMPLINGRATE_44_1) {
35883         return SL_SAMPLINGRATE_44_1;
35884     }
35885     if (samplesPerSec <= SL_SAMPLINGRATE_48) {
35886         return SL_SAMPLINGRATE_48;
35887     }
35888
35889     /* Android doesn't support more than 48000. */
35890 #ifndef MA_ANDROID
35891     if (samplesPerSec <= SL_SAMPLINGRATE_64) {
35892         return SL_SAMPLINGRATE_64;
35893     }
35894     if (samplesPerSec <= SL_SAMPLINGRATE_88_2) {
35895         return SL_SAMPLINGRATE_88_2;
35896     }
35897     if (samplesPerSec <= SL_SAMPLINGRATE_96) {
35898         return SL_SAMPLINGRATE_96;
35899     }
35900     if (samplesPerSec <= SL_SAMPLINGRATE_192) {
35901         return SL_SAMPLINGRATE_192;
35902     }
35903 #endif
35904
35905     return SL_SAMPLINGRATE_16;
35906 }
35907
35908
35909 static SLint32 ma_to_stream_type__opensl(ma_opensl_stream_type streamType)
35910 {
35911     switch (streamType) {
35912         case ma_opensl_stream_type_voice:        return SL_ANDROID_STREAM_VOICE;
35913         case ma_opensl_stream_type_system:       return SL_ANDROID_STREAM_SYSTEM;
35914         case ma_opensl_stream_type_ring:         return SL_ANDROID_STREAM_RING;
35915         case ma_opensl_stream_type_media:        return SL_ANDROID_STREAM_MEDIA;
35916         case ma_opensl_stream_type_alarm:        return SL_ANDROID_STREAM_ALARM;
35917         case ma_opensl_stream_type_notification: return SL_ANDROID_STREAM_NOTIFICATION;
35918         default: break;
35919     }
35920
35921     return SL_ANDROID_STREAM_VOICE;
35922 }
35923
35924 static SLint32 ma_to_recording_preset__opensl(ma_opensl_recording_preset recordingPreset)
35925 {
35926     switch (recordingPreset) {
35927         case ma_opensl_recording_preset_generic:             return SL_ANDROID_RECORDING_PRESET_GENERIC;
35928         case ma_opensl_recording_preset_camcorder:           return SL_ANDROID_RECORDING_PRESET_CAMCORDER;
35929         case ma_opensl_recording_preset_voice_recognition:   return SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
35930         case ma_opensl_recording_preset_voice_communication: return SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
35931         case ma_opensl_recording_preset_voice_unprocessed:   return SL_ANDROID_RECORDING_PRESET_UNPROCESSED;
35932         default: break;
35933     }
35934
35935     return SL_ANDROID_RECORDING_PRESET_NONE;
35936 }
35937
35938
35939 static ma_result ma_context_enumerate_devices__opensl(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
35940 {
35941     ma_bool32 cbResult;
35942
35943     MA_ASSERT(pContext != NULL);
35944     MA_ASSERT(callback != NULL);
35945
35946     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. */
35947     if (g_maOpenSLInitCounter == 0) {
35948         return MA_INVALID_OPERATION;
35949     }
35950
35951     /*
35952     TODO: Test Me.
35953
35954     This is currently untested, so for now we are just returning default devices.
35955     */
35956 #if 0 && !defined(MA_ANDROID)
35957     ma_bool32 isTerminated = MA_FALSE;
35958
35959     SLuint32 pDeviceIDs[128];
35960     SLint32 deviceCount = sizeof(pDeviceIDs) / sizeof(pDeviceIDs[0]);
35961
35962     SLAudioIODeviceCapabilitiesItf deviceCaps;
35963     SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps);
35964     if (resultSL != SL_RESULT_SUCCESS) {
35965         /* The interface may not be supported so just report a default device. */
35966         goto return_default_device;
35967     }
35968
35969     /* Playback */
35970     if (!isTerminated) {
35971         resultSL = (*deviceCaps)->GetAvailableAudioOutputs(deviceCaps, &deviceCount, pDeviceIDs);
35972         if (resultSL != SL_RESULT_SUCCESS) {
35973             return ma_result_from_OpenSL(resultSL);
35974         }
35975
35976         for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) {
35977             ma_device_info deviceInfo;
35978             MA_ZERO_OBJECT(&deviceInfo);
35979             deviceInfo.id.opensl = pDeviceIDs[iDevice];
35980
35981             SLAudioOutputDescriptor desc;
35982             resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, deviceInfo.id.opensl, &desc);
35983             if (resultSL == SL_RESULT_SUCCESS) {
35984                 ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)desc.pDeviceName, (size_t)-1);
35985
35986                 ma_bool32 cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
35987                 if (cbResult == MA_FALSE) {
35988                     isTerminated = MA_TRUE;
35989                     break;
35990                 }
35991             }
35992         }
35993     }
35994
35995     /* Capture */
35996     if (!isTerminated) {
35997         resultSL = (*deviceCaps)->GetAvailableAudioInputs(deviceCaps, &deviceCount, pDeviceIDs);
35998         if (resultSL != SL_RESULT_SUCCESS) {
35999             return ma_result_from_OpenSL(resultSL);
36000         }
36001
36002         for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) {
36003             ma_device_info deviceInfo;
36004             MA_ZERO_OBJECT(&deviceInfo);
36005             deviceInfo.id.opensl = pDeviceIDs[iDevice];
36006
36007             SLAudioInputDescriptor desc;
36008             resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, deviceInfo.id.opensl, &desc);
36009             if (resultSL == SL_RESULT_SUCCESS) {
36010                 ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)desc.deviceName, (size_t)-1);
36011
36012                 ma_bool32 cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
36013                 if (cbResult == MA_FALSE) {
36014                     isTerminated = MA_TRUE;
36015                     break;
36016                 }
36017             }
36018         }
36019     }
36020
36021     return MA_SUCCESS;
36022 #else
36023     goto return_default_device;
36024 #endif
36025
36026 return_default_device:;
36027     cbResult = MA_TRUE;
36028
36029     /* Playback. */
36030     if (cbResult) {
36031         ma_device_info deviceInfo;
36032         MA_ZERO_OBJECT(&deviceInfo);
36033         deviceInfo.id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT;
36034         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
36035         cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
36036     }
36037
36038     /* Capture. */
36039     if (cbResult) {
36040         ma_device_info deviceInfo;
36041         MA_ZERO_OBJECT(&deviceInfo);
36042         deviceInfo.id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT;
36043         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
36044         cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
36045     }
36046
36047     return MA_SUCCESS;
36048 }
36049
36050 static void ma_context_add_data_format_ex__opensl(ma_context* pContext, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_device_info* pDeviceInfo)
36051 {
36052     MA_ASSERT(pContext    != NULL);
36053     MA_ASSERT(pDeviceInfo != NULL);
36054
36055     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = format;
36056     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
36057     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate;
36058     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = 0;
36059     pDeviceInfo->nativeDataFormatCount += 1;
36060 }
36061
36062 static void ma_context_add_data_format__opensl(ma_context* pContext, ma_format format, ma_device_info* pDeviceInfo)
36063 {
36064     ma_uint32 minChannels   = 1;
36065     ma_uint32 maxChannels   = 2;
36066     ma_uint32 minSampleRate = (ma_uint32)ma_standard_sample_rate_8000;
36067     ma_uint32 maxSampleRate = (ma_uint32)ma_standard_sample_rate_48000;
36068     ma_uint32 iChannel;
36069     ma_uint32 iSampleRate;
36070
36071     MA_ASSERT(pContext    != NULL);
36072     MA_ASSERT(pDeviceInfo != NULL);
36073
36074     /*
36075     Each sample format can support mono and stereo, and we'll support a small subset of standard
36076     rates (up to 48000). A better solution would be to somehow find a native sample rate.
36077     */
36078     for (iChannel = minChannels; iChannel < maxChannels; iChannel += 1) {
36079         for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); iSampleRate += 1) {
36080             ma_uint32 standardSampleRate = g_maStandardSampleRatePriorities[iSampleRate];
36081             if (standardSampleRate >= minSampleRate && standardSampleRate <= maxSampleRate) {
36082                 ma_context_add_data_format_ex__opensl(pContext, format, iChannel, standardSampleRate, pDeviceInfo);
36083             }
36084         }
36085     }
36086 }
36087
36088 static ma_result ma_context_get_device_info__opensl(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
36089 {
36090     MA_ASSERT(pContext != NULL);
36091
36092     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. */
36093     if (g_maOpenSLInitCounter == 0) {
36094         return MA_INVALID_OPERATION;
36095     }
36096
36097     /*
36098     TODO: Test Me.
36099
36100     This is currently untested, so for now we are just returning default devices.
36101     */
36102 #if 0 && !defined(MA_ANDROID)
36103     SLAudioIODeviceCapabilitiesItf deviceCaps;
36104     SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps);
36105     if (resultSL != SL_RESULT_SUCCESS) {
36106         /* The interface may not be supported so just report a default device. */
36107         goto return_default_device;
36108     }
36109
36110     if (deviceType == ma_device_type_playback) {
36111         SLAudioOutputDescriptor desc;
36112         resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, pDeviceID->opensl, &desc);
36113         if (resultSL != SL_RESULT_SUCCESS) {
36114             return ma_result_from_OpenSL(resultSL);
36115         }
36116
36117         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (const char*)desc.pDeviceName, (size_t)-1);
36118     } else {
36119         SLAudioInputDescriptor desc;
36120         resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, pDeviceID->opensl, &desc);
36121         if (resultSL != SL_RESULT_SUCCESS) {
36122             return ma_result_from_OpenSL(resultSL);
36123         }
36124
36125         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (const char*)desc.deviceName, (size_t)-1);
36126     }
36127
36128     goto return_detailed_info;
36129 #else
36130     goto return_default_device;
36131 #endif
36132
36133 return_default_device:
36134     if (pDeviceID != NULL) {
36135         if ((deviceType == ma_device_type_playback && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOOUTPUT) ||
36136             (deviceType == ma_device_type_capture  && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOINPUT)) {
36137             return MA_NO_DEVICE;   /* Don't know the device. */
36138         }
36139     }
36140
36141     /* ID and Name / Description */
36142     if (deviceType == ma_device_type_playback) {
36143         pDeviceInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT;
36144         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
36145     } else {
36146         pDeviceInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT;
36147         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
36148     }
36149
36150     pDeviceInfo->isDefault = MA_TRUE;
36151
36152     goto return_detailed_info;
36153
36154
36155 return_detailed_info:
36156
36157     /*
36158     For now we're just outputting a set of values that are supported by the API but not necessarily supported
36159     by the device natively. Later on we should work on this so that it more closely reflects the device's
36160     actual native format.
36161     */
36162     pDeviceInfo->nativeDataFormatCount = 0;
36163 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
36164     ma_context_add_data_format__opensl(pContext, ma_format_f32, pDeviceInfo);
36165 #endif
36166     ma_context_add_data_format__opensl(pContext, ma_format_s16, pDeviceInfo);
36167     ma_context_add_data_format__opensl(pContext, ma_format_u8,  pDeviceInfo);
36168
36169     return MA_SUCCESS;
36170 }
36171
36172
36173 #ifdef MA_ANDROID
36174 /*void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, SLuint32 eventFlags, const void* pBuffer, SLuint32 bufferSize, SLuint32 dataUsed, void* pContext)*/
36175 static void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData)
36176 {
36177     ma_device* pDevice = (ma_device*)pUserData;
36178     size_t periodSizeInBytes;
36179     ma_uint8* pBuffer;
36180     SLresult resultSL;
36181
36182     MA_ASSERT(pDevice != NULL);
36183
36184     (void)pBufferQueue;
36185
36186     /*
36187     For now, don't do anything unless the buffer was fully processed. From what I can tell, it looks like
36188     OpenSL|ES 1.1 improves on buffer queues to the point that we could much more intelligently handle this,
36189     but unfortunately it looks like Android is only supporting OpenSL|ES 1.0.1 for now :(
36190     */
36191
36192     /* Don't do anything if the device is not started. */
36193     if (ma_device_get_state(pDevice) != ma_device_state_started) {
36194         return;
36195     }
36196
36197     /* Don't do anything if the device is being drained. */
36198     if (pDevice->opensl.isDrainingCapture) {
36199         return;
36200     }
36201
36202     periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
36203     pBuffer = pDevice->opensl.pBufferCapture + (pDevice->opensl.currentBufferIndexCapture * periodSizeInBytes);
36204
36205     ma_device_handle_backend_data_callback(pDevice, NULL, pBuffer, pDevice->capture.internalPeriodSizeInFrames);
36206
36207     resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pBuffer, periodSizeInBytes);
36208     if (resultSL != SL_RESULT_SUCCESS) {
36209         return;
36210     }
36211
36212     pDevice->opensl.currentBufferIndexCapture = (pDevice->opensl.currentBufferIndexCapture + 1) % pDevice->capture.internalPeriods;
36213 }
36214
36215 static void ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData)
36216 {
36217     ma_device* pDevice = (ma_device*)pUserData;
36218     size_t periodSizeInBytes;
36219     ma_uint8* pBuffer;
36220     SLresult resultSL;
36221
36222     MA_ASSERT(pDevice != NULL);
36223
36224     (void)pBufferQueue;
36225
36226     /* Don't do anything if the device is not started. */
36227     if (ma_device_get_state(pDevice) != ma_device_state_started) {
36228         return;
36229     }
36230
36231     /* Don't do anything if the device is being drained. */
36232     if (pDevice->opensl.isDrainingPlayback) {
36233         return;
36234     }
36235
36236     periodSizeInBytes = pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
36237     pBuffer = pDevice->opensl.pBufferPlayback + (pDevice->opensl.currentBufferIndexPlayback * periodSizeInBytes);
36238
36239     ma_device_handle_backend_data_callback(pDevice, pBuffer, NULL, pDevice->playback.internalPeriodSizeInFrames);
36240
36241     resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pBuffer, periodSizeInBytes);
36242     if (resultSL != SL_RESULT_SUCCESS) {
36243         return;
36244     }
36245
36246     pDevice->opensl.currentBufferIndexPlayback = (pDevice->opensl.currentBufferIndexPlayback + 1) % pDevice->playback.internalPeriods;
36247 }
36248 #endif
36249
36250 static ma_result ma_device_uninit__opensl(ma_device* pDevice)
36251 {
36252     MA_ASSERT(pDevice != NULL);
36253
36254     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. */
36255     if (g_maOpenSLInitCounter == 0) {
36256         return MA_INVALID_OPERATION;
36257     }
36258
36259     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
36260         if (pDevice->opensl.pAudioRecorderObj) {
36261             MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioRecorderObj);
36262         }
36263
36264         ma_free(pDevice->opensl.pBufferCapture, &pDevice->pContext->allocationCallbacks);
36265     }
36266
36267     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
36268         if (pDevice->opensl.pAudioPlayerObj) {
36269             MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioPlayerObj);
36270         }
36271         if (pDevice->opensl.pOutputMixObj) {
36272             MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Destroy((SLObjectItf)pDevice->opensl.pOutputMixObj);
36273         }
36274
36275         ma_free(pDevice->opensl.pBufferPlayback, &pDevice->pContext->allocationCallbacks);
36276     }
36277
36278     return MA_SUCCESS;
36279 }
36280
36281 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
36282 typedef SLAndroidDataFormat_PCM_EX  ma_SLDataFormat_PCM;
36283 #else
36284 typedef SLDataFormat_PCM            ma_SLDataFormat_PCM;
36285 #endif
36286
36287 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)
36288 {
36289     /* We need to convert our format/channels/rate so that they aren't set to default. */
36290     if (format == ma_format_unknown) {
36291         format = MA_DEFAULT_FORMAT;
36292     }
36293     if (channels == 0) {
36294         channels = MA_DEFAULT_CHANNELS;
36295     }
36296     if (sampleRate == 0) {
36297         sampleRate = MA_DEFAULT_SAMPLE_RATE;
36298     }
36299
36300 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
36301     if (format == ma_format_f32) {
36302         pDataFormat->formatType     = SL_ANDROID_DATAFORMAT_PCM_EX;
36303         pDataFormat->representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
36304     } else {
36305         pDataFormat->formatType = SL_DATAFORMAT_PCM;
36306     }
36307 #else
36308     pDataFormat->formatType = SL_DATAFORMAT_PCM;
36309 #endif
36310
36311     pDataFormat->numChannels   = channels;
36312     ((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 */
36313     pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format) * 8;
36314     pDataFormat->channelMask   = ma_channel_map_to_channel_mask__opensl(channelMap, channels);
36315     pDataFormat->endianness    = (ma_is_little_endian()) ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN;
36316
36317     /*
36318     Android has a few restrictions on the format as documented here: https://developer.android.com/ndk/guides/audio/opensl-for-android.html
36319      - Only mono and stereo is supported.
36320      - Only u8 and s16 formats are supported.
36321      - Maximum sample rate of 48000.
36322     */
36323 #ifdef MA_ANDROID
36324     if (pDataFormat->numChannels > 2) {
36325         pDataFormat->numChannels = 2;
36326     }
36327 #if __ANDROID_API__ >= 21
36328     if (pDataFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) {
36329         /* It's floating point. */
36330         MA_ASSERT(pDataFormat->representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT);
36331         if (pDataFormat->bitsPerSample > 32) {
36332             pDataFormat->bitsPerSample = 32;
36333         }
36334     } else {
36335         if (pDataFormat->bitsPerSample > 16) {
36336             pDataFormat->bitsPerSample = 16;
36337         }
36338     }
36339 #else
36340     if (pDataFormat->bitsPerSample > 16) {
36341         pDataFormat->bitsPerSample = 16;
36342     }
36343 #endif
36344     if (((SLDataFormat_PCM*)pDataFormat)->samplesPerSec > SL_SAMPLINGRATE_48) {
36345         ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = SL_SAMPLINGRATE_48;
36346     }
36347 #endif
36348
36349     pDataFormat->containerSize = pDataFormat->bitsPerSample;  /* Always tightly packed for now. */
36350
36351     return MA_SUCCESS;
36352 }
36353
36354 static ma_result ma_deconstruct_SLDataFormat_PCM__opensl(ma_SLDataFormat_PCM* pDataFormat, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
36355 {
36356     ma_bool32 isFloatingPoint = MA_FALSE;
36357 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
36358     if (pDataFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) {
36359         MA_ASSERT(pDataFormat->representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT);
36360         isFloatingPoint = MA_TRUE;
36361     }
36362 #endif
36363     if (isFloatingPoint) {
36364         if (pDataFormat->bitsPerSample == 32) {
36365             *pFormat = ma_format_f32;
36366         }
36367     } else {
36368         if (pDataFormat->bitsPerSample == 8) {
36369             *pFormat = ma_format_u8;
36370         } else if (pDataFormat->bitsPerSample == 16) {
36371             *pFormat = ma_format_s16;
36372         } else if (pDataFormat->bitsPerSample == 24) {
36373             *pFormat = ma_format_s24;
36374         } else if (pDataFormat->bitsPerSample == 32) {
36375             *pFormat = ma_format_s32;
36376         }
36377     }
36378
36379     *pChannels   = pDataFormat->numChannels;
36380     *pSampleRate = ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec / 1000;
36381     ma_channel_mask_to_channel_map__opensl(pDataFormat->channelMask, ma_min(pDataFormat->numChannels, channelMapCap), pChannelMap);
36382
36383     return MA_SUCCESS;
36384 }
36385
36386 static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
36387 {
36388 #ifdef MA_ANDROID
36389     SLDataLocator_AndroidSimpleBufferQueue queue;
36390     SLresult resultSL;
36391     size_t bufferSizeInBytes;
36392     SLInterfaceID itfIDs[2];
36393     const SLboolean itfIDsRequired[] = {
36394         SL_BOOLEAN_TRUE,    /* SL_IID_ANDROIDSIMPLEBUFFERQUEUE */
36395         SL_BOOLEAN_FALSE    /* SL_IID_ANDROIDCONFIGURATION */
36396     };
36397 #endif
36398
36399     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. */
36400     if (g_maOpenSLInitCounter == 0) {
36401         return MA_INVALID_OPERATION;
36402     }
36403
36404     if (pConfig->deviceType == ma_device_type_loopback) {
36405         return MA_DEVICE_TYPE_NOT_SUPPORTED;
36406     }
36407
36408     /*
36409     For now, only supporting Android implementations of OpenSL|ES since that's the only one I've
36410     been able to test with and I currently depend on Android-specific extensions (simple buffer
36411     queues).
36412     */
36413 #ifdef MA_ANDROID
36414     itfIDs[0] = (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
36415     itfIDs[1] = (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDCONFIGURATION;
36416
36417     /* No exclusive mode with OpenSL|ES. */
36418     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
36419         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive)) {
36420         return MA_SHARE_MODE_NOT_SUPPORTED;
36421     }
36422
36423     /* Now we can start initializing the device properly. */
36424     MA_ASSERT(pDevice != NULL);
36425     MA_ZERO_OBJECT(&pDevice->opensl);
36426
36427     queue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
36428
36429     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
36430         ma_SLDataFormat_PCM pcm;
36431         SLDataLocator_IODevice locatorDevice;
36432         SLDataSource source;
36433         SLDataSink sink;
36434         SLAndroidConfigurationItf pRecorderConfig;
36435
36436         ma_SLDataFormat_PCM_init__opensl(pDescriptorCapture->format, pDescriptorCapture->channels, pDescriptorCapture->sampleRate, pDescriptorCapture->channelMap, &pcm);
36437
36438         locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE;
36439         locatorDevice.deviceType  = SL_IODEVICE_AUDIOINPUT;
36440         locatorDevice.deviceID    = SL_DEFAULTDEVICEID_AUDIOINPUT;  /* Must always use the default device with Android. */
36441         locatorDevice.device      = NULL;
36442
36443         source.pLocator = &locatorDevice;
36444         source.pFormat  = NULL;
36445
36446         queue.numBuffers = pDescriptorCapture->periodCount;
36447
36448         sink.pLocator = &queue;
36449         sink.pFormat  = (SLDataFormat_PCM*)&pcm;
36450
36451         resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired);
36452         if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED || resultSL == SL_RESULT_PARAMETER_INVALID) {
36453             /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
36454             pcm.formatType    = SL_DATAFORMAT_PCM;
36455             pcm.numChannels   = 1;
36456             ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16;  /* The name of the sample rate variable is different between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM. */
36457             pcm.bitsPerSample = 16;
36458             pcm.containerSize = pcm.bitsPerSample;  /* Always tightly packed for now. */
36459             pcm.channelMask   = 0;
36460             resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired);
36461         }
36462
36463         if (resultSL != SL_RESULT_SUCCESS) {
36464             ma_device_uninit__opensl(pDevice);
36465             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio recorder.");
36466             return ma_result_from_OpenSL(resultSL);
36467         }
36468
36469
36470         /* Set the recording preset before realizing the player. */
36471         if (pConfig->opensl.recordingPreset != ma_opensl_recording_preset_default) {
36472             resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDCONFIGURATION, &pRecorderConfig);
36473             if (resultSL == SL_RESULT_SUCCESS) {
36474                 SLint32 recordingPreset = ma_to_recording_preset__opensl(pConfig->opensl.recordingPreset);
36475                 resultSL = (*pRecorderConfig)->SetConfiguration(pRecorderConfig, SL_ANDROID_KEY_RECORDING_PRESET, &recordingPreset, sizeof(SLint32));
36476                 if (resultSL != SL_RESULT_SUCCESS) {
36477                     /* Failed to set the configuration. Just keep going. */
36478                 }
36479             }
36480         }
36481
36482         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Realize((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_BOOLEAN_FALSE);
36483         if (resultSL != SL_RESULT_SUCCESS) {
36484             ma_device_uninit__opensl(pDevice);
36485             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder.");
36486             return ma_result_from_OpenSL(resultSL);
36487         }
36488
36489         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_RECORD, &pDevice->opensl.pAudioRecorder);
36490         if (resultSL != SL_RESULT_SUCCESS) {
36491             ma_device_uninit__opensl(pDevice);
36492             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.");
36493             return ma_result_from_OpenSL(resultSL);
36494         }
36495
36496         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueueCapture);
36497         if (resultSL != SL_RESULT_SUCCESS) {
36498             ma_device_uninit__opensl(pDevice);
36499             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.");
36500             return ma_result_from_OpenSL(resultSL);
36501         }
36502
36503         resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, ma_buffer_queue_callback_capture__opensl_android, pDevice);
36504         if (resultSL != SL_RESULT_SUCCESS) {
36505             ma_device_uninit__opensl(pDevice);
36506             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.");
36507             return ma_result_from_OpenSL(resultSL);
36508         }
36509
36510         /* The internal format is determined by the "pcm" object. */
36511         ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDescriptorCapture->format, &pDescriptorCapture->channels, &pDescriptorCapture->sampleRate, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap));
36512
36513         /* Buffer. */
36514         pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile);
36515         pDevice->opensl.currentBufferIndexCapture = 0;
36516
36517         bufferSizeInBytes = pDescriptorCapture->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) * pDescriptorCapture->periodCount;
36518         pDevice->opensl.pBufferCapture = (ma_uint8*)ma_calloc(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks);
36519         if (pDevice->opensl.pBufferCapture == NULL) {
36520             ma_device_uninit__opensl(pDevice);
36521             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.");
36522             return MA_OUT_OF_MEMORY;
36523         }
36524         MA_ZERO_MEMORY(pDevice->opensl.pBufferCapture, bufferSizeInBytes);
36525     }
36526
36527     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
36528         ma_SLDataFormat_PCM pcm;
36529         SLDataSource source;
36530         SLDataLocator_OutputMix outmixLocator;
36531         SLDataSink sink;
36532         SLAndroidConfigurationItf pPlayerConfig;
36533
36534         ma_SLDataFormat_PCM_init__opensl(pDescriptorPlayback->format, pDescriptorPlayback->channels, pDescriptorPlayback->sampleRate, pDescriptorPlayback->channelMap, &pcm);
36535
36536         resultSL = (*g_maEngineSL)->CreateOutputMix(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pOutputMixObj, 0, NULL, NULL);
36537         if (resultSL != SL_RESULT_SUCCESS) {
36538             ma_device_uninit__opensl(pDevice);
36539             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create output mix.");
36540             return ma_result_from_OpenSL(resultSL);
36541         }
36542
36543         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Realize((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_BOOLEAN_FALSE);
36544         if (resultSL != SL_RESULT_SUCCESS) {
36545             ma_device_uninit__opensl(pDevice);
36546             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object.");
36547             return ma_result_from_OpenSL(resultSL);
36548         }
36549
36550         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->GetInterface((SLObjectItf)pDevice->opensl.pOutputMixObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_OUTPUTMIX, &pDevice->opensl.pOutputMix);
36551         if (resultSL != SL_RESULT_SUCCESS) {
36552             ma_device_uninit__opensl(pDevice);
36553             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.");
36554             return ma_result_from_OpenSL(resultSL);
36555         }
36556
36557         /* Set the output device. */
36558         if (pDescriptorPlayback->pDeviceID != NULL) {
36559             SLuint32 deviceID_OpenSL = pDescriptorPlayback->pDeviceID->opensl;
36560             MA_OPENSL_OUTPUTMIX(pDevice->opensl.pOutputMix)->ReRoute((SLOutputMixItf)pDevice->opensl.pOutputMix, 1, &deviceID_OpenSL);
36561         }
36562
36563         queue.numBuffers = pDescriptorPlayback->periodCount;
36564
36565         source.pLocator = &queue;
36566         source.pFormat  = (SLDataFormat_PCM*)&pcm;
36567
36568         outmixLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX;
36569         outmixLocator.outputMix   = (SLObjectItf)pDevice->opensl.pOutputMixObj;
36570
36571         sink.pLocator = &outmixLocator;
36572         sink.pFormat  = NULL;
36573
36574         resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired);
36575         if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED || resultSL == SL_RESULT_PARAMETER_INVALID) {
36576             /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
36577             pcm.formatType = SL_DATAFORMAT_PCM;
36578             pcm.numChannels = 2;
36579             ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16;
36580             pcm.bitsPerSample = 16;
36581             pcm.containerSize = pcm.bitsPerSample;  /* Always tightly packed for now. */
36582             pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
36583             resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, ma_countof(itfIDs), itfIDs, itfIDsRequired);
36584         }
36585
36586         if (resultSL != SL_RESULT_SUCCESS) {
36587             ma_device_uninit__opensl(pDevice);
36588             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio player.");
36589             return ma_result_from_OpenSL(resultSL);
36590         }
36591
36592
36593         /* Set the stream type before realizing the player. */
36594         if (pConfig->opensl.streamType != ma_opensl_stream_type_default) {
36595             resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDCONFIGURATION, &pPlayerConfig);
36596             if (resultSL == SL_RESULT_SUCCESS) {
36597                 SLint32 streamType = ma_to_stream_type__opensl(pConfig->opensl.streamType);
36598                 resultSL = (*pPlayerConfig)->SetConfiguration(pPlayerConfig, SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
36599                 if (resultSL != SL_RESULT_SUCCESS) {
36600                     /* Failed to set the configuration. Just keep going. */
36601                 }
36602             }
36603         }
36604
36605         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Realize((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_BOOLEAN_FALSE);
36606         if (resultSL != SL_RESULT_SUCCESS) {
36607             ma_device_uninit__opensl(pDevice);
36608             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player.");
36609             return ma_result_from_OpenSL(resultSL);
36610         }
36611
36612         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_PLAY, &pDevice->opensl.pAudioPlayer);
36613         if (resultSL != SL_RESULT_SUCCESS) {
36614             ma_device_uninit__opensl(pDevice);
36615             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.");
36616             return ma_result_from_OpenSL(resultSL);
36617         }
36618
36619         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueuePlayback);
36620         if (resultSL != SL_RESULT_SUCCESS) {
36621             ma_device_uninit__opensl(pDevice);
36622             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.");
36623             return ma_result_from_OpenSL(resultSL);
36624         }
36625
36626         resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, ma_buffer_queue_callback_playback__opensl_android, pDevice);
36627         if (resultSL != SL_RESULT_SUCCESS) {
36628             ma_device_uninit__opensl(pDevice);
36629             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.");
36630             return ma_result_from_OpenSL(resultSL);
36631         }
36632
36633         /* The internal format is determined by the "pcm" object. */
36634         ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDescriptorPlayback->format, &pDescriptorPlayback->channels, &pDescriptorPlayback->sampleRate, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap));
36635
36636         /* Buffer. */
36637         pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
36638         pDevice->opensl.currentBufferIndexPlayback   = 0;
36639
36640         bufferSizeInBytes = pDescriptorPlayback->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) * pDescriptorPlayback->periodCount;
36641         pDevice->opensl.pBufferPlayback = (ma_uint8*)ma_calloc(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks);
36642         if (pDevice->opensl.pBufferPlayback == NULL) {
36643             ma_device_uninit__opensl(pDevice);
36644             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.");
36645             return MA_OUT_OF_MEMORY;
36646         }
36647         MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, bufferSizeInBytes);
36648     }
36649
36650     return MA_SUCCESS;
36651 #else
36652     return MA_NO_BACKEND;   /* Non-Android implementations are not supported. */
36653 #endif
36654 }
36655
36656 static ma_result ma_device_start__opensl(ma_device* pDevice)
36657 {
36658     SLresult resultSL;
36659     size_t periodSizeInBytes;
36660     ma_uint32 iPeriod;
36661
36662     MA_ASSERT(pDevice != NULL);
36663
36664     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. */
36665     if (g_maOpenSLInitCounter == 0) {
36666         return MA_INVALID_OPERATION;
36667     }
36668
36669     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
36670         resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_RECORDING);
36671         if (resultSL != SL_RESULT_SUCCESS) {
36672             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal capture device.");
36673             return ma_result_from_OpenSL(resultSL);
36674         }
36675
36676         periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
36677         for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
36678             resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pDevice->opensl.pBufferCapture + (periodSizeInBytes * iPeriod), periodSizeInBytes);
36679             if (resultSL != SL_RESULT_SUCCESS) {
36680                 MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED);
36681                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for capture device.");
36682                 return ma_result_from_OpenSL(resultSL);
36683             }
36684         }
36685     }
36686
36687     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
36688         resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_PLAYING);
36689         if (resultSL != SL_RESULT_SUCCESS) {
36690             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal playback device.");
36691             return ma_result_from_OpenSL(resultSL);
36692         }
36693
36694         /* In playback mode (no duplex) we need to load some initial buffers. In duplex mode we need to enqueu silent buffers. */
36695         if (pDevice->type == ma_device_type_duplex) {
36696             MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
36697         } else {
36698             ma_device__read_frames_from_client(pDevice, pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods, pDevice->opensl.pBufferPlayback);
36699         }
36700
36701         periodSizeInBytes = pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
36702         for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) {
36703             resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pDevice->opensl.pBufferPlayback + (periodSizeInBytes * iPeriod), periodSizeInBytes);
36704             if (resultSL != SL_RESULT_SUCCESS) {
36705                 MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED);
36706                 ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for playback device.");
36707                 return ma_result_from_OpenSL(resultSL);
36708             }
36709         }
36710     }
36711
36712     return MA_SUCCESS;
36713 }
36714
36715 static ma_result ma_device_drain__opensl(ma_device* pDevice, ma_device_type deviceType)
36716 {
36717     SLAndroidSimpleBufferQueueItf pBufferQueue;
36718
36719     MA_ASSERT(deviceType == ma_device_type_capture || deviceType == ma_device_type_playback);
36720
36721     if (pDevice->type == ma_device_type_capture) {
36722         pBufferQueue = (SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture;
36723         pDevice->opensl.isDrainingCapture  = MA_TRUE;
36724     } else {
36725         pBufferQueue = (SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback;
36726         pDevice->opensl.isDrainingPlayback = MA_TRUE;
36727     }
36728
36729     for (;;) {
36730         SLAndroidSimpleBufferQueueState state;
36731
36732         MA_OPENSL_BUFFERQUEUE(pBufferQueue)->GetState(pBufferQueue, &state);
36733         if (state.count == 0) {
36734             break;
36735         }
36736
36737         ma_sleep(10);
36738     }
36739
36740     if (pDevice->type == ma_device_type_capture) {
36741         pDevice->opensl.isDrainingCapture  = MA_FALSE;
36742     } else {
36743         pDevice->opensl.isDrainingPlayback = MA_FALSE;
36744     }
36745
36746     return MA_SUCCESS;
36747 }
36748
36749 static ma_result ma_device_stop__opensl(ma_device* pDevice)
36750 {
36751     SLresult resultSL;
36752
36753     MA_ASSERT(pDevice != NULL);
36754
36755     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. */
36756     if (g_maOpenSLInitCounter == 0) {
36757         return MA_INVALID_OPERATION;
36758     }
36759
36760     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
36761         ma_device_drain__opensl(pDevice, ma_device_type_capture);
36762
36763         resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED);
36764         if (resultSL != SL_RESULT_SUCCESS) {
36765             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal capture device.");
36766             return ma_result_from_OpenSL(resultSL);
36767         }
36768
36769         MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture);
36770     }
36771
36772     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
36773         ma_device_drain__opensl(pDevice, ma_device_type_playback);
36774
36775         resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED);
36776         if (resultSL != SL_RESULT_SUCCESS) {
36777             ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal playback device.");
36778             return ma_result_from_OpenSL(resultSL);
36779         }
36780
36781         MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback);
36782     }
36783
36784     /* 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. */
36785     ma_device__on_notification_stopped(pDevice);
36786
36787     return MA_SUCCESS;
36788 }
36789
36790
36791 static ma_result ma_context_uninit__opensl(ma_context* pContext)
36792 {
36793     MA_ASSERT(pContext != NULL);
36794     MA_ASSERT(pContext->backend == ma_backend_opensl);
36795     (void)pContext;
36796
36797     /* Uninit global data. */
36798     ma_spinlock_lock(&g_maOpenSLSpinlock);
36799     {
36800         MA_ASSERT(g_maOpenSLInitCounter > 0);   /* If you've triggered this, it means you have ma_context_init/uninit mismatch. Each successful call to ma_context_init() must be matched up with a call to ma_context_uninit(). */
36801
36802         g_maOpenSLInitCounter -= 1;
36803         if (g_maOpenSLInitCounter == 0) {
36804             (*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL);
36805         }
36806     }
36807     ma_spinlock_unlock(&g_maOpenSLSpinlock);
36808
36809     return MA_SUCCESS;
36810 }
36811
36812 static ma_result ma_dlsym_SLInterfaceID__opensl(ma_context* pContext, const char* pName, ma_handle* pHandle)
36813 {
36814     /* We need to return an error if the symbol cannot be found. This is important because there have been reports that some symbols do not exist. */
36815     ma_handle* p = (ma_handle*)ma_dlsym(pContext, pContext->opensl.libOpenSLES, pName);
36816     if (p == NULL) {
36817         ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Cannot find symbol %s", pName);
36818         return MA_NO_BACKEND;
36819     }
36820
36821     *pHandle = *p;
36822     return MA_SUCCESS;
36823 }
36824
36825 static ma_result ma_context_init_engine_nolock__opensl(ma_context* pContext)
36826 {
36827     g_maOpenSLInitCounter += 1;
36828     if (g_maOpenSLInitCounter == 1) {
36829         SLresult resultSL;
36830
36831         resultSL = ((ma_slCreateEngine_proc)pContext->opensl.slCreateEngine)(&g_maEngineObjectSL, 0, NULL, 0, NULL, NULL);
36832         if (resultSL != SL_RESULT_SUCCESS) {
36833             g_maOpenSLInitCounter -= 1;
36834             return ma_result_from_OpenSL(resultSL);
36835         }
36836
36837         (*g_maEngineObjectSL)->Realize(g_maEngineObjectSL, SL_BOOLEAN_FALSE);
36838
36839         resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_ENGINE, &g_maEngineSL);
36840         if (resultSL != SL_RESULT_SUCCESS) {
36841             (*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL);
36842             g_maOpenSLInitCounter -= 1;
36843             return ma_result_from_OpenSL(resultSL);
36844         }
36845     }
36846
36847     return MA_SUCCESS;
36848 }
36849
36850 static ma_result ma_context_init__opensl(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
36851 {
36852     ma_result result;
36853
36854 #if !defined(MA_NO_RUNTIME_LINKING)
36855     size_t i;
36856     const char* libOpenSLESNames[] = {
36857         "libOpenSLES.so"
36858     };
36859 #endif
36860
36861     MA_ASSERT(pContext != NULL);
36862
36863     (void)pConfig;
36864
36865 #if !defined(MA_NO_RUNTIME_LINKING)
36866     /*
36867     Dynamically link against libOpenSLES.so. I have now had multiple reports that SL_IID_ANDROIDSIMPLEBUFFERQUEUE cannot be found. One
36868     report was happening at compile time and another at runtime. To try working around this, I'm going to link to libOpenSLES at runtime
36869     and extract the symbols rather than reference them directly. This should, hopefully, fix these issues as the compiler won't see any
36870     references to the symbols and will hopefully skip the checks.
36871     */
36872     for (i = 0; i < ma_countof(libOpenSLESNames); i += 1) {
36873         pContext->opensl.libOpenSLES = ma_dlopen(pContext, libOpenSLESNames[i]);
36874         if (pContext->opensl.libOpenSLES != NULL) {
36875             break;
36876         }
36877     }
36878
36879     if (pContext->opensl.libOpenSLES == NULL) {
36880         ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Could not find libOpenSLES.so");
36881         return MA_NO_BACKEND;
36882     }
36883
36884     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ENGINE", &pContext->opensl.SL_IID_ENGINE);
36885     if (result != MA_SUCCESS) {
36886         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
36887         return result;
36888     }
36889
36890     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_AUDIOIODEVICECAPABILITIES", &pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES);
36891     if (result != MA_SUCCESS) {
36892         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
36893         return result;
36894     }
36895
36896     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ANDROIDSIMPLEBUFFERQUEUE", &pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE);
36897     if (result != MA_SUCCESS) {
36898         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
36899         return result;
36900     }
36901
36902     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_RECORD", &pContext->opensl.SL_IID_RECORD);
36903     if (result != MA_SUCCESS) {
36904         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
36905         return result;
36906     }
36907
36908     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_PLAY", &pContext->opensl.SL_IID_PLAY);
36909     if (result != MA_SUCCESS) {
36910         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
36911         return result;
36912     }
36913
36914     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_OUTPUTMIX", &pContext->opensl.SL_IID_OUTPUTMIX);
36915     if (result != MA_SUCCESS) {
36916         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
36917         return result;
36918     }
36919
36920     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ANDROIDCONFIGURATION", &pContext->opensl.SL_IID_ANDROIDCONFIGURATION);
36921     if (result != MA_SUCCESS) {
36922         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
36923         return result;
36924     }
36925
36926     pContext->opensl.slCreateEngine = (ma_proc)ma_dlsym(pContext, pContext->opensl.libOpenSLES, "slCreateEngine");
36927     if (pContext->opensl.slCreateEngine == NULL) {
36928         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
36929         ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Cannot find symbol slCreateEngine.");
36930         return MA_NO_BACKEND;
36931     }
36932 #else
36933     pContext->opensl.SL_IID_ENGINE                    = (ma_handle)SL_IID_ENGINE;
36934     pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES = (ma_handle)SL_IID_AUDIOIODEVICECAPABILITIES;
36935     pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE  = (ma_handle)SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
36936     pContext->opensl.SL_IID_RECORD                    = (ma_handle)SL_IID_RECORD;
36937     pContext->opensl.SL_IID_PLAY                      = (ma_handle)SL_IID_PLAY;
36938     pContext->opensl.SL_IID_OUTPUTMIX                 = (ma_handle)SL_IID_OUTPUTMIX;
36939     pContext->opensl.SL_IID_ANDROIDCONFIGURATION      = (ma_handle)SL_IID_ANDROIDCONFIGURATION;
36940     pContext->opensl.slCreateEngine                   = (ma_proc)slCreateEngine;
36941 #endif
36942
36943
36944     /* Initialize global data first if applicable. */
36945     ma_spinlock_lock(&g_maOpenSLSpinlock);
36946     {
36947         result = ma_context_init_engine_nolock__opensl(pContext);
36948     }
36949     ma_spinlock_unlock(&g_maOpenSLSpinlock);
36950
36951     if (result != MA_SUCCESS) {
36952         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
36953         ma_log_post(ma_context_get_log(pContext), MA_LOG_LEVEL_INFO, "[OpenSL] Failed to initialize OpenSL engine.");
36954         return result;
36955     }
36956
36957     pCallbacks->onContextInit             = ma_context_init__opensl;
36958     pCallbacks->onContextUninit           = ma_context_uninit__opensl;
36959     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__opensl;
36960     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__opensl;
36961     pCallbacks->onDeviceInit              = ma_device_init__opensl;
36962     pCallbacks->onDeviceUninit            = ma_device_uninit__opensl;
36963     pCallbacks->onDeviceStart             = ma_device_start__opensl;
36964     pCallbacks->onDeviceStop              = ma_device_stop__opensl;
36965     pCallbacks->onDeviceRead              = NULL;   /* Not needed because OpenSL|ES is asynchronous. */
36966     pCallbacks->onDeviceWrite             = NULL;   /* Not needed because OpenSL|ES is asynchronous. */
36967     pCallbacks->onDeviceDataLoop          = NULL;   /* Not needed because OpenSL|ES is asynchronous. */
36968
36969     return MA_SUCCESS;
36970 }
36971 #endif  /* OpenSL|ES */
36972
36973
36974 /******************************************************************************
36975
36976 Web Audio Backend
36977
36978 ******************************************************************************/
36979 #ifdef MA_HAS_WEBAUDIO
36980 #include <emscripten/emscripten.h>
36981
36982 static ma_bool32 ma_is_capture_supported__webaudio()
36983 {
36984     return EM_ASM_INT({
36985         return (navigator.mediaDevices !== undefined && navigator.mediaDevices.getUserMedia !== undefined);
36986     }, 0) != 0; /* Must pass in a dummy argument for C99 compatibility. */
36987 }
36988
36989 #ifdef __cplusplus
36990 extern "C" {
36991 #endif
36992 void EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_capture__webaudio(ma_device* pDevice, int frameCount, float* pFrames)
36993 {
36994     ma_device_handle_backend_data_callback(pDevice, NULL, pFrames, (ma_uint32)frameCount);
36995 }
36996
36997 void EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_playback__webaudio(ma_device* pDevice, int frameCount, float* pFrames)
36998 {
36999     ma_device_handle_backend_data_callback(pDevice, pFrames, NULL, (ma_uint32)frameCount);
37000 }
37001 #ifdef __cplusplus
37002 }
37003 #endif
37004
37005 static ma_result ma_context_enumerate_devices__webaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
37006 {
37007     ma_bool32 cbResult = MA_TRUE;
37008
37009     MA_ASSERT(pContext != NULL);
37010     MA_ASSERT(callback != NULL);
37011
37012     /* Only supporting default devices for now. */
37013
37014     /* Playback. */
37015     if (cbResult) {
37016         ma_device_info deviceInfo;
37017         MA_ZERO_OBJECT(&deviceInfo);
37018         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
37019         deviceInfo.isDefault = MA_TRUE;    /* Only supporting default devices. */
37020         cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
37021     }
37022
37023     /* Capture. */
37024     if (cbResult) {
37025         if (ma_is_capture_supported__webaudio()) {
37026             ma_device_info deviceInfo;
37027             MA_ZERO_OBJECT(&deviceInfo);
37028             ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
37029             deviceInfo.isDefault = MA_TRUE;    /* Only supporting default devices. */
37030             cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
37031         }
37032     }
37033
37034     return MA_SUCCESS;
37035 }
37036
37037 static ma_result ma_context_get_device_info__webaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
37038 {
37039     MA_ASSERT(pContext != NULL);
37040
37041     if (deviceType == ma_device_type_capture && !ma_is_capture_supported__webaudio()) {
37042         return MA_NO_DEVICE;
37043     }
37044
37045     MA_ZERO_MEMORY(pDeviceInfo->id.webaudio, sizeof(pDeviceInfo->id.webaudio));
37046
37047     /* Only supporting default devices for now. */
37048     (void)pDeviceID;
37049     if (deviceType == ma_device_type_playback) {
37050         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
37051     } else {
37052         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
37053     }
37054
37055     /* Only supporting default devices. */
37056     pDeviceInfo->isDefault = MA_TRUE;
37057
37058     /* Web Audio can support any number of channels and sample rates. It only supports f32 formats, however. */
37059     pDeviceInfo->nativeDataFormats[0].flags      = 0;
37060     pDeviceInfo->nativeDataFormats[0].format     = ma_format_unknown;
37061     pDeviceInfo->nativeDataFormats[0].channels   = 0; /* All channels are supported. */
37062     pDeviceInfo->nativeDataFormats[0].sampleRate = EM_ASM_INT({
37063         try {
37064             var temp = new (window.AudioContext || window.webkitAudioContext)();
37065             var sampleRate = temp.sampleRate;
37066             temp.close();
37067             return sampleRate;
37068         } catch(e) {
37069             return 0;
37070         }
37071     }, 0);  /* Must pass in a dummy argument for C99 compatibility. */
37072
37073     if (pDeviceInfo->nativeDataFormats[0].sampleRate == 0) {
37074         return MA_NO_DEVICE;
37075     }
37076
37077     pDeviceInfo->nativeDataFormatCount = 1;
37078
37079     return MA_SUCCESS;
37080 }
37081
37082
37083 static void ma_device_uninit_by_index__webaudio(ma_device* pDevice, ma_device_type deviceType, int deviceIndex)
37084 {
37085     MA_ASSERT(pDevice != NULL);
37086
37087     EM_ASM({
37088         var device = miniaudio.get_device_by_index($0);
37089
37090         /* Make sure all nodes are disconnected and marked for collection. */
37091         if (device.scriptNode !== undefined) {
37092             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... */
37093             device.scriptNode.disconnect();
37094             device.scriptNode = undefined;
37095         }
37096         if (device.streamNode !== undefined) {
37097             device.streamNode.disconnect();
37098             device.streamNode = undefined;
37099         }
37100
37101         /*
37102         Stop the device. I think there is a chance the callback could get fired after calling this, hence why we want
37103         to clear the callback before closing.
37104         */
37105         device.webaudio.close();
37106         device.webaudio = undefined;
37107
37108         /* Can't forget to free the intermediary buffer. This is the buffer that's shared between JavaScript and C. */
37109         if (device.intermediaryBuffer !== undefined) {
37110             Module._free(device.intermediaryBuffer);
37111             device.intermediaryBuffer = undefined;
37112             device.intermediaryBufferView = undefined;
37113             device.intermediaryBufferSizeInBytes = undefined;
37114         }
37115
37116         /* Make sure the device is untracked so the slot can be reused later. */
37117         miniaudio.untrack_device_by_index($0);
37118     }, deviceIndex, deviceType);
37119 }
37120
37121 static ma_result ma_device_uninit__webaudio(ma_device* pDevice)
37122 {
37123     MA_ASSERT(pDevice != NULL);
37124
37125     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
37126         ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture);
37127     }
37128
37129     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
37130         ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_playback, pDevice->webaudio.indexPlayback);
37131     }
37132
37133     return MA_SUCCESS;
37134 }
37135
37136 static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__webaudio(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile)
37137 {
37138     /*
37139     There have been reports of the default buffer size being too small on some browsers. There have been reports of the default buffer
37140     size being too small on some browsers. If we're using default buffer size, we'll make sure the period size is a big biffer than our
37141     standard defaults.
37142     */
37143     ma_uint32 periodSizeInFrames;
37144
37145     if (pDescriptor->periodSizeInFrames == 0) {
37146         if (pDescriptor->periodSizeInMilliseconds == 0) {
37147             if (performanceProfile == ma_performance_profile_low_latency) {
37148                 periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(33, nativeSampleRate);  /* 1 frame @ 30 FPS */
37149             } else {
37150                 periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(333, nativeSampleRate);
37151             }
37152         } else {
37153             periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptor->periodSizeInMilliseconds, nativeSampleRate);
37154         }
37155     } else {
37156         periodSizeInFrames = pDescriptor->periodSizeInFrames;
37157     }
37158
37159     /* The size of the buffer must be a power of 2 and between 256 and 16384. */
37160     if (periodSizeInFrames < 256) {
37161         periodSizeInFrames = 256;
37162     } else if (periodSizeInFrames > 16384) {
37163         periodSizeInFrames = 16384;
37164     } else {
37165         periodSizeInFrames = ma_next_power_of_2(periodSizeInFrames);
37166     }
37167
37168     return periodSizeInFrames;
37169 }
37170
37171 static ma_result ma_device_init_by_type__webaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType)
37172 {
37173     int deviceIndex;
37174     ma_uint32 channels;
37175     ma_uint32 sampleRate;
37176     ma_uint32 periodSizeInFrames;
37177
37178     MA_ASSERT(pDevice    != NULL);
37179     MA_ASSERT(pConfig    != NULL);
37180     MA_ASSERT(deviceType != ma_device_type_duplex);
37181
37182     if (deviceType == ma_device_type_capture && !ma_is_capture_supported__webaudio()) {
37183         return MA_NO_DEVICE;
37184     }
37185
37186     /* We're going to calculate some stuff in C just to simplify the JS code. */
37187     channels           = (pDescriptor->channels   > 0) ? pDescriptor->channels   : MA_DEFAULT_CHANNELS;
37188     sampleRate         = (pDescriptor->sampleRate > 0) ? pDescriptor->sampleRate : MA_DEFAULT_SAMPLE_RATE;
37189     periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__webaudio(pDescriptor, sampleRate, pConfig->performanceProfile);
37190
37191
37192     /* 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. */
37193     deviceIndex = EM_ASM_INT({
37194         var channels   = $0;
37195         var sampleRate = $1;
37196         var bufferSize = $2;    /* In PCM frames. */
37197         var isCapture  = $3;
37198         var pDevice    = $4;
37199
37200         if (typeof(window.miniaudio) === 'undefined') {
37201             return -1;  /* Context not initialized. */
37202         }
37203
37204         var device = {};
37205
37206         /* The AudioContext must be created in a suspended state. */
37207         device.webaudio = new (window.AudioContext || window.webkitAudioContext)({sampleRate:sampleRate});
37208         device.webaudio.suspend();
37209         device.state = 1; /* ma_device_state_stopped */
37210
37211         /*
37212         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
37213         JavaScript and C it needs to be allocated and freed using Module._malloc() and Module._free().
37214         */
37215         device.intermediaryBufferSizeInBytes = channels * bufferSize * 4;
37216         device.intermediaryBuffer = Module._malloc(device.intermediaryBufferSizeInBytes);
37217         device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes);
37218
37219         /*
37220         Both playback and capture devices use a ScriptProcessorNode for performing per-sample operations.
37221
37222         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
37223         that's periodically fired, just like a normal audio callback function. But apparently this design is "flawed" and is now deprecated in favour of
37224         something called AudioWorklets which _forces_ you to load a _separate_ .js file at run time... nice... Hopefully ScriptProcessorNode will continue to
37225         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
37226         implementation. I'll be avoiding that insane AudioWorklet API like the plague...
37227
37228         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
37229         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
37230         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
37231         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
37232         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
37233         this for now. If anyone knows how I could get raw PCM data using the MediaRecorder API please let me know!
37234         */
37235         device.scriptNode = device.webaudio.createScriptProcessor(bufferSize, (isCapture) ? channels : 0, (isCapture) ? 0 : channels);
37236
37237         if (isCapture) {
37238             device.scriptNode.onaudioprocess = function(e) {
37239                 if (device.intermediaryBuffer === undefined) {
37240                     return; /* This means the device has been uninitialized. */
37241                 }
37242
37243                 if (device.intermediaryBufferView.length == 0) {
37244                     /* Recreate intermediaryBufferView when losing reference to the underlying buffer, probably due to emscripten resizing heap. */
37245                     device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes);
37246                 }
37247
37248                 /* Make sure silence it output to the AudioContext destination. Not doing this will cause sound to come out of the speakers! */
37249                 for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) {
37250                     e.outputBuffer.getChannelData(iChannel).fill(0.0);
37251                 }
37252
37253                 /* There are some situations where we may want to send silence to the client. */
37254                 var sendSilence = false;
37255                 if (device.streamNode === undefined) {
37256                     sendSilence = true;
37257                 }
37258
37259                 /* Sanity check. This will never happen, right? */
37260                 if (e.inputBuffer.numberOfChannels != channels) {
37261                     console.log("Capture: Channel count mismatch. " + e.inputBufer.numberOfChannels + " != " + channels + ". Sending silence.");
37262                     sendSilence = true;
37263                 }
37264
37265                 /* This looped design guards against the situation where e.inputBuffer is a different size to the original buffer size. Should never happen in practice. */
37266                 var totalFramesProcessed = 0;
37267                 while (totalFramesProcessed < e.inputBuffer.length) {
37268                     var framesRemaining = e.inputBuffer.length - totalFramesProcessed;
37269                     var framesToProcess = framesRemaining;
37270                     if (framesToProcess > (device.intermediaryBufferSizeInBytes/channels/4)) {
37271                         framesToProcess = (device.intermediaryBufferSizeInBytes/channels/4);
37272                     }
37273
37274                     /* 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. */
37275                     if (sendSilence) {
37276                         device.intermediaryBufferView.fill(0.0);
37277                     } else {
37278                         for (var iFrame = 0; iFrame < framesToProcess; ++iFrame) {
37279                             for (var iChannel = 0; iChannel < e.inputBuffer.numberOfChannels; ++iChannel) {
37280                                 device.intermediaryBufferView[iFrame*channels + iChannel] = e.inputBuffer.getChannelData(iChannel)[totalFramesProcessed + iFrame];
37281                             }
37282                         }
37283                     }
37284
37285                     /* Send data to the client from our intermediary buffer. */
37286                     ccall("ma_device_process_pcm_frames_capture__webaudio", "undefined", ["number", "number", "number"], [pDevice, framesToProcess, device.intermediaryBuffer]);
37287
37288                     totalFramesProcessed += framesToProcess;
37289                 }
37290             };
37291
37292             navigator.mediaDevices.getUserMedia({audio:true, video:false})
37293                 .then(function(stream) {
37294                     device.streamNode = device.webaudio.createMediaStreamSource(stream);
37295                     device.streamNode.connect(device.scriptNode);
37296                     device.scriptNode.connect(device.webaudio.destination);
37297                 })
37298                 .catch(function(error) {
37299                     /* I think this should output silence... */
37300                     device.scriptNode.connect(device.webaudio.destination);
37301                 });
37302         } else {
37303             device.scriptNode.onaudioprocess = function(e) {
37304                 if (device.intermediaryBuffer === undefined) {
37305                     return; /* This means the device has been uninitialized. */
37306                 }
37307
37308                 if(device.intermediaryBufferView.length == 0) {
37309                     /* Recreate intermediaryBufferView when losing reference to the underlying buffer, probably due to emscripten resizing heap. */
37310                     device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes);
37311                 }
37312
37313                 var outputSilence = false;
37314
37315                 /* Sanity check. This will never happen, right? */
37316                 if (e.outputBuffer.numberOfChannels != channels) {
37317                     console.log("Playback: Channel count mismatch. " + e.outputBufer.numberOfChannels + " != " + channels + ". Outputting silence.");
37318                     outputSilence = true;
37319                     return;
37320                 }
37321
37322                 /* This looped design guards against the situation where e.outputBuffer is a different size to the original buffer size. Should never happen in practice. */
37323                 var totalFramesProcessed = 0;
37324                 while (totalFramesProcessed < e.outputBuffer.length) {
37325                     var framesRemaining = e.outputBuffer.length - totalFramesProcessed;
37326                     var framesToProcess = framesRemaining;
37327                     if (framesToProcess > (device.intermediaryBufferSizeInBytes/channels/4)) {
37328                         framesToProcess = (device.intermediaryBufferSizeInBytes/channels/4);
37329                     }
37330
37331                     /* Read data from the client into our intermediary buffer. */
37332                     ccall("ma_device_process_pcm_frames_playback__webaudio", "undefined", ["number", "number", "number"], [pDevice, framesToProcess, device.intermediaryBuffer]);
37333
37334                     /* At this point we'll have data in our intermediary buffer which we now need to deinterleave and copy over to the output buffers. */
37335                     if (outputSilence) {
37336                         for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) {
37337                             e.outputBuffer.getChannelData(iChannel).fill(0.0);
37338                         }
37339                     } else {
37340                         for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) {
37341                             var outputBuffer = e.outputBuffer.getChannelData(iChannel);
37342                             var intermediaryBuffer = device.intermediaryBufferView;
37343                             for (var iFrame = 0; iFrame < framesToProcess; ++iFrame) {
37344                                 outputBuffer[totalFramesProcessed + iFrame] = intermediaryBuffer[iFrame*channels + iChannel];
37345                             }
37346                         }
37347                     }
37348
37349                     totalFramesProcessed += framesToProcess;
37350                 }
37351             };
37352
37353             device.scriptNode.connect(device.webaudio.destination);
37354         }
37355
37356         return miniaudio.track_device(device);
37357     }, channels, sampleRate, periodSizeInFrames, deviceType == ma_device_type_capture, pDevice);
37358
37359     if (deviceIndex < 0) {
37360         return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
37361     }
37362
37363     if (deviceType == ma_device_type_capture) {
37364         pDevice->webaudio.indexCapture  = deviceIndex;
37365     } else {
37366         pDevice->webaudio.indexPlayback = deviceIndex;
37367     }
37368
37369     pDescriptor->format             = ma_format_f32;
37370     pDescriptor->channels           = channels;
37371     ma_channel_map_init_standard(ma_standard_channel_map_webaudio, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels);
37372     pDescriptor->sampleRate         = EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex);
37373     pDescriptor->periodSizeInFrames = periodSizeInFrames;
37374     pDescriptor->periodCount        = 1;
37375
37376     return MA_SUCCESS;
37377 }
37378
37379 static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
37380 {
37381     ma_result result;
37382
37383     if (pConfig->deviceType == ma_device_type_loopback) {
37384         return MA_DEVICE_TYPE_NOT_SUPPORTED;
37385     }
37386
37387     /* No exclusive mode with Web Audio. */
37388     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
37389         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive)) {
37390         return MA_SHARE_MODE_NOT_SUPPORTED;
37391     }
37392
37393     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
37394         result = ma_device_init_by_type__webaudio(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
37395         if (result != MA_SUCCESS) {
37396             return result;
37397         }
37398     }
37399
37400     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
37401         result = ma_device_init_by_type__webaudio(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
37402         if (result != MA_SUCCESS) {
37403             if (pConfig->deviceType == ma_device_type_duplex) {
37404                 ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture);
37405             }
37406             return result;
37407         }
37408     }
37409
37410     return MA_SUCCESS;
37411 }
37412
37413 static ma_result ma_device_start__webaudio(ma_device* pDevice)
37414 {
37415     MA_ASSERT(pDevice != NULL);
37416
37417     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
37418         EM_ASM({
37419             var device = miniaudio.get_device_by_index($0);
37420             device.webaudio.resume();
37421             device.state = 2; /* ma_device_state_started */
37422         }, pDevice->webaudio.indexCapture);
37423     }
37424
37425     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
37426         EM_ASM({
37427             var device = miniaudio.get_device_by_index($0);
37428             device.webaudio.resume();
37429             device.state = 2; /* ma_device_state_started */
37430         }, pDevice->webaudio.indexPlayback);
37431     }
37432
37433     return MA_SUCCESS;
37434 }
37435
37436 static ma_result ma_device_stop__webaudio(ma_device* pDevice)
37437 {
37438     MA_ASSERT(pDevice != NULL);
37439
37440     /*
37441     From the WebAudio API documentation for AudioContext.suspend():
37442
37443         Suspends the progression of AudioContext's currentTime, allows any current context processing blocks that are already processed to be played to the
37444         destination, and then allows the system to release its claim on audio hardware.
37445
37446     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
37447     do any kind of explicit draining.
37448     */
37449
37450     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
37451         EM_ASM({
37452             var device = miniaudio.get_device_by_index($0);
37453             device.webaudio.suspend();
37454             device.state = 1; /* ma_device_state_stopped */
37455         }, pDevice->webaudio.indexCapture);
37456     }
37457
37458     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
37459         EM_ASM({
37460             var device = miniaudio.get_device_by_index($0);
37461             device.webaudio.suspend();
37462             device.state = 1; /* ma_device_state_stopped */
37463         }, pDevice->webaudio.indexPlayback);
37464     }
37465
37466     ma_device__on_notification_stopped(pDevice);
37467
37468     return MA_SUCCESS;
37469 }
37470
37471 static ma_result ma_context_uninit__webaudio(ma_context* pContext)
37472 {
37473     MA_ASSERT(pContext != NULL);
37474     MA_ASSERT(pContext->backend == ma_backend_webaudio);
37475
37476     /* Nothing needs to be done here. */
37477     (void)pContext;
37478
37479     return MA_SUCCESS;
37480 }
37481
37482 static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
37483 {
37484     int resultFromJS;
37485
37486     MA_ASSERT(pContext != NULL);
37487
37488     (void)pConfig; /* Unused. */
37489
37490     /* Here is where our global JavaScript object is initialized. */
37491     resultFromJS = EM_ASM_INT({
37492         if ((window.AudioContext || window.webkitAudioContext) === undefined) {
37493             return 0;   /* Web Audio not supported. */
37494         }
37495
37496         if (typeof(window.miniaudio) === 'undefined') {
37497             window.miniaudio = {};
37498             miniaudio.devices = [];   /* Device cache for mapping devices to indexes for JavaScript/C interop. */
37499
37500             miniaudio.track_device = function(device) {
37501                 /* Try inserting into a free slot first. */
37502                 for (var iDevice = 0; iDevice < miniaudio.devices.length; ++iDevice) {
37503                     if (miniaudio.devices[iDevice] == null) {
37504                         miniaudio.devices[iDevice] = device;
37505                         return iDevice;
37506                     }
37507                 }
37508
37509                 /* Getting here means there is no empty slots in the array so we just push to the end. */
37510                 miniaudio.devices.push(device);
37511                 return miniaudio.devices.length - 1;
37512             };
37513
37514             miniaudio.untrack_device_by_index = function(deviceIndex) {
37515                 /* We just set the device's slot to null. The slot will get reused in the next call to ma_track_device. */
37516                 miniaudio.devices[deviceIndex] = null;
37517
37518                 /* Trim the array if possible. */
37519                 while (miniaudio.devices.length > 0) {
37520                     if (miniaudio.devices[miniaudio.devices.length-1] == null) {
37521                         miniaudio.devices.pop();
37522                     } else {
37523                         break;
37524                     }
37525                 }
37526             };
37527
37528             miniaudio.untrack_device = function(device) {
37529                 for (var iDevice = 0; iDevice < miniaudio.devices.length; ++iDevice) {
37530                     if (miniaudio.devices[iDevice] == device) {
37531                         return miniaudio.untrack_device_by_index(iDevice);
37532                     }
37533                 }
37534             };
37535
37536             miniaudio.get_device_by_index = function(deviceIndex) {
37537                 return miniaudio.devices[deviceIndex];
37538             };
37539
37540             miniaudio.unlock_event_types = (function(){
37541                 return ['touchstart', 'touchend', 'click'];
37542             })();
37543
37544             miniaudio.unlock = function() {
37545                 for(var i = 0; i < miniaudio.devices.length; ++i) {
37546                     var device = miniaudio.devices[i];
37547                     if (device != null && device.webaudio != null && device.state === 2 /* ma_device_state_started */) {
37548                         device.webaudio.resume();
37549                     }
37550                 }
37551                 miniaudio.unlock_event_types.map(function(event_type) {
37552                     document.removeEventListener(event_type, miniaudio.unlock, true);
37553                 });
37554             };
37555
37556             miniaudio.unlock_event_types.map(function(event_type) {
37557                 document.addEventListener(event_type, miniaudio.unlock, true);
37558             });
37559         }
37560
37561         return 1;
37562     }, 0);  /* Must pass in a dummy argument for C99 compatibility. */
37563
37564     if (resultFromJS != 1) {
37565         return MA_FAILED_TO_INIT_BACKEND;
37566     }
37567
37568     pCallbacks->onContextInit             = ma_context_init__webaudio;
37569     pCallbacks->onContextUninit           = ma_context_uninit__webaudio;
37570     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__webaudio;
37571     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__webaudio;
37572     pCallbacks->onDeviceInit              = ma_device_init__webaudio;
37573     pCallbacks->onDeviceUninit            = ma_device_uninit__webaudio;
37574     pCallbacks->onDeviceStart             = ma_device_start__webaudio;
37575     pCallbacks->onDeviceStop              = ma_device_stop__webaudio;
37576     pCallbacks->onDeviceRead              = NULL;   /* Not needed because WebAudio is asynchronous. */
37577     pCallbacks->onDeviceWrite             = NULL;   /* Not needed because WebAudio is asynchronous. */
37578     pCallbacks->onDeviceDataLoop          = NULL;   /* Not needed because WebAudio is asynchronous. */
37579
37580     return MA_SUCCESS;
37581 }
37582 #endif  /* Web Audio */
37583
37584
37585
37586 static ma_bool32 ma__is_channel_map_valid(const ma_channel* pChannelMap, ma_uint32 channels)
37587 {
37588     /* A blank channel map should be allowed, in which case it should use an appropriate default which will depend on context. */
37589     if (pChannelMap != NULL && pChannelMap[0] != MA_CHANNEL_NONE) {
37590         ma_uint32 iChannel;
37591
37592         if (channels == 0 || channels > MA_MAX_CHANNELS) {
37593             return MA_FALSE;   /* Channel count out of range. */
37594         }
37595
37596         /* A channel cannot be present in the channel map more than once. */
37597         for (iChannel = 0; iChannel < channels; ++iChannel) {
37598             ma_uint32 jChannel;
37599             for (jChannel = iChannel + 1; jChannel < channels; ++jChannel) {
37600                 if (pChannelMap[iChannel] == pChannelMap[jChannel]) {
37601                     return MA_FALSE;
37602                 }
37603             }
37604         }
37605     }
37606
37607     return MA_TRUE;
37608 }
37609
37610
37611 static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType)
37612 {
37613     ma_result result;
37614
37615     MA_ASSERT(pDevice != NULL);
37616
37617     if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
37618         if (pDevice->capture.format == ma_format_unknown) {
37619             pDevice->capture.format = pDevice->capture.internalFormat;
37620         }
37621         if (pDevice->capture.channels == 0) {
37622             pDevice->capture.channels = pDevice->capture.internalChannels;
37623         }
37624         if (pDevice->capture.channelMap[0] == MA_CHANNEL_NONE) {
37625             MA_ASSERT(pDevice->capture.channels <= MA_MAX_CHANNELS);
37626             if (pDevice->capture.internalChannels == pDevice->capture.channels) {
37627                 ma_channel_map_copy(pDevice->capture.channelMap, pDevice->capture.internalChannelMap, pDevice->capture.channels);
37628             } else {
37629                 if (pDevice->capture.channelMixMode == ma_channel_mix_mode_simple) {
37630                     ma_channel_map_init_blank(pDevice->capture.channelMap, pDevice->capture.channels);
37631                 } else {
37632                     ma_channel_map_init_standard(ma_standard_channel_map_default, pDevice->capture.channelMap, ma_countof(pDevice->capture.channelMap), pDevice->capture.channels);
37633                 }
37634             }
37635         }
37636     }
37637
37638     if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
37639         if (pDevice->playback.format == ma_format_unknown) {
37640             pDevice->playback.format = pDevice->playback.internalFormat;
37641         }
37642         if (pDevice->playback.channels == 0) {
37643             pDevice->playback.channels = pDevice->playback.internalChannels;
37644         }
37645         if (pDevice->playback.channelMap[0] == MA_CHANNEL_NONE) {
37646             MA_ASSERT(pDevice->playback.channels <= MA_MAX_CHANNELS);
37647             if (pDevice->playback.internalChannels == pDevice->playback.channels) {
37648                 ma_channel_map_copy(pDevice->playback.channelMap, pDevice->playback.internalChannelMap, pDevice->playback.channels);
37649             } else {
37650                 if (pDevice->playback.channelMixMode == ma_channel_mix_mode_simple) {
37651                     ma_channel_map_init_blank(pDevice->playback.channelMap, pDevice->playback.channels);
37652                 } else {
37653                     ma_channel_map_init_standard(ma_standard_channel_map_default, pDevice->playback.channelMap, ma_countof(pDevice->playback.channelMap), pDevice->playback.channels);
37654                 }
37655             }
37656         }
37657     }
37658
37659     if (pDevice->sampleRate == 0) {
37660         if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
37661             pDevice->sampleRate = pDevice->capture.internalSampleRate;
37662         } else {
37663             pDevice->sampleRate = pDevice->playback.internalSampleRate;
37664         }
37665     }
37666
37667     /* Data converters. */
37668     if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
37669         /* Converting from internal device format to client format. */
37670         ma_data_converter_config converterConfig = ma_data_converter_config_init_default();
37671         converterConfig.formatIn                    = pDevice->capture.internalFormat;
37672         converterConfig.channelsIn                  = pDevice->capture.internalChannels;
37673         converterConfig.sampleRateIn                = pDevice->capture.internalSampleRate;
37674         converterConfig.pChannelMapIn               = pDevice->capture.internalChannelMap;
37675         converterConfig.formatOut                   = pDevice->capture.format;
37676         converterConfig.channelsOut                 = pDevice->capture.channels;
37677         converterConfig.sampleRateOut               = pDevice->sampleRate;
37678         converterConfig.pChannelMapOut              = pDevice->capture.channelMap;
37679         converterConfig.channelMixMode              = pDevice->capture.channelMixMode;
37680         converterConfig.allowDynamicSampleRate      = MA_FALSE;
37681         converterConfig.resampling.algorithm        = pDevice->resampling.algorithm;
37682         converterConfig.resampling.linear.lpfOrder  = pDevice->resampling.linear.lpfOrder;
37683         converterConfig.resampling.pBackendVTable   = pDevice->resampling.pBackendVTable;
37684         converterConfig.resampling.pBackendUserData = pDevice->resampling.pBackendUserData;
37685
37686         /* Make sure the old converter is uninitialized first. */
37687         if (ma_device_get_state(pDevice) != ma_device_state_uninitialized) {
37688             ma_data_converter_uninit(&pDevice->capture.converter, &pDevice->pContext->allocationCallbacks);
37689         }
37690
37691         result = ma_data_converter_init(&converterConfig, &pDevice->pContext->allocationCallbacks, &pDevice->capture.converter);
37692         if (result != MA_SUCCESS) {
37693             return result;
37694         }
37695     }
37696
37697     if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
37698         /* Converting from client format to device format. */
37699         ma_data_converter_config converterConfig = ma_data_converter_config_init_default();
37700         converterConfig.formatIn                    = pDevice->playback.format;
37701         converterConfig.channelsIn                  = pDevice->playback.channels;
37702         converterConfig.sampleRateIn                = pDevice->sampleRate;
37703         converterConfig.pChannelMapIn               = pDevice->playback.channelMap;
37704         converterConfig.formatOut                   = pDevice->playback.internalFormat;
37705         converterConfig.channelsOut                 = pDevice->playback.internalChannels;
37706         converterConfig.sampleRateOut               = pDevice->playback.internalSampleRate;
37707         converterConfig.pChannelMapOut              = pDevice->playback.internalChannelMap;
37708         converterConfig.channelMixMode              = pDevice->playback.channelMixMode;
37709         converterConfig.allowDynamicSampleRate      = MA_FALSE;
37710         converterConfig.resampling.algorithm        = pDevice->resampling.algorithm;
37711         converterConfig.resampling.linear.lpfOrder  = pDevice->resampling.linear.lpfOrder;
37712         converterConfig.resampling.pBackendVTable   = pDevice->resampling.pBackendVTable;
37713         converterConfig.resampling.pBackendUserData = pDevice->resampling.pBackendUserData;
37714
37715         /* Make sure the old converter is uninitialized first. */
37716         if (ma_device_get_state(pDevice) != ma_device_state_uninitialized) {
37717             ma_data_converter_uninit(&pDevice->playback.converter, &pDevice->pContext->allocationCallbacks);
37718         }
37719
37720         result = ma_data_converter_init(&converterConfig, &pDevice->pContext->allocationCallbacks, &pDevice->playback.converter);
37721         if (result != MA_SUCCESS) {
37722             return result;
37723         }
37724     }
37725
37726
37727     /*
37728     In playback mode, if the data converter does not support retrieval of the required number of
37729     input frames given a number of output frames, we need to fall back to a heap-allocated cache.
37730     */
37731     if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
37732         ma_uint64 unused;
37733
37734         pDevice->playback.inputCacheConsumed  = 0;
37735         pDevice->playback.inputCacheRemaining = 0;
37736
37737         if (deviceType == ma_device_type_duplex || ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, 1, &unused) != MA_SUCCESS) {
37738             /* We need a heap allocated cache. We want to size this based on the period size. */
37739             void* pNewInputCache;
37740             ma_uint64 newInputCacheCap;
37741             ma_uint64 newInputCacheSizeInBytes;
37742
37743             newInputCacheCap = ma_calculate_frame_count_after_resampling(pDevice->playback.internalSampleRate, pDevice->sampleRate, pDevice->playback.internalPeriodSizeInFrames);
37744
37745             newInputCacheSizeInBytes = newInputCacheCap * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
37746             if (newInputCacheSizeInBytes > MA_SIZE_MAX) {
37747                 ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks);
37748                 pDevice->playback.pInputCache   = NULL;
37749                 pDevice->playback.inputCacheCap = 0;
37750                 return MA_OUT_OF_MEMORY;    /* Allocation too big. Should never hit this, but makes the cast below safer for 32-bit builds. */
37751             }
37752
37753             pNewInputCache   = ma_realloc(pDevice->playback.pInputCache, (size_t)newInputCacheSizeInBytes, &pDevice->pContext->allocationCallbacks);
37754             if (pNewInputCache == NULL) {
37755                 ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks);
37756                 pDevice->playback.pInputCache   = NULL;
37757                 pDevice->playback.inputCacheCap = 0;
37758                 return MA_OUT_OF_MEMORY;
37759             }
37760
37761             pDevice->playback.pInputCache   = pNewInputCache;
37762             pDevice->playback.inputCacheCap = newInputCacheCap;
37763         } else {
37764             /* Heap allocation not required. Make sure we clear out the old cache just in case this function was called in response to a route change. */
37765             ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks);
37766             pDevice->playback.pInputCache   = NULL;
37767             pDevice->playback.inputCacheCap = 0;
37768         }
37769     }
37770
37771     return MA_SUCCESS;
37772 }
37773
37774
37775 static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData)
37776 {
37777     ma_device* pDevice = (ma_device*)pData;
37778     MA_ASSERT(pDevice != NULL);
37779
37780 #ifdef MA_WIN32
37781     ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE);
37782 #endif
37783
37784     /*
37785     When the device is being initialized it's initial state is set to ma_device_state_uninitialized. Before returning from
37786     ma_device_init(), the state needs to be set to something valid. In miniaudio the device's default state immediately
37787     after initialization is stopped, so therefore we need to mark the device as such. miniaudio will wait on the worker
37788     thread to signal an event to know when the worker thread is ready for action.
37789     */
37790     ma_device__set_state(pDevice, ma_device_state_stopped);
37791     ma_event_signal(&pDevice->stopEvent);
37792
37793     for (;;) {  /* <-- This loop just keeps the thread alive. The main audio loop is inside. */
37794         ma_result startResult;
37795         ma_result stopResult;   /* <-- This will store the result from onDeviceStop(). If it returns an error, we don't fire the stopped notification callback. */
37796
37797         /* We wait on an event to know when something has requested that the device be started and the main loop entered. */
37798         ma_event_wait(&pDevice->wakeupEvent);
37799
37800         /* Default result code. */
37801         pDevice->workResult = MA_SUCCESS;
37802
37803         /* If the reason for the wake up is that we are terminating, just break from the loop. */
37804         if (ma_device_get_state(pDevice) == ma_device_state_uninitialized) {
37805             break;
37806         }
37807
37808         /*
37809         Getting to this point means the device is wanting to get started. The function that has requested that the device
37810         be started will be waiting on an event (pDevice->startEvent) which means we need to make sure we signal the event
37811         in both the success and error case. It's important that the state of the device is set _before_ signaling the event.
37812         */
37813         MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_starting);
37814
37815         /* If the device has a start callback, start it now. */
37816         if (pDevice->pContext->callbacks.onDeviceStart != NULL) {
37817             startResult = pDevice->pContext->callbacks.onDeviceStart(pDevice);
37818         } else {
37819             startResult = MA_SUCCESS;
37820         }
37821
37822         if (startResult != MA_SUCCESS) {
37823             pDevice->workResult = startResult;
37824             continue;   /* Failed to start. Loop back to the start and wait for something to happen (pDevice->wakeupEvent). */
37825         }
37826
37827         /* Make sure the state is set appropriately. */
37828         ma_device__set_state(pDevice, ma_device_state_started);
37829         ma_event_signal(&pDevice->startEvent);
37830
37831         ma_device__on_notification_started(pDevice);
37832
37833         if (pDevice->pContext->callbacks.onDeviceDataLoop != NULL) {
37834             pDevice->pContext->callbacks.onDeviceDataLoop(pDevice);
37835         } else {
37836             /* The backend is not using a custom main loop implementation, so now fall back to the blocking read-write implementation. */
37837             ma_device_audio_thread__default_read_write(pDevice);
37838         }
37839
37840         /* Getting here means we have broken from the main loop which happens the application has requested that device be stopped. */
37841         if (pDevice->pContext->callbacks.onDeviceStop != NULL) {
37842             stopResult = pDevice->pContext->callbacks.onDeviceStop(pDevice);
37843         } else {
37844             stopResult = MA_SUCCESS;    /* No stop callback with the backend. Just assume successful. */
37845         }
37846
37847         /*
37848         After the device has stopped, make sure an event is posted. Don't post a stopped event if
37849         stopping failed. This can happen on some backends when the underlying stream has been
37850         stopped due to the device being physically unplugged or disabled via an OS setting.
37851         */
37852         if (stopResult == MA_SUCCESS) {
37853             ma_device__on_notification_stopped(pDevice);
37854         }
37855
37856         /* 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. */
37857         ma_device__set_state(pDevice, ma_device_state_stopped);
37858         ma_event_signal(&pDevice->stopEvent);
37859     }
37860
37861 #ifdef MA_WIN32
37862     ma_CoUninitialize(pDevice->pContext);
37863 #endif
37864
37865     return (ma_thread_result)0;
37866 }
37867
37868
37869 /* Helper for determining whether or not the given device is initialized. */
37870 static ma_bool32 ma_device__is_initialized(ma_device* pDevice)
37871 {
37872     if (pDevice == NULL) {
37873         return MA_FALSE;
37874     }
37875
37876     return ma_device_get_state(pDevice) != ma_device_state_uninitialized;
37877 }
37878
37879
37880 #ifdef MA_WIN32
37881 static ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext)
37882 {
37883     /* For some reason UWP complains when CoUninitialize() is called. I'm just not going to call it on UWP. */
37884 #ifdef MA_WIN32_DESKTOP
37885     ma_CoUninitialize(pContext);
37886     ma_dlclose(pContext, pContext->win32.hUser32DLL);
37887     ma_dlclose(pContext, pContext->win32.hOle32DLL);
37888     ma_dlclose(pContext, pContext->win32.hAdvapi32DLL);
37889 #else
37890     (void)pContext;
37891 #endif
37892
37893     return MA_SUCCESS;
37894 }
37895
37896 static ma_result ma_context_init_backend_apis__win32(ma_context* pContext)
37897 {
37898 #ifdef MA_WIN32_DESKTOP
37899     /* Ole32.dll */
37900     pContext->win32.hOle32DLL = ma_dlopen(pContext, "ole32.dll");
37901     if (pContext->win32.hOle32DLL == NULL) {
37902         return MA_FAILED_TO_INIT_BACKEND;
37903     }
37904
37905     pContext->win32.CoInitializeEx   = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoInitializeEx");
37906     pContext->win32.CoUninitialize   = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoUninitialize");
37907     pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoCreateInstance");
37908     pContext->win32.CoTaskMemFree    = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoTaskMemFree");
37909     pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "PropVariantClear");
37910     pContext->win32.StringFromGUID2  = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "StringFromGUID2");
37911
37912
37913     /* User32.dll */
37914     pContext->win32.hUser32DLL = ma_dlopen(pContext, "user32.dll");
37915     if (pContext->win32.hUser32DLL == NULL) {
37916         return MA_FAILED_TO_INIT_BACKEND;
37917     }
37918
37919     pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetForegroundWindow");
37920     pContext->win32.GetDesktopWindow    = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetDesktopWindow");
37921
37922
37923     /* Advapi32.dll */
37924     pContext->win32.hAdvapi32DLL = ma_dlopen(pContext, "advapi32.dll");
37925     if (pContext->win32.hAdvapi32DLL == NULL) {
37926         return MA_FAILED_TO_INIT_BACKEND;
37927     }
37928
37929     pContext->win32.RegOpenKeyExA    = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegOpenKeyExA");
37930     pContext->win32.RegCloseKey      = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegCloseKey");
37931     pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegQueryValueExA");
37932 #endif
37933
37934     ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE);
37935     return MA_SUCCESS;
37936 }
37937 #else
37938 static ma_result ma_context_uninit_backend_apis__nix(ma_context* pContext)
37939 {
37940 #if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
37941     ma_dlclose(pContext, pContext->posix.pthreadSO);
37942 #else
37943     (void)pContext;
37944 #endif
37945
37946     return MA_SUCCESS;
37947 }
37948
37949 static ma_result ma_context_init_backend_apis__nix(ma_context* pContext)
37950 {
37951     /* pthread */
37952 #if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
37953     const char* libpthreadFileNames[] = {
37954         "libpthread.so",
37955         "libpthread.so.0",
37956         "libpthread.dylib"
37957     };
37958     size_t i;
37959
37960     for (i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) {
37961         pContext->posix.pthreadSO = ma_dlopen(pContext, libpthreadFileNames[i]);
37962         if (pContext->posix.pthreadSO != NULL) {
37963             break;
37964         }
37965     }
37966
37967     if (pContext->posix.pthreadSO == NULL) {
37968         return MA_FAILED_TO_INIT_BACKEND;
37969     }
37970
37971     pContext->posix.pthread_create              = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_create");
37972     pContext->posix.pthread_join                = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_join");
37973     pContext->posix.pthread_mutex_init          = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_init");
37974     pContext->posix.pthread_mutex_destroy       = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_destroy");
37975     pContext->posix.pthread_mutex_lock          = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_lock");
37976     pContext->posix.pthread_mutex_unlock        = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_unlock");
37977     pContext->posix.pthread_cond_init           = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_init");
37978     pContext->posix.pthread_cond_destroy        = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_destroy");
37979     pContext->posix.pthread_cond_wait           = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_wait");
37980     pContext->posix.pthread_cond_signal         = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_signal");
37981     pContext->posix.pthread_attr_init           = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_init");
37982     pContext->posix.pthread_attr_destroy        = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_destroy");
37983     pContext->posix.pthread_attr_setschedpolicy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedpolicy");
37984     pContext->posix.pthread_attr_getschedparam  = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_getschedparam");
37985     pContext->posix.pthread_attr_setschedparam  = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedparam");
37986 #else
37987     pContext->posix.pthread_create              = (ma_proc)pthread_create;
37988     pContext->posix.pthread_join                = (ma_proc)pthread_join;
37989     pContext->posix.pthread_mutex_init          = (ma_proc)pthread_mutex_init;
37990     pContext->posix.pthread_mutex_destroy       = (ma_proc)pthread_mutex_destroy;
37991     pContext->posix.pthread_mutex_lock          = (ma_proc)pthread_mutex_lock;
37992     pContext->posix.pthread_mutex_unlock        = (ma_proc)pthread_mutex_unlock;
37993     pContext->posix.pthread_cond_init           = (ma_proc)pthread_cond_init;
37994     pContext->posix.pthread_cond_destroy        = (ma_proc)pthread_cond_destroy;
37995     pContext->posix.pthread_cond_wait           = (ma_proc)pthread_cond_wait;
37996     pContext->posix.pthread_cond_signal         = (ma_proc)pthread_cond_signal;
37997     pContext->posix.pthread_attr_init           = (ma_proc)pthread_attr_init;
37998     pContext->posix.pthread_attr_destroy        = (ma_proc)pthread_attr_destroy;
37999 #if !defined(__EMSCRIPTEN__)
38000     pContext->posix.pthread_attr_setschedpolicy = (ma_proc)pthread_attr_setschedpolicy;
38001     pContext->posix.pthread_attr_getschedparam  = (ma_proc)pthread_attr_getschedparam;
38002     pContext->posix.pthread_attr_setschedparam  = (ma_proc)pthread_attr_setschedparam;
38003 #endif
38004 #endif
38005
38006     return MA_SUCCESS;
38007 }
38008 #endif
38009
38010 static ma_result ma_context_init_backend_apis(ma_context* pContext)
38011 {
38012     ma_result result;
38013 #ifdef MA_WIN32
38014     result = ma_context_init_backend_apis__win32(pContext);
38015 #else
38016     result = ma_context_init_backend_apis__nix(pContext);
38017 #endif
38018
38019     return result;
38020 }
38021
38022 static ma_result ma_context_uninit_backend_apis(ma_context* pContext)
38023 {
38024     ma_result result;
38025 #ifdef MA_WIN32
38026     result = ma_context_uninit_backend_apis__win32(pContext);
38027 #else
38028     result = ma_context_uninit_backend_apis__nix(pContext);
38029 #endif
38030
38031     return result;
38032 }
38033
38034
38035 static ma_bool32 ma_context_is_backend_asynchronous(ma_context* pContext)
38036 {
38037     MA_ASSERT(pContext != NULL);
38038
38039     if (pContext->callbacks.onDeviceRead == NULL && pContext->callbacks.onDeviceWrite == NULL) {
38040         if (pContext->callbacks.onDeviceDataLoop == NULL) {
38041             return MA_TRUE;
38042         } else {
38043             return MA_FALSE;
38044         }
38045     } else {
38046         return MA_FALSE;
38047     }
38048 }
38049
38050
38051 MA_API ma_context_config ma_context_config_init()
38052 {
38053     ma_context_config config;
38054     MA_ZERO_OBJECT(&config);
38055
38056     return config;
38057 }
38058
38059 MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext)
38060 {
38061     ma_result result;
38062     ma_context_config defaultConfig;
38063     ma_backend defaultBackends[ma_backend_null+1];
38064     ma_uint32 iBackend;
38065     ma_backend* pBackendsToIterate;
38066     ma_uint32 backendsToIterateCount;
38067
38068     if (pContext == NULL) {
38069         return MA_INVALID_ARGS;
38070     }
38071
38072     MA_ZERO_OBJECT(pContext);
38073
38074     /* Always make sure the config is set first to ensure properties are available as soon as possible. */
38075     if (pConfig == NULL) {
38076         defaultConfig = ma_context_config_init();
38077         pConfig = &defaultConfig;
38078     }
38079
38080     /* Allocation callbacks need to come first because they'll be passed around to other areas. */
38081     result = ma_allocation_callbacks_init_copy(&pContext->allocationCallbacks, &pConfig->allocationCallbacks);
38082     if (result != MA_SUCCESS) {
38083         return result;
38084     }
38085
38086     /* Get a lot set up first so we can start logging ASAP. */
38087     if (pConfig->pLog != NULL) {
38088         pContext->pLog = pConfig->pLog;
38089     } else {
38090         result = ma_log_init(&pContext->allocationCallbacks, &pContext->log);
38091         if (result == MA_SUCCESS) {
38092             pContext->pLog = &pContext->log;
38093         } else {
38094             pContext->pLog = NULL;  /* Logging is not available. */
38095         }
38096     }
38097
38098     pContext->threadPriority  = pConfig->threadPriority;
38099     pContext->threadStackSize = pConfig->threadStackSize;
38100     pContext->pUserData       = pConfig->pUserData;
38101
38102     /* Backend APIs need to be initialized first. This is where external libraries will be loaded and linked. */
38103     result = ma_context_init_backend_apis(pContext);
38104     if (result != MA_SUCCESS) {
38105         return result;
38106     }
38107
38108     for (iBackend = 0; iBackend <= ma_backend_null; ++iBackend) {
38109         defaultBackends[iBackend] = (ma_backend)iBackend;
38110     }
38111
38112     pBackendsToIterate = (ma_backend*)backends;
38113     backendsToIterateCount = backendCount;
38114     if (pBackendsToIterate == NULL) {
38115         pBackendsToIterate = (ma_backend*)defaultBackends;
38116         backendsToIterateCount = ma_countof(defaultBackends);
38117     }
38118
38119     MA_ASSERT(pBackendsToIterate != NULL);
38120
38121     for (iBackend = 0; iBackend < backendsToIterateCount; iBackend += 1) {
38122         ma_backend backend = pBackendsToIterate[iBackend];
38123
38124         /* Make sure all callbacks are reset so we don't accidentally drag in any from previously failed initialization attempts. */
38125         MA_ZERO_OBJECT(&pContext->callbacks);
38126
38127         /* These backends are using the new callback system. */
38128         switch (backend) {
38129         #ifdef MA_HAS_WASAPI
38130             case ma_backend_wasapi:
38131             {
38132                 pContext->callbacks.onContextInit = ma_context_init__wasapi;
38133             } break;
38134         #endif
38135         #ifdef MA_HAS_DSOUND
38136             case ma_backend_dsound:
38137             {
38138                 pContext->callbacks.onContextInit = ma_context_init__dsound;
38139             } break;
38140         #endif
38141         #ifdef MA_HAS_WINMM
38142             case ma_backend_winmm:
38143             {
38144                 pContext->callbacks.onContextInit = ma_context_init__winmm;
38145             } break;
38146         #endif
38147         #ifdef MA_HAS_COREAUDIO
38148             case ma_backend_coreaudio:
38149             {
38150                 pContext->callbacks.onContextInit = ma_context_init__coreaudio;
38151             } break;
38152         #endif
38153         #ifdef MA_HAS_SNDIO
38154             case ma_backend_sndio:
38155             {
38156                 pContext->callbacks.onContextInit = ma_context_init__sndio;
38157             } break;
38158         #endif
38159         #ifdef MA_HAS_AUDIO4
38160             case ma_backend_audio4:
38161             {
38162                 pContext->callbacks.onContextInit = ma_context_init__audio4;
38163             } break;
38164         #endif
38165         #ifdef MA_HAS_OSS
38166             case ma_backend_oss:
38167             {
38168                 pContext->callbacks.onContextInit = ma_context_init__oss;
38169             } break;
38170         #endif
38171         #ifdef MA_HAS_PULSEAUDIO
38172             case ma_backend_pulseaudio:
38173             {
38174                 pContext->callbacks.onContextInit = ma_context_init__pulse;
38175             } break;
38176         #endif
38177         #ifdef MA_HAS_ALSA
38178             case ma_backend_alsa:
38179             {
38180                 pContext->callbacks.onContextInit = ma_context_init__alsa;
38181             } break;
38182         #endif
38183         #ifdef MA_HAS_JACK
38184             case ma_backend_jack:
38185             {
38186                 pContext->callbacks.onContextInit = ma_context_init__jack;
38187             } break;
38188         #endif
38189         #ifdef MA_HAS_AAUDIO
38190             case ma_backend_aaudio:
38191             {
38192                 pContext->callbacks.onContextInit = ma_context_init__aaudio;
38193             } break;
38194         #endif
38195         #ifdef MA_HAS_OPENSL
38196             case ma_backend_opensl:
38197             {
38198                 pContext->callbacks.onContextInit = ma_context_init__opensl;
38199             } break;
38200         #endif
38201         #ifdef MA_HAS_WEBAUDIO
38202             case ma_backend_webaudio:
38203             {
38204                 pContext->callbacks.onContextInit = ma_context_init__webaudio;
38205             } break;
38206         #endif
38207         #ifdef MA_HAS_CUSTOM
38208             case ma_backend_custom:
38209             {
38210                 /* Slightly different logic for custom backends. Custom backends can optionally set all of their callbacks in the config. */
38211                 pContext->callbacks = pConfig->custom;
38212             } break;
38213         #endif
38214         #ifdef MA_HAS_NULL
38215             case ma_backend_null:
38216             {
38217                 pContext->callbacks.onContextInit = ma_context_init__null;
38218             } break;
38219         #endif
38220
38221             default: break;
38222         }
38223
38224         if (pContext->callbacks.onContextInit != NULL) {
38225             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Attempting to initialize %s backend...\n", ma_get_backend_name(backend));
38226             result = pContext->callbacks.onContextInit(pContext, pConfig, &pContext->callbacks);
38227         } else {
38228             result = MA_NO_BACKEND;
38229         }
38230
38231         /* If this iteration was successful, return. */
38232         if (result == MA_SUCCESS) {
38233             result = ma_mutex_init(&pContext->deviceEnumLock);
38234             if (result != MA_SUCCESS) {
38235                 ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.\n");
38236             }
38237
38238             result = ma_mutex_init(&pContext->deviceInfoLock);
38239             if (result != MA_SUCCESS) {
38240                 ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.\n");
38241             }
38242
38243             #ifdef MA_DEBUG_OUTPUT
38244             {
38245                 ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] Endian:  %s\n", ma_is_little_endian() ? "LE"  : "BE");
38246                 ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] SSE2:    %s\n", ma_has_sse2()         ? "YES" : "NO");
38247                 ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] AVX2:    %s\n", ma_has_avx2()         ? "YES" : "NO");
38248                 ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "[miniaudio] NEON:    %s\n", ma_has_neon()         ? "YES" : "NO");
38249             }
38250             #endif
38251
38252             pContext->backend = backend;
38253             return result;
38254         } else {
38255             ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_DEBUG, "Failed to initialize %s backend.\n", ma_get_backend_name(backend));
38256         }
38257     }
38258
38259     /* If we get here it means an error occurred. */
38260     MA_ZERO_OBJECT(pContext);  /* Safety. */
38261     return MA_NO_BACKEND;
38262 }
38263
38264 MA_API ma_result ma_context_uninit(ma_context* pContext)
38265 {
38266     if (pContext == NULL) {
38267         return MA_INVALID_ARGS;
38268     }
38269
38270     if (pContext->callbacks.onContextUninit != NULL) {
38271         pContext->callbacks.onContextUninit(pContext);
38272     }
38273
38274     ma_mutex_uninit(&pContext->deviceEnumLock);
38275     ma_mutex_uninit(&pContext->deviceInfoLock);
38276     ma_free(pContext->pDeviceInfos, &pContext->allocationCallbacks);
38277     ma_context_uninit_backend_apis(pContext);
38278
38279     if (pContext->pLog == &pContext->log) {
38280         ma_log_uninit(&pContext->log);
38281     }
38282
38283     return MA_SUCCESS;
38284 }
38285
38286 MA_API size_t ma_context_sizeof()
38287 {
38288     return sizeof(ma_context);
38289 }
38290
38291
38292 MA_API ma_log* ma_context_get_log(ma_context* pContext)
38293 {
38294     if (pContext == NULL) {
38295         return NULL;
38296     }
38297
38298     return pContext->pLog;
38299 }
38300
38301
38302 MA_API ma_result ma_context_enumerate_devices(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
38303 {
38304     ma_result result;
38305
38306     if (pContext == NULL || callback == NULL) {
38307         return MA_INVALID_ARGS;
38308     }
38309
38310     if (pContext->callbacks.onContextEnumerateDevices == NULL) {
38311         return MA_INVALID_OPERATION;
38312     }
38313
38314     ma_mutex_lock(&pContext->deviceEnumLock);
38315     {
38316         result = pContext->callbacks.onContextEnumerateDevices(pContext, callback, pUserData);
38317     }
38318     ma_mutex_unlock(&pContext->deviceEnumLock);
38319
38320     return result;
38321 }
38322
38323
38324 static ma_bool32 ma_context_get_devices__enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData)
38325 {
38326     /*
38327     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
38328     it's just appended to the end. If it's a playback device it's inserted just before the first capture device.
38329     */
38330
38331     /*
38332     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
38333     simple fixed size increment for buffer expansion.
38334     */
38335     const ma_uint32 bufferExpansionCount = 2;
38336     const ma_uint32 totalDeviceInfoCount = pContext->playbackDeviceInfoCount + pContext->captureDeviceInfoCount;
38337
38338     if (totalDeviceInfoCount >= pContext->deviceInfoCapacity) {
38339         ma_uint32 newCapacity = pContext->deviceInfoCapacity + bufferExpansionCount;
38340         ma_device_info* pNewInfos = (ma_device_info*)ma_realloc(pContext->pDeviceInfos, sizeof(*pContext->pDeviceInfos)*newCapacity, &pContext->allocationCallbacks);
38341         if (pNewInfos == NULL) {
38342             return MA_FALSE;   /* Out of memory. */
38343         }
38344
38345         pContext->pDeviceInfos = pNewInfos;
38346         pContext->deviceInfoCapacity = newCapacity;
38347     }
38348
38349     if (deviceType == ma_device_type_playback) {
38350         /* Playback. Insert just before the first capture device. */
38351
38352         /* The first thing to do is move all of the capture devices down a slot. */
38353         ma_uint32 iFirstCaptureDevice = pContext->playbackDeviceInfoCount;
38354         size_t iCaptureDevice;
38355         for (iCaptureDevice = totalDeviceInfoCount; iCaptureDevice > iFirstCaptureDevice; --iCaptureDevice) {
38356             pContext->pDeviceInfos[iCaptureDevice] = pContext->pDeviceInfos[iCaptureDevice-1];
38357         }
38358
38359         /* Now just insert where the first capture device was before moving it down a slot. */
38360         pContext->pDeviceInfos[iFirstCaptureDevice] = *pInfo;
38361         pContext->playbackDeviceInfoCount += 1;
38362     } else {
38363         /* Capture. Insert at the end. */
38364         pContext->pDeviceInfos[totalDeviceInfoCount] = *pInfo;
38365         pContext->captureDeviceInfoCount += 1;
38366     }
38367
38368     (void)pUserData;
38369     return MA_TRUE;
38370 }
38371
38372 MA_API ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** ppPlaybackDeviceInfos, ma_uint32* pPlaybackDeviceCount, ma_device_info** ppCaptureDeviceInfos, ma_uint32* pCaptureDeviceCount)
38373 {
38374     ma_result result;
38375
38376     /* Safety. */
38377     if (ppPlaybackDeviceInfos != NULL) *ppPlaybackDeviceInfos = NULL;
38378     if (pPlaybackDeviceCount  != NULL) *pPlaybackDeviceCount  = 0;
38379     if (ppCaptureDeviceInfos  != NULL) *ppCaptureDeviceInfos  = NULL;
38380     if (pCaptureDeviceCount   != NULL) *pCaptureDeviceCount   = 0;
38381
38382     if (pContext == NULL) {
38383         return MA_INVALID_ARGS;
38384     }
38385
38386     if (pContext->callbacks.onContextEnumerateDevices == NULL) {
38387         return MA_INVALID_OPERATION;
38388     }
38389
38390     /* Note that we don't use ma_context_enumerate_devices() here because we want to do locking at a higher level. */
38391     ma_mutex_lock(&pContext->deviceEnumLock);
38392     {
38393         /* Reset everything first. */
38394         pContext->playbackDeviceInfoCount = 0;
38395         pContext->captureDeviceInfoCount = 0;
38396
38397         /* Now enumerate over available devices. */
38398         result = pContext->callbacks.onContextEnumerateDevices(pContext, ma_context_get_devices__enum_callback, NULL);
38399         if (result == MA_SUCCESS) {
38400             /* Playback devices. */
38401             if (ppPlaybackDeviceInfos != NULL) {
38402                 *ppPlaybackDeviceInfos = pContext->pDeviceInfos;
38403             }
38404             if (pPlaybackDeviceCount != NULL) {
38405                 *pPlaybackDeviceCount = pContext->playbackDeviceInfoCount;
38406             }
38407
38408             /* Capture devices. */
38409             if (ppCaptureDeviceInfos != NULL) {
38410                 *ppCaptureDeviceInfos = pContext->pDeviceInfos + pContext->playbackDeviceInfoCount; /* Capture devices come after playback devices. */
38411             }
38412             if (pCaptureDeviceCount != NULL) {
38413                 *pCaptureDeviceCount = pContext->captureDeviceInfoCount;
38414             }
38415         }
38416     }
38417     ma_mutex_unlock(&pContext->deviceEnumLock);
38418
38419     return result;
38420 }
38421
38422 MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
38423 {
38424     ma_result result;
38425     ma_device_info deviceInfo;
38426
38427     /* NOTE: Do not clear pDeviceInfo on entry. The reason is the pDeviceID may actually point to pDeviceInfo->id which will break things. */
38428     if (pContext == NULL || pDeviceInfo == NULL) {
38429         return MA_INVALID_ARGS;
38430     }
38431
38432     MA_ZERO_OBJECT(&deviceInfo);
38433
38434     /* Help the backend out by copying over the device ID if we have one. */
38435     if (pDeviceID != NULL) {
38436         MA_COPY_MEMORY(&deviceInfo.id, pDeviceID, sizeof(*pDeviceID));
38437     }
38438
38439     if (pContext->callbacks.onContextGetDeviceInfo == NULL) {
38440         return MA_INVALID_OPERATION;
38441     }
38442
38443     ma_mutex_lock(&pContext->deviceInfoLock);
38444     {
38445         result = pContext->callbacks.onContextGetDeviceInfo(pContext, deviceType, pDeviceID, &deviceInfo);
38446     }
38447     ma_mutex_unlock(&pContext->deviceInfoLock);
38448
38449     *pDeviceInfo = deviceInfo;
38450     return result;
38451 }
38452
38453 MA_API ma_bool32 ma_context_is_loopback_supported(ma_context* pContext)
38454 {
38455     if (pContext == NULL) {
38456         return MA_FALSE;
38457     }
38458
38459     return ma_is_loopback_supported(pContext->backend);
38460 }
38461
38462
38463 MA_API ma_device_config ma_device_config_init(ma_device_type deviceType)
38464 {
38465     ma_device_config config;
38466     MA_ZERO_OBJECT(&config);
38467     config.deviceType = deviceType;
38468     config.resampling = ma_resampler_config_init(ma_format_unknown, 0, 0, 0, ma_resample_algorithm_linear); /* Format/channels/rate don't matter here. */
38469
38470     return config;
38471 }
38472
38473 MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
38474 {
38475     ma_result result;
38476     ma_device_descriptor descriptorPlayback;
38477     ma_device_descriptor descriptorCapture;
38478
38479     /* The context can be null, in which case we self-manage it. */
38480     if (pContext == NULL) {
38481         return ma_device_init_ex(NULL, 0, NULL, pConfig, pDevice);
38482     }
38483
38484     if (pDevice == NULL) {
38485         return MA_INVALID_ARGS;
38486     }
38487
38488     MA_ZERO_OBJECT(pDevice);
38489
38490     if (pConfig == NULL) {
38491         return MA_INVALID_ARGS;
38492     }
38493
38494     /* Check that we have our callbacks defined. */
38495     if (pContext->callbacks.onDeviceInit == NULL) {
38496         return MA_INVALID_OPERATION;
38497     }
38498
38499     /* Basic config validation. */
38500     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
38501         if (pConfig->capture.channels > MA_MAX_CHANNELS) {
38502             return MA_INVALID_ARGS;
38503         }
38504
38505         if (!ma__is_channel_map_valid(pConfig->capture.pChannelMap, pConfig->capture.channels)) {
38506             return MA_INVALID_ARGS;
38507         }
38508     }
38509
38510     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
38511         if (pConfig->playback.channels > MA_MAX_CHANNELS) {
38512             return MA_INVALID_ARGS;
38513         }
38514
38515         if (!ma__is_channel_map_valid(pConfig->playback.pChannelMap, pConfig->playback.channels)) {
38516             return MA_INVALID_ARGS;
38517         }
38518     }
38519
38520     pDevice->pContext = pContext;
38521
38522     /* Set the user data and log callback ASAP to ensure it is available for the entire initialization process. */
38523     pDevice->pUserData      = pConfig->pUserData;
38524     pDevice->onData         = pConfig->dataCallback;
38525     pDevice->onNotification = pConfig->notificationCallback;
38526     pDevice->onStop         = pConfig->stopCallback;
38527
38528     if (pConfig->playback.pDeviceID != NULL) {
38529         MA_COPY_MEMORY(&pDevice->playback.id, pConfig->playback.pDeviceID, sizeof(pDevice->playback.id));
38530     }
38531
38532     if (pConfig->capture.pDeviceID != NULL) {
38533         MA_COPY_MEMORY(&pDevice->capture.id, pConfig->capture.pDeviceID, sizeof(pDevice->capture.id));
38534     }
38535
38536     pDevice->noPreSilencedOutputBuffer   = pConfig->noPreSilencedOutputBuffer;
38537     pDevice->noClip                      = pConfig->noClip;
38538     pDevice->masterVolumeFactor          = 1;
38539
38540     pDevice->type                        = pConfig->deviceType;
38541     pDevice->sampleRate                  = pConfig->sampleRate;
38542     pDevice->resampling.algorithm        = pConfig->resampling.algorithm;
38543     pDevice->resampling.linear.lpfOrder  = pConfig->resampling.linear.lpfOrder;
38544     pDevice->resampling.pBackendVTable   = pConfig->resampling.pBackendVTable;
38545     pDevice->resampling.pBackendUserData = pConfig->resampling.pBackendUserData;
38546
38547     pDevice->capture.shareMode           = pConfig->capture.shareMode;
38548     pDevice->capture.format              = pConfig->capture.format;
38549     pDevice->capture.channels            = pConfig->capture.channels;
38550     ma_channel_map_copy_or_default(pDevice->capture.channelMap, ma_countof(pDevice->capture.channelMap), pConfig->capture.pChannelMap, pConfig->capture.channels);
38551     pDevice->capture.channelMixMode      = pConfig->capture.channelMixMode;
38552
38553     pDevice->playback.shareMode          = pConfig->playback.shareMode;
38554     pDevice->playback.format             = pConfig->playback.format;
38555     pDevice->playback.channels           = pConfig->playback.channels;
38556     ma_channel_map_copy_or_default(pDevice->playback.channelMap, ma_countof(pDevice->playback.channelMap), pConfig->playback.pChannelMap, pConfig->playback.channels);
38557     pDevice->playback.channelMixMode     = pConfig->playback.channelMixMode;
38558
38559
38560     result = ma_mutex_init(&pDevice->startStopLock);
38561     if (result != MA_SUCCESS) {
38562         return result;
38563     }
38564
38565     /*
38566     When the device is started, the worker thread is the one that does the actual startup of the backend device. We
38567     use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device.
38568
38569     Each of these semaphores is released internally by the worker thread when the work is completed. The start
38570     semaphore is also used to wake up the worker thread.
38571     */
38572     result = ma_event_init(&pDevice->wakeupEvent);
38573     if (result != MA_SUCCESS) {
38574         ma_mutex_uninit(&pDevice->startStopLock);
38575         return result;
38576     }
38577
38578     result = ma_event_init(&pDevice->startEvent);
38579     if (result != MA_SUCCESS) {
38580         ma_event_uninit(&pDevice->wakeupEvent);
38581         ma_mutex_uninit(&pDevice->startStopLock);
38582         return result;
38583     }
38584
38585     result = ma_event_init(&pDevice->stopEvent);
38586     if (result != MA_SUCCESS) {
38587         ma_event_uninit(&pDevice->startEvent);
38588         ma_event_uninit(&pDevice->wakeupEvent);
38589         ma_mutex_uninit(&pDevice->startStopLock);
38590         return result;
38591     }
38592
38593
38594     MA_ZERO_OBJECT(&descriptorPlayback);
38595     descriptorPlayback.pDeviceID                = pConfig->playback.pDeviceID;
38596     descriptorPlayback.shareMode                = pConfig->playback.shareMode;
38597     descriptorPlayback.format                   = pConfig->playback.format;
38598     descriptorPlayback.channels                 = pConfig->playback.channels;
38599     descriptorPlayback.sampleRate               = pConfig->sampleRate;
38600     ma_channel_map_copy_or_default(descriptorPlayback.channelMap, ma_countof(descriptorPlayback.channelMap), pConfig->playback.pChannelMap, pConfig->playback.channels);
38601     descriptorPlayback.periodSizeInFrames       = pConfig->periodSizeInFrames;
38602     descriptorPlayback.periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
38603     descriptorPlayback.periodCount              = pConfig->periods;
38604
38605     if (descriptorPlayback.periodCount == 0) {
38606         descriptorPlayback.periodCount = MA_DEFAULT_PERIODS;
38607     }
38608
38609
38610     MA_ZERO_OBJECT(&descriptorCapture);
38611     descriptorCapture.pDeviceID                 = pConfig->capture.pDeviceID;
38612     descriptorCapture.shareMode                 = pConfig->capture.shareMode;
38613     descriptorCapture.format                    = pConfig->capture.format;
38614     descriptorCapture.channels                  = pConfig->capture.channels;
38615     descriptorCapture.sampleRate                = pConfig->sampleRate;
38616     ma_channel_map_copy_or_default(descriptorCapture.channelMap, ma_countof(descriptorCapture.channelMap), pConfig->capture.pChannelMap, pConfig->capture.channels);
38617     descriptorCapture.periodSizeInFrames        = pConfig->periodSizeInFrames;
38618     descriptorCapture.periodSizeInMilliseconds  = pConfig->periodSizeInMilliseconds;
38619     descriptorCapture.periodCount               = pConfig->periods;
38620
38621     if (descriptorCapture.periodCount == 0) {
38622         descriptorCapture.periodCount = MA_DEFAULT_PERIODS;
38623     }
38624
38625
38626     result = pContext->callbacks.onDeviceInit(pDevice, pConfig, &descriptorPlayback, &descriptorCapture);
38627     if (result != MA_SUCCESS) {
38628         ma_event_uninit(&pDevice->startEvent);
38629         ma_event_uninit(&pDevice->wakeupEvent);
38630         ma_mutex_uninit(&pDevice->startStopLock);
38631         return result;
38632     }
38633
38634
38635     /*
38636     On output the descriptors will contain the *actual* data format of the device. We need this to know how to convert the data between
38637     the requested format and the internal format.
38638     */
38639     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
38640         if (!ma_device_descriptor_is_valid(&descriptorCapture)) {
38641             ma_device_uninit(pDevice);
38642             return MA_INVALID_ARGS;
38643         }
38644
38645         pDevice->capture.internalFormat             = descriptorCapture.format;
38646         pDevice->capture.internalChannels           = descriptorCapture.channels;
38647         pDevice->capture.internalSampleRate         = descriptorCapture.sampleRate;
38648         ma_channel_map_copy(pDevice->capture.internalChannelMap, descriptorCapture.channelMap, descriptorCapture.channels);
38649         pDevice->capture.internalPeriodSizeInFrames = descriptorCapture.periodSizeInFrames;
38650         pDevice->capture.internalPeriods            = descriptorCapture.periodCount;
38651
38652         if (pDevice->capture.internalPeriodSizeInFrames == 0) {
38653             pDevice->capture.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(descriptorCapture.periodSizeInMilliseconds, descriptorCapture.sampleRate);
38654         }
38655     }
38656
38657     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
38658         if (!ma_device_descriptor_is_valid(&descriptorPlayback)) {
38659             ma_device_uninit(pDevice);
38660             return MA_INVALID_ARGS;
38661         }
38662
38663         pDevice->playback.internalFormat             = descriptorPlayback.format;
38664         pDevice->playback.internalChannels           = descriptorPlayback.channels;
38665         pDevice->playback.internalSampleRate         = descriptorPlayback.sampleRate;
38666         ma_channel_map_copy(pDevice->playback.internalChannelMap, descriptorPlayback.channelMap, descriptorPlayback.channels);
38667         pDevice->playback.internalPeriodSizeInFrames = descriptorPlayback.periodSizeInFrames;
38668         pDevice->playback.internalPeriods            = descriptorPlayback.periodCount;
38669
38670         if (pDevice->playback.internalPeriodSizeInFrames == 0) {
38671             pDevice->playback.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(descriptorPlayback.periodSizeInMilliseconds, descriptorPlayback.sampleRate);
38672         }
38673     }
38674
38675
38676     /*
38677     The name of the device can be retrieved from device info. This may be temporary and replaced with a `ma_device_get_info(pDevice, deviceType)` instead.
38678     For loopback devices, we need to retrieve the name of the playback device.
38679     */
38680     {
38681         ma_device_info deviceInfo;
38682
38683         if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
38684             result = ma_device_get_info(pDevice, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, &deviceInfo);
38685             if (result == MA_SUCCESS) {
38686                 ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1);
38687             } else {
38688                 /* We failed to retrieve the device info. Fall back to a default name. */
38689                 if (descriptorCapture.pDeviceID == NULL) {
38690                     ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
38691                 } else {
38692                     ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "Capture Device", (size_t)-1);
38693                 }
38694             }
38695         }
38696
38697         if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
38698             result = ma_device_get_info(pDevice, ma_device_type_playback, &deviceInfo);
38699             if (result == MA_SUCCESS) {
38700                 ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), deviceInfo.name, (size_t)-1);
38701             } else {
38702                 /* We failed to retrieve the device info. Fall back to a default name. */
38703                 if (descriptorPlayback.pDeviceID == NULL) {
38704                     ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
38705                 } else {
38706                     ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), "Playback Device", (size_t)-1);
38707                 }
38708             }
38709         }
38710     }
38711
38712
38713     ma_device__post_init_setup(pDevice, pConfig->deviceType);
38714
38715
38716     /* Some backends don't require the worker thread. */
38717     if (!ma_context_is_backend_asynchronous(pContext)) {
38718         /* The worker thread. */
38719         result = ma_thread_create(&pDevice->thread, pContext->threadPriority, pContext->threadStackSize, ma_worker_thread, pDevice, &pContext->allocationCallbacks);
38720         if (result != MA_SUCCESS) {
38721             ma_device_uninit(pDevice);
38722             return result;
38723         }
38724
38725         /* Wait for the worker thread to put the device into it's stopped state for real. */
38726         ma_event_wait(&pDevice->stopEvent);
38727         MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped);
38728     } else {
38729         /*
38730         If the backend is asynchronous and the device is duplex, we'll need an intermediary ring buffer. Note that this needs to be done
38731         after ma_device__post_init_setup().
38732         */
38733         if (ma_context_is_backend_asynchronous(pContext)) {
38734             if (pConfig->deviceType == ma_device_type_duplex) {
38735                 result = ma_duplex_rb_init(pDevice->capture.format, pDevice->capture.channels, pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB);
38736                 if (result != MA_SUCCESS) {
38737                     ma_device_uninit(pDevice);
38738                     return result;
38739                 }
38740             }
38741         }
38742
38743         ma_device__set_state(pDevice, ma_device_state_stopped);
38744     }
38745
38746     /* Restricting this to debug output because it's a bit spamy and only really needed for debugging. */
38747     #if defined(MA_DEBUG_OUTPUT)
38748     {
38749         ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[%s]\n", ma_get_backend_name(pDevice->pContext->backend));
38750         if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
38751             char name[MA_MAX_DEVICE_NAME_LENGTH + 1];
38752             ma_device_get_name(pDevice, ma_device_type_capture, name, sizeof(name), NULL);
38753
38754             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "  %s (%s)\n", name, "Capture");
38755             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Format:      %s -> %s\n", ma_get_format_name(pDevice->capture.internalFormat), ma_get_format_name(pDevice->capture.format));
38756             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Channels:    %d -> %d\n", pDevice->capture.internalChannels, pDevice->capture.channels);
38757             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Sample Rate: %d -> %d\n", pDevice->capture.internalSampleRate, pDevice->sampleRate);
38758             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Buffer Size: %d*%d (%d)\n", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods));
38759             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Conversion:\n");
38760             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "      Pre Format Conversion:  %s\n", pDevice->capture.converter.hasPreFormatConversion  ? "YES" : "NO");
38761             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "      Post Format Conversion: %s\n", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO");
38762             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "      Channel Routing:        %s\n", pDevice->capture.converter.hasChannelConverter     ? "YES" : "NO");
38763             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "      Resampling:             %s\n", pDevice->capture.converter.hasResampler            ? "YES" : "NO");
38764             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "      Passthrough:            %s\n", pDevice->capture.converter.isPassthrough           ? "YES" : "NO");
38765         }
38766         if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
38767             char name[MA_MAX_DEVICE_NAME_LENGTH + 1];
38768             ma_device_get_name(pDevice, ma_device_type_playback, name, sizeof(name), NULL);
38769
38770             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "  %s (%s)\n", name, "Playback");
38771             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Format:      %s -> %s\n", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat));
38772             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Channels:    %d -> %d\n", pDevice->playback.channels, pDevice->playback.internalChannels);
38773             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Sample Rate: %d -> %d\n", pDevice->sampleRate, pDevice->playback.internalSampleRate);
38774             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Buffer Size: %d*%d (%d)\n", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods));
38775             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "    Conversion:\n");
38776             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "      Pre Format Conversion:  %s\n", pDevice->playback.converter.hasPreFormatConversion  ? "YES" : "NO");
38777             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "      Post Format Conversion: %s\n", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO");
38778             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "      Channel Routing:        %s\n", pDevice->playback.converter.hasChannelConverter     ? "YES" : "NO");
38779             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "      Resampling:             %s\n", pDevice->playback.converter.hasResampler            ? "YES" : "NO");
38780             ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "      Passthrough:            %s\n", pDevice->playback.converter.isPassthrough           ? "YES" : "NO");
38781         }
38782     }
38783     #endif
38784
38785     MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped);
38786     return MA_SUCCESS;
38787 }
38788
38789 MA_API 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)
38790 {
38791     ma_result result;
38792     ma_context* pContext;
38793     ma_backend defaultBackends[ma_backend_null+1];
38794     ma_uint32 iBackend;
38795     ma_backend* pBackendsToIterate;
38796     ma_uint32 backendsToIterateCount;
38797     ma_allocation_callbacks allocationCallbacks;
38798
38799     if (pConfig == NULL) {
38800         return MA_INVALID_ARGS;
38801     }
38802
38803     if (pContextConfig != NULL) {
38804         result = ma_allocation_callbacks_init_copy(&allocationCallbacks, &pContextConfig->allocationCallbacks);
38805         if (result != MA_SUCCESS) {
38806             return result;
38807         }
38808     } else {
38809         allocationCallbacks = ma_allocation_callbacks_init_default();
38810     }
38811
38812
38813     pContext = (ma_context*)ma_malloc(sizeof(*pContext), &allocationCallbacks);
38814     if (pContext == NULL) {
38815         return MA_OUT_OF_MEMORY;
38816     }
38817
38818     for (iBackend = 0; iBackend <= ma_backend_null; ++iBackend) {
38819         defaultBackends[iBackend] = (ma_backend)iBackend;
38820     }
38821
38822     pBackendsToIterate = (ma_backend*)backends;
38823     backendsToIterateCount = backendCount;
38824     if (pBackendsToIterate == NULL) {
38825         pBackendsToIterate = (ma_backend*)defaultBackends;
38826         backendsToIterateCount = ma_countof(defaultBackends);
38827     }
38828
38829     result = MA_NO_BACKEND;
38830
38831     for (iBackend = 0; iBackend < backendsToIterateCount; ++iBackend) {
38832         result = ma_context_init(&pBackendsToIterate[iBackend], 1, pContextConfig, pContext);
38833         if (result == MA_SUCCESS) {
38834             result = ma_device_init(pContext, pConfig, pDevice);
38835             if (result == MA_SUCCESS) {
38836                 break;  /* Success. */
38837             } else {
38838                 ma_context_uninit(pContext);   /* Failure. */
38839             }
38840         }
38841     }
38842
38843     if (result != MA_SUCCESS) {
38844         ma_free(pContext, &allocationCallbacks);
38845         return result;
38846     }
38847
38848     pDevice->isOwnerOfContext = MA_TRUE;
38849     return result;
38850 }
38851
38852 MA_API void ma_device_uninit(ma_device* pDevice)
38853 {
38854     if (!ma_device__is_initialized(pDevice)) {
38855         return;
38856     }
38857
38858     /* 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. */
38859     if (ma_device_is_started(pDevice)) {
38860         ma_device_stop(pDevice);
38861     }
38862
38863     /* Putting the device into an uninitialized state will make the worker thread return. */
38864     ma_device__set_state(pDevice, ma_device_state_uninitialized);
38865
38866     /* Wake up the worker thread and wait for it to properly terminate. */
38867     if (!ma_context_is_backend_asynchronous(pDevice->pContext)) {
38868         ma_event_signal(&pDevice->wakeupEvent);
38869         ma_thread_wait(&pDevice->thread);
38870     }
38871
38872     if (pDevice->pContext->callbacks.onDeviceUninit != NULL) {
38873         pDevice->pContext->callbacks.onDeviceUninit(pDevice);
38874     }
38875
38876
38877     ma_event_uninit(&pDevice->stopEvent);
38878     ma_event_uninit(&pDevice->startEvent);
38879     ma_event_uninit(&pDevice->wakeupEvent);
38880     ma_mutex_uninit(&pDevice->startStopLock);
38881
38882     if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
38883         if (pDevice->type == ma_device_type_duplex) {
38884             ma_duplex_rb_uninit(&pDevice->duplexRB);
38885         }
38886     }
38887
38888     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
38889         ma_data_converter_uninit(&pDevice->capture.converter, &pDevice->pContext->allocationCallbacks);
38890     }
38891     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
38892         ma_data_converter_uninit(&pDevice->playback.converter, &pDevice->pContext->allocationCallbacks);
38893     }
38894
38895     if (pDevice->playback.pInputCache != NULL) {
38896         ma_free(pDevice->playback.pInputCache, &pDevice->pContext->allocationCallbacks);
38897     }
38898
38899     if (pDevice->isOwnerOfContext) {
38900         ma_allocation_callbacks allocationCallbacks = pDevice->pContext->allocationCallbacks;
38901
38902         ma_context_uninit(pDevice->pContext);
38903         ma_free(pDevice->pContext, &allocationCallbacks);
38904     }
38905
38906     MA_ZERO_OBJECT(pDevice);
38907 }
38908
38909 MA_API ma_context* ma_device_get_context(ma_device* pDevice)
38910 {
38911     if (pDevice == NULL) {
38912         return NULL;
38913     }
38914
38915     return pDevice->pContext;
38916 }
38917
38918 MA_API ma_log* ma_device_get_log(ma_device* pDevice)
38919 {
38920     return ma_context_get_log(ma_device_get_context(pDevice));
38921 }
38922
38923 MA_API ma_result ma_device_get_info(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo)
38924 {
38925     if (pDeviceInfo == NULL) {
38926         return MA_INVALID_ARGS;
38927     }
38928
38929     MA_ZERO_OBJECT(pDeviceInfo);
38930
38931     if (pDevice == NULL) {
38932         return MA_INVALID_ARGS;
38933     }
38934
38935     /* If the onDeviceGetInfo() callback is set, use that. Otherwise we'll fall back to ma_context_get_device_info(). */
38936     if (pDevice->pContext->callbacks.onDeviceGetInfo != NULL) {
38937         return pDevice->pContext->callbacks.onDeviceGetInfo(pDevice, type, pDeviceInfo);
38938     }
38939
38940     /* Getting here means onDeviceGetInfo is not implemented so we need to fall back to an alternative. */
38941     if (type == ma_device_type_playback) {
38942         return ma_context_get_device_info(pDevice->pContext, type, &pDevice->playback.id, pDeviceInfo);
38943     } else {
38944         return ma_context_get_device_info(pDevice->pContext, type, &pDevice->capture.id, pDeviceInfo);
38945     }
38946 }
38947
38948 MA_API ma_result ma_device_get_name(ma_device* pDevice, ma_device_type type, char* pName, size_t nameCap, size_t* pLengthNotIncludingNullTerminator)
38949 {
38950     ma_result result;
38951     ma_device_info deviceInfo;
38952
38953     if (pLengthNotIncludingNullTerminator != NULL) {
38954         *pLengthNotIncludingNullTerminator = 0;
38955     }
38956
38957     if (pName != NULL && nameCap > 0) {
38958         pName[0] = '\0';
38959     }
38960
38961     result = ma_device_get_info(pDevice, type, &deviceInfo);
38962     if (result != MA_SUCCESS) {
38963         return result;
38964     }
38965
38966     if (pName != NULL) {
38967         ma_strncpy_s(pName, nameCap, deviceInfo.name, (size_t)-1);
38968
38969         /*
38970         For safety, make sure the length is based on the truncated output string rather than the
38971         source. Otherwise the caller might assume the output buffer contains more content than it
38972         actually does.
38973         */
38974         if (pLengthNotIncludingNullTerminator != NULL) {
38975             *pLengthNotIncludingNullTerminator = strlen(pName);
38976         }
38977     } else {
38978         /* Name not specified. Just report the length of the source string. */
38979         if (pLengthNotIncludingNullTerminator != NULL) {
38980             *pLengthNotIncludingNullTerminator = strlen(deviceInfo.name);
38981         }
38982     }
38983
38984     return MA_SUCCESS;
38985 }
38986
38987 MA_API ma_result ma_device_start(ma_device* pDevice)
38988 {
38989     ma_result result;
38990
38991     if (pDevice == NULL) {
38992         return MA_INVALID_ARGS;
38993     }
38994
38995     if (ma_device_get_state(pDevice) == ma_device_state_uninitialized) {
38996         return MA_INVALID_OPERATION;    /* Not initialized. */
38997     }
38998
38999     if (ma_device_get_state(pDevice) == ma_device_state_started) {
39000         return MA_INVALID_OPERATION;    /* Already started. Returning an error to let the application know because it probably means they're doing something wrong. */
39001     }
39002
39003     ma_mutex_lock(&pDevice->startStopLock);
39004     {
39005         /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a stopped or paused state. */
39006         MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped);
39007
39008         ma_device__set_state(pDevice, ma_device_state_starting);
39009
39010         /* Asynchronous backends need to be handled differently. */
39011         if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
39012             if (pDevice->pContext->callbacks.onDeviceStart != NULL) {
39013                 result = pDevice->pContext->callbacks.onDeviceStart(pDevice);
39014             } else {
39015                 result = MA_INVALID_OPERATION;
39016             }
39017
39018             if (result == MA_SUCCESS) {
39019                 ma_device__set_state(pDevice, ma_device_state_started);
39020                 ma_device__on_notification_started(pDevice);
39021             }
39022         } else {
39023             /*
39024             Synchronous backends are started by signaling an event that's being waited on in the worker thread. We first wake up the
39025             thread and then wait for the start event.
39026             */
39027             ma_event_signal(&pDevice->wakeupEvent);
39028
39029             /*
39030             Wait for the worker thread to finish starting the device. Note that the worker thread will be the one who puts the device
39031             into the started state. Don't call ma_device__set_state() here.
39032             */
39033             ma_event_wait(&pDevice->startEvent);
39034             result = pDevice->workResult;
39035         }
39036
39037         /* We changed the state from stopped to started, so if we failed, make sure we put the state back to stopped. */
39038         if (result != MA_SUCCESS) {
39039             ma_device__set_state(pDevice, ma_device_state_stopped);
39040         }
39041     }
39042     ma_mutex_unlock(&pDevice->startStopLock);
39043
39044     return result;
39045 }
39046
39047 MA_API ma_result ma_device_stop(ma_device* pDevice)
39048 {
39049     ma_result result;
39050
39051     if (pDevice == NULL) {
39052         return MA_INVALID_ARGS;
39053     }
39054
39055     if (ma_device_get_state(pDevice) == ma_device_state_uninitialized) {
39056         return MA_INVALID_OPERATION;    /* Not initialized. */
39057     }
39058
39059     if (ma_device_get_state(pDevice) == ma_device_state_stopped) {
39060         return MA_INVALID_OPERATION;    /* Already stopped. Returning an error to let the application know because it probably means they're doing something wrong. */
39061     }
39062
39063     ma_mutex_lock(&pDevice->startStopLock);
39064     {
39065         /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a started or paused state. */
39066         MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_started);
39067
39068         ma_device__set_state(pDevice, ma_device_state_stopping);
39069
39070         /* Asynchronous backends need to be handled differently. */
39071         if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
39072             /* Asynchronous backends must have a stop operation. */
39073             if (pDevice->pContext->callbacks.onDeviceStop != NULL) {
39074                 result = pDevice->pContext->callbacks.onDeviceStop(pDevice);
39075             } else {
39076                 result = MA_INVALID_OPERATION;
39077             }
39078
39079             ma_device__set_state(pDevice, ma_device_state_stopped);
39080         } else {
39081             /*
39082             Synchronous backends. The stop callback is always called from the worker thread. Do not call the stop callback here. If
39083             the backend is implementing it's own audio thread loop we'll need to wake it up if required. Note that we need to make
39084             sure the state of the device is *not* playing right now, which it shouldn't be since we set it above. This is super
39085             important though, so I'm asserting it here as well for extra safety in case we accidentally change something later.
39086             */
39087             MA_ASSERT(ma_device_get_state(pDevice) != ma_device_state_started);
39088
39089             if (pDevice->pContext->callbacks.onDeviceDataLoopWakeup != NULL) {
39090                 pDevice->pContext->callbacks.onDeviceDataLoopWakeup(pDevice);
39091             }
39092
39093             /*
39094             We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be
39095             the one who puts the device into the stopped state. Don't call ma_device__set_state() here.
39096             */
39097             ma_event_wait(&pDevice->stopEvent);
39098             result = MA_SUCCESS;
39099         }
39100     }
39101     ma_mutex_unlock(&pDevice->startStopLock);
39102
39103     return result;
39104 }
39105
39106 MA_API ma_bool32 ma_device_is_started(const ma_device* pDevice)
39107 {
39108     return ma_device_get_state(pDevice) == ma_device_state_started;
39109 }
39110
39111 MA_API ma_device_state ma_device_get_state(const ma_device* pDevice)
39112 {
39113     if (pDevice == NULL) {
39114         return ma_device_state_uninitialized;
39115     }
39116
39117     return (ma_device_state)c89atomic_load_i32((ma_int32*)&pDevice->state);  /* Naughty cast to get rid of a const warning. */
39118 }
39119
39120 MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume)
39121 {
39122     if (pDevice == NULL) {
39123         return MA_INVALID_ARGS;
39124     }
39125
39126     if (volume < 0.0f) {
39127         return MA_INVALID_ARGS;
39128     }
39129
39130     c89atomic_exchange_f32(&pDevice->masterVolumeFactor, volume);
39131
39132     return MA_SUCCESS;
39133 }
39134
39135 MA_API ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume)
39136 {
39137     if (pVolume == NULL) {
39138         return MA_INVALID_ARGS;
39139     }
39140
39141     if (pDevice == NULL) {
39142         *pVolume = 0;
39143         return MA_INVALID_ARGS;
39144     }
39145
39146     *pVolume = c89atomic_load_f32(&pDevice->masterVolumeFactor);
39147
39148     return MA_SUCCESS;
39149 }
39150
39151 MA_API ma_result ma_device_set_master_volume_db(ma_device* pDevice, float gainDB)
39152 {
39153     if (gainDB > 0) {
39154         return MA_INVALID_ARGS;
39155     }
39156
39157     return ma_device_set_master_volume(pDevice, ma_volume_db_to_linear(gainDB));
39158 }
39159
39160 MA_API ma_result ma_device_get_master_volume_db(ma_device* pDevice, float* pGainDB)
39161 {
39162     float factor;
39163     ma_result result;
39164
39165     if (pGainDB == NULL) {
39166         return MA_INVALID_ARGS;
39167     }
39168
39169     result = ma_device_get_master_volume(pDevice, &factor);
39170     if (result != MA_SUCCESS) {
39171         *pGainDB = 0;
39172         return result;
39173     }
39174
39175     *pGainDB = ma_volume_linear_to_db(factor);
39176
39177     return MA_SUCCESS;
39178 }
39179
39180
39181 MA_API ma_result ma_device_handle_backend_data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
39182 {
39183     if (pDevice == NULL) {
39184         return MA_INVALID_ARGS;
39185     }
39186
39187     if (pOutput == NULL && pInput == NULL) {
39188         return MA_INVALID_ARGS;
39189     }
39190
39191     if (pDevice->type == ma_device_type_duplex) {
39192         if (pInput != NULL) {
39193             ma_device__handle_duplex_callback_capture(pDevice, frameCount, pInput, &pDevice->duplexRB.rb);
39194         }
39195
39196         if (pOutput != NULL) {
39197             ma_device__handle_duplex_callback_playback(pDevice, frameCount, pOutput, &pDevice->duplexRB.rb);
39198         }
39199     } else {
39200         if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_loopback) {
39201             if (pInput == NULL) {
39202                 return MA_INVALID_ARGS;
39203             }
39204
39205             ma_device__send_frames_to_client(pDevice, frameCount, pInput);
39206         }
39207
39208         if (pDevice->type == ma_device_type_playback) {
39209             if (pOutput == NULL) {
39210                 return MA_INVALID_ARGS;
39211             }
39212
39213             ma_device__read_frames_from_client(pDevice, frameCount, pOutput);
39214         }
39215     }
39216
39217     return MA_SUCCESS;
39218 }
39219
39220 MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile)
39221 {
39222     if (pDescriptor == NULL) {
39223         return 0;
39224     }
39225
39226     /*
39227     We must have a non-0 native sample rate, but some backends don't allow retrieval of this at the
39228     time when the size of the buffer needs to be determined. In this case we need to just take a best
39229     guess and move on. We'll try using the sample rate in pDescriptor first. If that's not set we'll
39230     just fall back to MA_DEFAULT_SAMPLE_RATE.
39231     */
39232     if (nativeSampleRate == 0) {
39233         nativeSampleRate = pDescriptor->sampleRate;
39234     }
39235     if (nativeSampleRate == 0) {
39236         nativeSampleRate = MA_DEFAULT_SAMPLE_RATE;
39237     }
39238
39239     MA_ASSERT(nativeSampleRate != 0);
39240
39241     if (pDescriptor->periodSizeInFrames == 0) {
39242         if (pDescriptor->periodSizeInMilliseconds == 0) {
39243             if (performanceProfile == ma_performance_profile_low_latency) {
39244                 return ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, nativeSampleRate);
39245             } else {
39246                 return ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, nativeSampleRate);
39247             }
39248         } else {
39249             return ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptor->periodSizeInMilliseconds, nativeSampleRate);
39250         }
39251     } else {
39252         return pDescriptor->periodSizeInFrames;
39253     }
39254 }
39255 #endif  /* MA_NO_DEVICE_IO */
39256
39257
39258 MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate)
39259 {
39260     /* Prevent a division by zero. */
39261     if (sampleRate == 0) {
39262         return 0;
39263     }
39264
39265     return bufferSizeInFrames*1000 / sampleRate;
39266 }
39267
39268 MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate)
39269 {
39270     /* Prevent a division by zero. */
39271     if (sampleRate == 0) {
39272         return 0;
39273     }
39274
39275     return bufferSizeInMilliseconds*sampleRate / 1000;
39276 }
39277
39278 MA_API void ma_copy_pcm_frames(void* dst, const void* src, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
39279 {
39280     if (dst == src) {
39281         return; /* No-op. */
39282     }
39283
39284     ma_copy_memory_64(dst, src, frameCount * ma_get_bytes_per_frame(format, channels));
39285 }
39286
39287 MA_API void ma_silence_pcm_frames(void* p, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
39288 {
39289     if (format == ma_format_u8) {
39290         ma_uint64 sampleCount = frameCount * channels;
39291         ma_uint64 iSample;
39292         for (iSample = 0; iSample < sampleCount; iSample += 1) {
39293             ((ma_uint8*)p)[iSample] = 128;
39294         }
39295     } else {
39296         ma_zero_memory_64(p, frameCount * ma_get_bytes_per_frame(format, channels));
39297     }
39298 }
39299
39300 MA_API void* ma_offset_pcm_frames_ptr(void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels)
39301 {
39302     return ma_offset_ptr(p, offsetInFrames * ma_get_bytes_per_frame(format, channels));
39303 }
39304
39305 MA_API const void* ma_offset_pcm_frames_const_ptr(const void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels)
39306 {
39307     return ma_offset_ptr(p, offsetInFrames * ma_get_bytes_per_frame(format, channels));
39308 }
39309
39310
39311 MA_API void ma_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count)
39312 {
39313     ma_uint64 iSample;
39314
39315     MA_ASSERT(pDst != NULL);
39316     MA_ASSERT(pSrc != NULL);
39317
39318     for (iSample = 0; iSample < count; iSample += 1) {
39319         pDst[iSample] = ma_clip_u8(pSrc[iSample]);
39320     }
39321 }
39322
39323 MA_API void ma_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count)
39324 {
39325     ma_uint64 iSample;
39326
39327     MA_ASSERT(pDst != NULL);
39328     MA_ASSERT(pSrc != NULL);
39329
39330     for (iSample = 0; iSample < count; iSample += 1) {
39331         pDst[iSample] = ma_clip_s16(pSrc[iSample]);
39332     }
39333 }
39334
39335 MA_API void ma_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count)
39336 {
39337     ma_uint64 iSample;
39338
39339     MA_ASSERT(pDst != NULL);
39340     MA_ASSERT(pSrc != NULL);
39341
39342     for (iSample = 0; iSample < count; iSample += 1) {
39343         ma_int64 s = ma_clip_s24(pSrc[iSample]);
39344         pDst[iSample*3 + 0] = (ma_uint8)((s & 0x000000FF) >>  0);
39345         pDst[iSample*3 + 1] = (ma_uint8)((s & 0x0000FF00) >>  8);
39346         pDst[iSample*3 + 2] = (ma_uint8)((s & 0x00FF0000) >> 16);
39347     }
39348 }
39349
39350 MA_API void ma_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count)
39351 {
39352     ma_uint64 iSample;
39353
39354     MA_ASSERT(pDst != NULL);
39355     MA_ASSERT(pSrc != NULL);
39356
39357     for (iSample = 0; iSample < count; iSample += 1) {
39358         pDst[iSample] = ma_clip_s32(pSrc[iSample]);
39359     }
39360 }
39361
39362 MA_API void ma_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count)
39363 {
39364     ma_uint64 iSample;
39365
39366     MA_ASSERT(pDst != NULL);
39367     MA_ASSERT(pSrc != NULL);
39368
39369     for (iSample = 0; iSample < count; iSample += 1) {
39370         pDst[iSample] = ma_clip_f32(pSrc[iSample]);
39371     }
39372 }
39373
39374 MA_API void ma_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
39375 {
39376     ma_uint64 sampleCount;
39377
39378     MA_ASSERT(pDst != NULL);
39379     MA_ASSERT(pSrc != NULL);
39380
39381     sampleCount = frameCount * channels;
39382
39383     switch (format) {
39384         case ma_format_u8:  ma_clip_samples_u8( (ma_uint8*)pDst, (const ma_int16*)pSrc, sampleCount); break;
39385         case ma_format_s16: ma_clip_samples_s16((ma_int16*)pDst, (const ma_int32*)pSrc, sampleCount); break;
39386         case ma_format_s24: ma_clip_samples_s24((ma_uint8*)pDst, (const ma_int64*)pSrc, sampleCount); break;
39387         case ma_format_s32: ma_clip_samples_s32((ma_int32*)pDst, (const ma_int64*)pSrc, sampleCount); break;
39388         case ma_format_f32: ma_clip_samples_f32((   float*)pDst, (const    float*)pSrc, sampleCount); break;
39389
39390         /* Do nothing if we don't know the format. We're including these here to silence a compiler warning about enums not being handled by the switch. */
39391         case ma_format_unknown:
39392         case ma_format_count:
39393             break;
39394     }
39395 }
39396
39397
39398 MA_API void ma_copy_and_apply_volume_factor_u8(ma_uint8* pSamplesOut, const ma_uint8* pSamplesIn, ma_uint64 sampleCount, float factor)
39399 {
39400     ma_uint64 iSample;
39401
39402     if (pSamplesOut == NULL || pSamplesIn == NULL) {
39403         return;
39404     }
39405
39406     for (iSample = 0; iSample < sampleCount; iSample += 1) {
39407         pSamplesOut[iSample] = (ma_uint8)(pSamplesIn[iSample] * factor);
39408     }
39409 }
39410
39411 MA_API void ma_copy_and_apply_volume_factor_s16(ma_int16* pSamplesOut, const ma_int16* pSamplesIn, ma_uint64 sampleCount, float factor)
39412 {
39413     ma_uint64 iSample;
39414
39415     if (pSamplesOut == NULL || pSamplesIn == NULL) {
39416         return;
39417     }
39418
39419     for (iSample = 0; iSample < sampleCount; iSample += 1) {
39420         pSamplesOut[iSample] = (ma_int16)(pSamplesIn[iSample] * factor);
39421     }
39422 }
39423
39424 MA_API void ma_copy_and_apply_volume_factor_s24(void* pSamplesOut, const void* pSamplesIn, ma_uint64 sampleCount, float factor)
39425 {
39426     ma_uint64 iSample;
39427     ma_uint8* pSamplesOut8;
39428     ma_uint8* pSamplesIn8;
39429
39430     if (pSamplesOut == NULL || pSamplesIn == NULL) {
39431         return;
39432     }
39433
39434     pSamplesOut8 = (ma_uint8*)pSamplesOut;
39435     pSamplesIn8  = (ma_uint8*)pSamplesIn;
39436
39437     for (iSample = 0; iSample < sampleCount; iSample += 1) {
39438         ma_int32 sampleS32;
39439
39440         sampleS32 = (ma_int32)(((ma_uint32)(pSamplesIn8[iSample*3+0]) << 8) | ((ma_uint32)(pSamplesIn8[iSample*3+1]) << 16) | ((ma_uint32)(pSamplesIn8[iSample*3+2])) << 24);
39441         sampleS32 = (ma_int32)(sampleS32 * factor);
39442
39443         pSamplesOut8[iSample*3+0] = (ma_uint8)(((ma_uint32)sampleS32 & 0x0000FF00) >>  8);
39444         pSamplesOut8[iSample*3+1] = (ma_uint8)(((ma_uint32)sampleS32 & 0x00FF0000) >> 16);
39445         pSamplesOut8[iSample*3+2] = (ma_uint8)(((ma_uint32)sampleS32 & 0xFF000000) >> 24);
39446     }
39447 }
39448
39449 MA_API void ma_copy_and_apply_volume_factor_s32(ma_int32* pSamplesOut, const ma_int32* pSamplesIn, ma_uint64 sampleCount, float factor)
39450 {
39451     ma_uint64 iSample;
39452
39453     if (pSamplesOut == NULL || pSamplesIn == NULL) {
39454         return;
39455     }
39456
39457     for (iSample = 0; iSample < sampleCount; iSample += 1) {
39458         pSamplesOut[iSample] = (ma_int32)(pSamplesIn[iSample] * factor);
39459     }
39460 }
39461
39462 MA_API void ma_copy_and_apply_volume_factor_f32(float* pSamplesOut, const float* pSamplesIn, ma_uint64 sampleCount, float factor)
39463 {
39464     ma_uint64 iSample;
39465
39466     if (pSamplesOut == NULL || pSamplesIn == NULL) {
39467         return;
39468     }
39469
39470     if (factor == 1) {
39471         if (pSamplesOut == pSamplesIn) {
39472             /* In place. No-op. */
39473         } else {
39474             /* Just a copy. */
39475             for (iSample = 0; iSample < sampleCount; iSample += 1) {
39476                 pSamplesOut[iSample] = pSamplesIn[iSample];
39477             }
39478         }
39479     } else {
39480         for (iSample = 0; iSample < sampleCount; iSample += 1) {
39481             pSamplesOut[iSample] = pSamplesIn[iSample] * factor;
39482         }
39483     }
39484 }
39485
39486 MA_API void ma_apply_volume_factor_u8(ma_uint8* pSamples, ma_uint64 sampleCount, float factor)
39487 {
39488     ma_copy_and_apply_volume_factor_u8(pSamples, pSamples, sampleCount, factor);
39489 }
39490
39491 MA_API void ma_apply_volume_factor_s16(ma_int16* pSamples, ma_uint64 sampleCount, float factor)
39492 {
39493     ma_copy_and_apply_volume_factor_s16(pSamples, pSamples, sampleCount, factor);
39494 }
39495
39496 MA_API void ma_apply_volume_factor_s24(void* pSamples, ma_uint64 sampleCount, float factor)
39497 {
39498     ma_copy_and_apply_volume_factor_s24(pSamples, pSamples, sampleCount, factor);
39499 }
39500
39501 MA_API void ma_apply_volume_factor_s32(ma_int32* pSamples, ma_uint64 sampleCount, float factor)
39502 {
39503     ma_copy_and_apply_volume_factor_s32(pSamples, pSamples, sampleCount, factor);
39504 }
39505
39506 MA_API void ma_apply_volume_factor_f32(float* pSamples, ma_uint64 sampleCount, float factor)
39507 {
39508     ma_copy_and_apply_volume_factor_f32(pSamples, pSamples, sampleCount, factor);
39509 }
39510
39511 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pFramesOut, const ma_uint8* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor)
39512 {
39513     ma_copy_and_apply_volume_factor_u8(pFramesOut, pFramesIn, frameCount*channels, factor);
39514 }
39515
39516 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pFramesOut, const ma_int16* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor)
39517 {
39518     ma_copy_and_apply_volume_factor_s16(pFramesOut, pFramesIn, frameCount*channels, factor);
39519 }
39520
39521 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor)
39522 {
39523     ma_copy_and_apply_volume_factor_s24(pFramesOut, pFramesIn, frameCount*channels, factor);
39524 }
39525
39526 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pFramesOut, const ma_int32* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor)
39527 {
39528     ma_copy_and_apply_volume_factor_s32(pFramesOut, pFramesIn, frameCount*channels, factor);
39529 }
39530
39531 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor)
39532 {
39533     ma_copy_and_apply_volume_factor_f32(pFramesOut, pFramesIn, frameCount*channels, factor);
39534 }
39535
39536 MA_API void ma_copy_and_apply_volume_factor_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor)
39537 {
39538     switch (format)
39539     {
39540     case ma_format_u8:  ma_copy_and_apply_volume_factor_pcm_frames_u8 ((ma_uint8*)pFramesOut, (const ma_uint8*)pFramesIn, frameCount, channels, factor); return;
39541     case ma_format_s16: ma_copy_and_apply_volume_factor_pcm_frames_s16((ma_int16*)pFramesOut, (const ma_int16*)pFramesIn, frameCount, channels, factor); return;
39542     case ma_format_s24: ma_copy_and_apply_volume_factor_pcm_frames_s24(           pFramesOut,                  pFramesIn, frameCount, channels, factor); return;
39543     case ma_format_s32: ma_copy_and_apply_volume_factor_pcm_frames_s32((ma_int32*)pFramesOut, (const ma_int32*)pFramesIn, frameCount, channels, factor); return;
39544     case ma_format_f32: ma_copy_and_apply_volume_factor_pcm_frames_f32(   (float*)pFramesOut,    (const float*)pFramesIn, frameCount, channels, factor); return;
39545     default: return;    /* Do nothing. */
39546     }
39547 }
39548
39549 MA_API void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor)
39550 {
39551     ma_copy_and_apply_volume_factor_pcm_frames_u8(pFrames, pFrames, frameCount, channels, factor);
39552 }
39553
39554 MA_API void ma_apply_volume_factor_pcm_frames_s16(ma_int16* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor)
39555 {
39556     ma_copy_and_apply_volume_factor_pcm_frames_s16(pFrames, pFrames, frameCount, channels, factor);
39557 }
39558
39559 MA_API void ma_apply_volume_factor_pcm_frames_s24(void* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor)
39560 {
39561     ma_copy_and_apply_volume_factor_pcm_frames_s24(pFrames, pFrames, frameCount, channels, factor);
39562 }
39563
39564 MA_API void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor)
39565 {
39566     ma_copy_and_apply_volume_factor_pcm_frames_s32(pFrames, pFrames, frameCount, channels, factor);
39567 }
39568
39569 MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor)
39570 {
39571     ma_copy_and_apply_volume_factor_pcm_frames_f32(pFrames, pFrames, frameCount, channels, factor);
39572 }
39573
39574 MA_API void ma_apply_volume_factor_pcm_frames(void* pFramesOut, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor)
39575 {
39576     ma_copy_and_apply_volume_factor_pcm_frames(pFramesOut, pFramesOut, frameCount, format, channels, factor);
39577 }
39578
39579
39580 MA_API void ma_copy_and_apply_volume_factor_per_channel_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, ma_uint32 channels, float* pChannelGains)
39581 {
39582     ma_uint64 iFrame;
39583
39584     if (channels == 2) {
39585         /* TODO: Do an optimized implementation for stereo and mono. Can do a SIMD optimized implementation as well. */
39586     }
39587
39588     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
39589         ma_uint32 iChannel;
39590         for (iChannel = 0; iChannel < channels; iChannel += 1) {
39591             pFramesOut[iFrame * channels + iChannel] = pFramesIn[iFrame * channels + iChannel] * pChannelGains[iChannel];
39592         }
39593     }
39594 }
39595
39596
39597
39598 static MA_INLINE ma_int16 ma_apply_volume_unclipped_u8(ma_int16 x, ma_int16 volume)
39599 {
39600     return (ma_int16)(((ma_int32)x * (ma_int32)volume) >> 8);
39601 }
39602
39603 static MA_INLINE ma_int32 ma_apply_volume_unclipped_s16(ma_int32 x, ma_int16 volume)
39604 {
39605     return (ma_int32)((x * volume) >> 8);
39606 }
39607
39608 static MA_INLINE ma_int64 ma_apply_volume_unclipped_s24(ma_int64 x, ma_int16 volume)
39609 {
39610     return (ma_int64)((x * volume) >> 8);
39611 }
39612
39613 static MA_INLINE ma_int64 ma_apply_volume_unclipped_s32(ma_int64 x, ma_int16 volume)
39614 {
39615     return (ma_int64)((x * volume) >> 8);
39616 }
39617
39618 static MA_INLINE float ma_apply_volume_unclipped_f32(float x, float volume)
39619 {
39620     return x * volume;
39621 }
39622
39623
39624 MA_API void ma_copy_and_apply_volume_and_clip_samples_u8(ma_uint8* pDst, const ma_int16* pSrc, ma_uint64 count, float volume)
39625 {
39626     ma_uint64 iSample;
39627     ma_int16  volumeFixed;
39628
39629     MA_ASSERT(pDst != NULL);
39630     MA_ASSERT(pSrc != NULL);
39631
39632     volumeFixed = ma_float_to_fixed_16(volume);
39633
39634     for (iSample = 0; iSample < count; iSample += 1) {
39635         pDst[iSample] = ma_clip_u8(ma_apply_volume_unclipped_u8(pSrc[iSample], volumeFixed));
39636     }
39637 }
39638
39639 MA_API void ma_copy_and_apply_volume_and_clip_samples_s16(ma_int16* pDst, const ma_int32* pSrc, ma_uint64 count, float volume)
39640 {
39641     ma_uint64 iSample;
39642     ma_int16  volumeFixed;
39643
39644     MA_ASSERT(pDst != NULL);
39645     MA_ASSERT(pSrc != NULL);
39646
39647     volumeFixed = ma_float_to_fixed_16(volume);
39648
39649     for (iSample = 0; iSample < count; iSample += 1) {
39650         pDst[iSample] = ma_clip_s16(ma_apply_volume_unclipped_s16(pSrc[iSample], volumeFixed));
39651     }
39652 }
39653
39654 MA_API void ma_copy_and_apply_volume_and_clip_samples_s24(ma_uint8* pDst, const ma_int64* pSrc, ma_uint64 count, float volume)
39655 {
39656     ma_uint64 iSample;
39657     ma_int16  volumeFixed;
39658
39659     MA_ASSERT(pDst != NULL);
39660     MA_ASSERT(pSrc != NULL);
39661
39662     volumeFixed = ma_float_to_fixed_16(volume);
39663
39664     for (iSample = 0; iSample < count; iSample += 1) {
39665         ma_int64 s = ma_clip_s24(ma_apply_volume_unclipped_s24(pSrc[iSample], volumeFixed));
39666         pDst[iSample*3 + 0] = (ma_uint8)((s & 0x000000FF) >>  0);
39667         pDst[iSample*3 + 1] = (ma_uint8)((s & 0x0000FF00) >>  8);
39668         pDst[iSample*3 + 2] = (ma_uint8)((s & 0x00FF0000) >> 16);
39669     }
39670 }
39671
39672 MA_API void ma_copy_and_apply_volume_and_clip_samples_s32(ma_int32* pDst, const ma_int64* pSrc, ma_uint64 count, float volume)
39673 {
39674     ma_uint64 iSample;
39675     ma_int16  volumeFixed;
39676
39677     MA_ASSERT(pDst != NULL);
39678     MA_ASSERT(pSrc != NULL);
39679
39680     volumeFixed = ma_float_to_fixed_16(volume);
39681
39682     for (iSample = 0; iSample < count; iSample += 1) {
39683         pDst[iSample] = ma_clip_s32(ma_apply_volume_unclipped_s32(pSrc[iSample], volumeFixed));
39684     }
39685 }
39686
39687 MA_API void ma_copy_and_apply_volume_and_clip_samples_f32(float* pDst, const float* pSrc, ma_uint64 count, float volume)
39688 {
39689     ma_uint64 iSample;
39690
39691     MA_ASSERT(pDst != NULL);
39692     MA_ASSERT(pSrc != NULL);
39693
39694     /* For the f32 case we need to make sure this supports in-place processing where the input and output buffers are the same. */
39695
39696     for (iSample = 0; iSample < count; iSample += 1) {
39697         pDst[iSample] = ma_clip_f32(ma_apply_volume_unclipped_f32(pSrc[iSample], volume));
39698     }
39699 }
39700
39701 MA_API void ma_copy_and_apply_volume_and_clip_pcm_frames(void* pDst, const void* pSrc, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float volume)
39702 {
39703     MA_ASSERT(pDst != NULL);
39704     MA_ASSERT(pSrc != NULL);
39705
39706     if (volume == 1) {
39707         ma_clip_pcm_frames(pDst, pSrc, frameCount, format, channels);   /* Optimized case for volume = 1. */
39708     } else if (volume == 0) {
39709         ma_silence_pcm_frames(pDst, frameCount, format, channels);      /* Optimized case for volume = 0. */
39710     } else {
39711         ma_uint64 sampleCount = frameCount * channels;
39712
39713         switch (format) {
39714             case ma_format_u8:  ma_copy_and_apply_volume_and_clip_samples_u8( (ma_uint8*)pDst, (const ma_int16*)pSrc, sampleCount, volume); break;
39715             case ma_format_s16: ma_copy_and_apply_volume_and_clip_samples_s16((ma_int16*)pDst, (const ma_int32*)pSrc, sampleCount, volume); break;
39716             case ma_format_s24: ma_copy_and_apply_volume_and_clip_samples_s24((ma_uint8*)pDst, (const ma_int64*)pSrc, sampleCount, volume); break;
39717             case ma_format_s32: ma_copy_and_apply_volume_and_clip_samples_s32((ma_int32*)pDst, (const ma_int64*)pSrc, sampleCount, volume); break;
39718             case ma_format_f32: ma_copy_and_apply_volume_and_clip_samples_f32((   float*)pDst, (const    float*)pSrc, sampleCount, volume); break;
39719
39720             /* Do nothing if we don't know the format. We're including these here to silence a compiler warning about enums not being handled by the switch. */
39721             case ma_format_unknown:
39722             case ma_format_count:
39723                 break;
39724         }
39725     }
39726 }
39727
39728
39729
39730 MA_API float ma_volume_linear_to_db(float factor)
39731 {
39732     return 20*ma_log10f(factor);
39733 }
39734
39735 MA_API float ma_volume_db_to_linear(float gain)
39736 {
39737     return ma_powf(10, gain/20.0f);
39738 }
39739
39740
39741
39742 MA_API ma_slot_allocator_config ma_slot_allocator_config_init(ma_uint32 capacity)
39743 {
39744     ma_slot_allocator_config config;
39745
39746     MA_ZERO_OBJECT(&config);
39747     config.capacity = capacity;
39748
39749     return config;
39750 }
39751
39752
39753 static MA_INLINE ma_uint32 ma_slot_allocator_calculate_group_capacity(ma_uint32 slotCapacity)
39754 {
39755     ma_uint32 cap = slotCapacity / 32;
39756     if ((slotCapacity % 32) != 0) {
39757         cap += 1;
39758     }
39759
39760     return cap;
39761 }
39762
39763 static MA_INLINE ma_uint32 ma_slot_allocator_group_capacity(const ma_slot_allocator* pAllocator)
39764 {
39765     return ma_slot_allocator_calculate_group_capacity(pAllocator->capacity);
39766 }
39767
39768
39769 typedef struct
39770 {
39771     size_t sizeInBytes;
39772     size_t groupsOffset;
39773     size_t slotsOffset;
39774 } ma_slot_allocator_heap_layout;
39775
39776 static ma_result ma_slot_allocator_get_heap_layout(const ma_slot_allocator_config* pConfig, ma_slot_allocator_heap_layout* pHeapLayout)
39777 {
39778     MA_ASSERT(pHeapLayout != NULL);
39779
39780     MA_ZERO_OBJECT(pHeapLayout);
39781
39782     if (pConfig == NULL) {
39783         return MA_INVALID_ARGS;
39784     }
39785
39786     if (pConfig->capacity == 0) {
39787         return MA_INVALID_ARGS;
39788     }
39789
39790     pHeapLayout->sizeInBytes = 0;
39791
39792     /* Groups. */
39793     pHeapLayout->groupsOffset = pHeapLayout->sizeInBytes;
39794     pHeapLayout->sizeInBytes += ma_align_64(ma_slot_allocator_calculate_group_capacity(pConfig->capacity) * sizeof(ma_slot_allocator_group));
39795
39796     /* Slots. */
39797     pHeapLayout->slotsOffset  = pHeapLayout->sizeInBytes;
39798     pHeapLayout->sizeInBytes += ma_align_64(pConfig->capacity * sizeof(ma_uint32));
39799
39800     return MA_SUCCESS;
39801 }
39802
39803 MA_API ma_result ma_slot_allocator_get_heap_size(const ma_slot_allocator_config* pConfig, size_t* pHeapSizeInBytes)
39804 {
39805     ma_result result;
39806     ma_slot_allocator_heap_layout layout;
39807
39808     if (pHeapSizeInBytes == NULL) {
39809         return MA_INVALID_ARGS;
39810     }
39811
39812     *pHeapSizeInBytes = 0;
39813
39814     result = ma_slot_allocator_get_heap_layout(pConfig, &layout);
39815     if (result != MA_SUCCESS) {
39816         return result;
39817     }
39818
39819     *pHeapSizeInBytes = layout.sizeInBytes;
39820
39821     return result;
39822 }
39823
39824 MA_API ma_result ma_slot_allocator_init_preallocated(const ma_slot_allocator_config* pConfig, void* pHeap, ma_slot_allocator* pAllocator)
39825 {
39826     ma_result result;
39827     ma_slot_allocator_heap_layout heapLayout;
39828
39829     if (pAllocator == NULL) {
39830         return MA_INVALID_ARGS;
39831     }
39832
39833     MA_ZERO_OBJECT(pAllocator);
39834
39835     if (pHeap == NULL) {
39836         return MA_INVALID_ARGS;
39837     }
39838
39839     result = ma_slot_allocator_get_heap_layout(pConfig, &heapLayout);
39840     if (result != MA_SUCCESS) {
39841         return result;
39842     }
39843
39844     pAllocator->_pHeap = pHeap;
39845     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
39846
39847     pAllocator->pGroups  = (ma_slot_allocator_group*)ma_offset_ptr(pHeap, heapLayout.groupsOffset);
39848     pAllocator->pSlots   = (ma_uint32*)ma_offset_ptr(pHeap, heapLayout.slotsOffset);
39849     pAllocator->capacity = pConfig->capacity;
39850
39851     return MA_SUCCESS;
39852 }
39853
39854 MA_API ma_result ma_slot_allocator_init(const ma_slot_allocator_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_slot_allocator* pAllocator)
39855 {
39856     ma_result result;
39857     size_t heapSizeInBytes;
39858     void* pHeap;
39859
39860     result = ma_slot_allocator_get_heap_size(pConfig, &heapSizeInBytes);
39861     if (result != MA_SUCCESS) {
39862         return result;  /* Failed to retrieve the size of the heap allocation. */
39863     }
39864
39865     if (heapSizeInBytes > 0) {
39866         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
39867         if (pHeap == NULL) {
39868             return MA_OUT_OF_MEMORY;
39869         }
39870     } else {
39871         pHeap = NULL;
39872     }
39873
39874     result = ma_slot_allocator_init_preallocated(pConfig, pHeap, pAllocator);
39875     if (result != MA_SUCCESS) {
39876         ma_free(pHeap, pAllocationCallbacks);
39877         return result;
39878     }
39879
39880     pAllocator->_ownsHeap = MA_TRUE;
39881     return MA_SUCCESS;
39882 }
39883
39884 MA_API void ma_slot_allocator_uninit(ma_slot_allocator* pAllocator, const ma_allocation_callbacks* pAllocationCallbacks)
39885 {
39886     if (pAllocator == NULL) {
39887         return;
39888     }
39889
39890     if (pAllocator->_ownsHeap) {
39891         ma_free(pAllocator->_pHeap, pAllocationCallbacks);
39892     }
39893 }
39894
39895 MA_API ma_result ma_slot_allocator_alloc(ma_slot_allocator* pAllocator, ma_uint64* pSlot)
39896 {
39897     ma_uint32 iAttempt;
39898     const ma_uint32 maxAttempts = 2;    /* The number of iterations to perform until returning MA_OUT_OF_MEMORY if no slots can be found. */
39899
39900     if (pAllocator == NULL || pSlot == NULL) {
39901         return MA_INVALID_ARGS;
39902     }
39903
39904     for (iAttempt = 0; iAttempt < maxAttempts; iAttempt += 1) {
39905         /* We need to acquire a suitable bitfield first. This is a bitfield that's got an available slot within it. */
39906         ma_uint32 iGroup;
39907         for (iGroup = 0; iGroup < ma_slot_allocator_group_capacity(pAllocator); iGroup += 1) {
39908             /* CAS */
39909             for (;;) {
39910                 ma_uint32 oldBitfield;
39911                 ma_uint32 newBitfield;
39912                 ma_uint32 bitOffset;
39913
39914                 oldBitfield = c89atomic_load_32(&pAllocator->pGroups[iGroup].bitfield);  /* <-- This copy must happen. The compiler must not optimize this away. */
39915
39916                 /* Fast check to see if anything is available. */
39917                 if (oldBitfield == 0xFFFFFFFF) {
39918                     break;  /* No available bits in this bitfield. */
39919                 }
39920
39921                 bitOffset = ma_ffs_32(~oldBitfield);
39922                 MA_ASSERT(bitOffset < 32);
39923
39924                 newBitfield = oldBitfield | (1 << bitOffset);
39925
39926                 if (c89atomic_compare_and_swap_32(&pAllocator->pGroups[iGroup].bitfield, oldBitfield, newBitfield) == oldBitfield) {
39927                     ma_uint32 slotIndex;
39928
39929                     /* Increment the counter as soon as possible to have other threads report out-of-memory sooner than later. */
39930                     c89atomic_fetch_add_32(&pAllocator->count, 1);
39931
39932                     /* The slot index is required for constructing the output value. */
39933                     slotIndex = (iGroup << 5) + bitOffset;  /* iGroup << 5 = iGroup * 32 */
39934                     if (slotIndex >= pAllocator->capacity) {
39935                         return MA_OUT_OF_MEMORY;
39936                     }
39937
39938                     /* Increment the reference count before constructing the output value. */
39939                     pAllocator->pSlots[slotIndex] += 1;
39940
39941                     /* Construct the output value. */
39942                     *pSlot = (((ma_uint64)pAllocator->pSlots[slotIndex] << 32) | slotIndex);
39943
39944                     return MA_SUCCESS;
39945                 }
39946             }
39947         }
39948
39949         /* We weren't able to find a slot. If it's because we've reached our capacity we need to return MA_OUT_OF_MEMORY. Otherwise we need to do another iteration and try again. */
39950         if (pAllocator->count < pAllocator->capacity) {
39951             ma_yield();
39952         } else {
39953             return MA_OUT_OF_MEMORY;
39954         }
39955     }
39956
39957     /* We couldn't find a slot within the maximum number of attempts. */
39958     return MA_OUT_OF_MEMORY;
39959 }
39960
39961 MA_API ma_result ma_slot_allocator_free(ma_slot_allocator* pAllocator, ma_uint64 slot)
39962 {
39963     ma_uint32 iGroup;
39964     ma_uint32 iBit;
39965
39966     if (pAllocator == NULL) {
39967         return MA_INVALID_ARGS;
39968     }
39969
39970     iGroup = (ma_uint32)((slot & 0xFFFFFFFF) >> 5);   /* slot / 32 */
39971     iBit   = (ma_uint32)((slot & 0xFFFFFFFF) & 31);   /* slot % 32 */
39972
39973     if (iGroup >= ma_slot_allocator_group_capacity(pAllocator)) {
39974         return MA_INVALID_ARGS;
39975     }
39976
39977     MA_ASSERT(iBit < 32);   /* This must be true due to the logic we used to actually calculate it. */
39978
39979     while (c89atomic_load_32(&pAllocator->count) > 0) {
39980         /* CAS */
39981         ma_uint32 oldBitfield;
39982         ma_uint32 newBitfield;
39983
39984         oldBitfield = c89atomic_load_32(&pAllocator->pGroups[iGroup].bitfield);  /* <-- This copy must happen. The compiler must not optimize this away. */
39985         newBitfield = oldBitfield & ~(1 << iBit);
39986
39987         /* Debugging for checking for double-frees. */
39988         #if defined(MA_DEBUG_OUTPUT)
39989         {
39990             if ((oldBitfield & (1 << iBit)) == 0) {
39991                 MA_ASSERT(MA_FALSE);    /* Double free detected.*/
39992             }
39993         }
39994         #endif
39995
39996         if (c89atomic_compare_and_swap_32(&pAllocator->pGroups[iGroup].bitfield, oldBitfield, newBitfield) == oldBitfield) {
39997             c89atomic_fetch_sub_32(&pAllocator->count, 1);
39998             return MA_SUCCESS;
39999         }
40000     }
40001
40002     /* Getting here means there are no allocations available for freeing. */
40003     return MA_INVALID_OPERATION;
40004 }
40005
40006
40007
40008 /**************************************************************************************************************************************************************
40009
40010 Format Conversion
40011
40012 **************************************************************************************************************************************************************/
40013
40014 static MA_INLINE ma_int16 ma_pcm_sample_f32_to_s16(float x)
40015 {
40016     return (ma_int16)(x * 32767.0f);
40017 }
40018
40019 static MA_INLINE ma_int16 ma_pcm_sample_u8_to_s16_no_scale(ma_uint8 x)
40020 {
40021     return (ma_int16)((ma_int16)x - 128);
40022 }
40023
40024 static MA_INLINE ma_int64 ma_pcm_sample_s24_to_s32_no_scale(const ma_uint8* x)
40025 {
40026     return (ma_int64)(((ma_uint64)x[0] << 40) | ((ma_uint64)x[1] << 48) | ((ma_uint64)x[2] << 56)) >> 40;  /* Make sure the sign bits are maintained. */
40027 }
40028
40029 static MA_INLINE void ma_pcm_sample_s32_to_s24_no_scale(ma_int64 x, ma_uint8* s24)
40030 {
40031     s24[0] = (ma_uint8)((x & 0x000000FF) >>  0);
40032     s24[1] = (ma_uint8)((x & 0x0000FF00) >>  8);
40033     s24[2] = (ma_uint8)((x & 0x00FF0000) >> 16);
40034 }
40035
40036
40037 /* u8 */
40038 MA_API void ma_pcm_u8_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40039 {
40040     (void)ditherMode;
40041     ma_copy_memory_64(dst, src, count * sizeof(ma_uint8));
40042 }
40043
40044
40045 static MA_INLINE void ma_pcm_u8_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40046 {
40047     ma_int16* dst_s16 = (ma_int16*)dst;
40048     const ma_uint8* src_u8 = (const ma_uint8*)src;
40049
40050     ma_uint64 i;
40051     for (i = 0; i < count; i += 1) {
40052         ma_int16 x = src_u8[i];
40053         x = (ma_int16)(x - 128);
40054         x = (ma_int16)(x << 8);
40055         dst_s16[i] = x;
40056     }
40057
40058     (void)ditherMode;
40059 }
40060
40061 static MA_INLINE void ma_pcm_u8_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40062 {
40063     ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode);
40064 }
40065
40066 #if defined(MA_SUPPORT_SSE2)
40067 static MA_INLINE void ma_pcm_u8_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40068 {
40069     ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
40070 }
40071 #endif
40072 #if defined(MA_SUPPORT_AVX2)
40073 static MA_INLINE void ma_pcm_u8_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40074 {
40075     ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
40076 }
40077 #endif
40078 #if defined(MA_SUPPORT_NEON)
40079 static MA_INLINE void ma_pcm_u8_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40080 {
40081     ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
40082 }
40083 #endif
40084
40085 MA_API void ma_pcm_u8_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40086 {
40087 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40088     ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode);
40089 #else
40090     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
40091         if (ma_has_avx2()) {
40092             ma_pcm_u8_to_s16__avx2(dst, src, count, ditherMode);
40093         } else
40094     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
40095         if (ma_has_sse2()) {
40096             ma_pcm_u8_to_s16__sse2(dst, src, count, ditherMode);
40097         } else
40098     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
40099         if (ma_has_neon()) {
40100             ma_pcm_u8_to_s16__neon(dst, src, count, ditherMode);
40101         } else
40102     #endif
40103         {
40104             ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
40105         }
40106 #endif
40107 }
40108
40109
40110 static MA_INLINE void ma_pcm_u8_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40111 {
40112     ma_uint8* dst_s24 = (ma_uint8*)dst;
40113     const ma_uint8* src_u8 = (const ma_uint8*)src;
40114
40115     ma_uint64 i;
40116     for (i = 0; i < count; i += 1) {
40117         ma_int16 x = src_u8[i];
40118         x = (ma_int16)(x - 128);
40119
40120         dst_s24[i*3+0] = 0;
40121         dst_s24[i*3+1] = 0;
40122         dst_s24[i*3+2] = (ma_uint8)((ma_int8)x);
40123     }
40124
40125     (void)ditherMode;
40126 }
40127
40128 static MA_INLINE void ma_pcm_u8_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40129 {
40130     ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode);
40131 }
40132
40133 #if defined(MA_SUPPORT_SSE2)
40134 static MA_INLINE void ma_pcm_u8_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40135 {
40136     ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
40137 }
40138 #endif
40139 #if defined(MA_SUPPORT_AVX2)
40140 static MA_INLINE void ma_pcm_u8_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40141 {
40142     ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
40143 }
40144 #endif
40145 #if defined(MA_SUPPORT_NEON)
40146 static MA_INLINE void ma_pcm_u8_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40147 {
40148     ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
40149 }
40150 #endif
40151
40152 MA_API void ma_pcm_u8_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40153 {
40154 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40155     ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode);
40156 #else
40157     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
40158         if (ma_has_avx2()) {
40159             ma_pcm_u8_to_s24__avx2(dst, src, count, ditherMode);
40160         } else
40161     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
40162         if (ma_has_sse2()) {
40163             ma_pcm_u8_to_s24__sse2(dst, src, count, ditherMode);
40164         } else
40165     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
40166         if (ma_has_neon()) {
40167             ma_pcm_u8_to_s24__neon(dst, src, count, ditherMode);
40168         } else
40169     #endif
40170         {
40171             ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
40172         }
40173 #endif
40174 }
40175
40176
40177 static MA_INLINE void ma_pcm_u8_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40178 {
40179     ma_int32* dst_s32 = (ma_int32*)dst;
40180     const ma_uint8* src_u8 = (const ma_uint8*)src;
40181
40182     ma_uint64 i;
40183     for (i = 0; i < count; i += 1) {
40184         ma_int32 x = src_u8[i];
40185         x = x - 128;
40186         x = x << 24;
40187         dst_s32[i] = x;
40188     }
40189
40190     (void)ditherMode;
40191 }
40192
40193 static MA_INLINE void ma_pcm_u8_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40194 {
40195     ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode);
40196 }
40197
40198 #if defined(MA_SUPPORT_SSE2)
40199 static MA_INLINE void ma_pcm_u8_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40200 {
40201     ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
40202 }
40203 #endif
40204 #if defined(MA_SUPPORT_AVX2)
40205 static MA_INLINE void ma_pcm_u8_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40206 {
40207     ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
40208 }
40209 #endif
40210 #if defined(MA_SUPPORT_NEON)
40211 static MA_INLINE void ma_pcm_u8_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40212 {
40213     ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
40214 }
40215 #endif
40216
40217 MA_API void ma_pcm_u8_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40218 {
40219 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40220     ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode);
40221 #else
40222     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
40223         if (ma_has_avx2()) {
40224             ma_pcm_u8_to_s32__avx2(dst, src, count, ditherMode);
40225         } else
40226     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
40227         if (ma_has_sse2()) {
40228             ma_pcm_u8_to_s32__sse2(dst, src, count, ditherMode);
40229         } else
40230     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
40231         if (ma_has_neon()) {
40232             ma_pcm_u8_to_s32__neon(dst, src, count, ditherMode);
40233         } else
40234     #endif
40235         {
40236             ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
40237         }
40238 #endif
40239 }
40240
40241
40242 static MA_INLINE void ma_pcm_u8_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40243 {
40244     float* dst_f32 = (float*)dst;
40245     const ma_uint8* src_u8 = (const ma_uint8*)src;
40246
40247     ma_uint64 i;
40248     for (i = 0; i < count; i += 1) {
40249         float x = (float)src_u8[i];
40250         x = x * 0.00784313725490196078f;    /* 0..255 to 0..2 */
40251         x = x - 1;                          /* 0..2 to -1..1 */
40252
40253         dst_f32[i] = x;
40254     }
40255
40256     (void)ditherMode;
40257 }
40258
40259 static MA_INLINE void ma_pcm_u8_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40260 {
40261     ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode);
40262 }
40263
40264 #if defined(MA_SUPPORT_SSE2)
40265 static MA_INLINE void ma_pcm_u8_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40266 {
40267     ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
40268 }
40269 #endif
40270 #if defined(MA_SUPPORT_AVX2)
40271 static MA_INLINE void ma_pcm_u8_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40272 {
40273     ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
40274 }
40275 #endif
40276 #if defined(MA_SUPPORT_NEON)
40277 static MA_INLINE void ma_pcm_u8_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40278 {
40279     ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
40280 }
40281 #endif
40282
40283 MA_API void ma_pcm_u8_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40284 {
40285 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40286     ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode);
40287 #else
40288     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
40289         if (ma_has_avx2()) {
40290             ma_pcm_u8_to_f32__avx2(dst, src, count, ditherMode);
40291         } else
40292     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
40293         if (ma_has_sse2()) {
40294             ma_pcm_u8_to_f32__sse2(dst, src, count, ditherMode);
40295         } else
40296     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
40297         if (ma_has_neon()) {
40298             ma_pcm_u8_to_f32__neon(dst, src, count, ditherMode);
40299         } else
40300     #endif
40301         {
40302             ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
40303         }
40304 #endif
40305 }
40306
40307
40308 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40309 static MA_INLINE void ma_pcm_interleave_u8__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
40310 {
40311     ma_uint8* dst_u8 = (ma_uint8*)dst;
40312     const ma_uint8** src_u8 = (const ma_uint8**)src;
40313
40314     ma_uint64 iFrame;
40315     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
40316         ma_uint32 iChannel;
40317         for (iChannel = 0; iChannel < channels; iChannel += 1) {
40318             dst_u8[iFrame*channels + iChannel] = src_u8[iChannel][iFrame];
40319         }
40320     }
40321 }
40322 #else
40323 static MA_INLINE void ma_pcm_interleave_u8__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
40324 {
40325     ma_uint8* dst_u8 = (ma_uint8*)dst;
40326     const ma_uint8** src_u8 = (const ma_uint8**)src;
40327
40328     if (channels == 1) {
40329         ma_copy_memory_64(dst, src[0], frameCount * sizeof(ma_uint8));
40330     } else if (channels == 2) {
40331         ma_uint64 iFrame;
40332         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
40333             dst_u8[iFrame*2 + 0] = src_u8[0][iFrame];
40334             dst_u8[iFrame*2 + 1] = src_u8[1][iFrame];
40335         }
40336     } else {
40337         ma_uint64 iFrame;
40338         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
40339             ma_uint32 iChannel;
40340             for (iChannel = 0; iChannel < channels; iChannel += 1) {
40341                 dst_u8[iFrame*channels + iChannel] = src_u8[iChannel][iFrame];
40342             }
40343         }
40344     }
40345 }
40346 #endif
40347
40348 MA_API void ma_pcm_interleave_u8(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
40349 {
40350 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40351     ma_pcm_interleave_u8__reference(dst, src, frameCount, channels);
40352 #else
40353     ma_pcm_interleave_u8__optimized(dst, src, frameCount, channels);
40354 #endif
40355 }
40356
40357
40358 static MA_INLINE void ma_pcm_deinterleave_u8__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
40359 {
40360     ma_uint8** dst_u8 = (ma_uint8**)dst;
40361     const ma_uint8* src_u8 = (const ma_uint8*)src;
40362
40363     ma_uint64 iFrame;
40364     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
40365         ma_uint32 iChannel;
40366         for (iChannel = 0; iChannel < channels; iChannel += 1) {
40367             dst_u8[iChannel][iFrame] = src_u8[iFrame*channels + iChannel];
40368         }
40369     }
40370 }
40371
40372 static MA_INLINE void ma_pcm_deinterleave_u8__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
40373 {
40374     ma_pcm_deinterleave_u8__reference(dst, src, frameCount, channels);
40375 }
40376
40377 MA_API void ma_pcm_deinterleave_u8(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
40378 {
40379 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40380     ma_pcm_deinterleave_u8__reference(dst, src, frameCount, channels);
40381 #else
40382     ma_pcm_deinterleave_u8__optimized(dst, src, frameCount, channels);
40383 #endif
40384 }
40385
40386
40387 /* s16 */
40388 static MA_INLINE void ma_pcm_s16_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40389 {
40390     ma_uint8* dst_u8 = (ma_uint8*)dst;
40391     const ma_int16* src_s16 = (const ma_int16*)src;
40392
40393     if (ditherMode == ma_dither_mode_none) {
40394         ma_uint64 i;
40395         for (i = 0; i < count; i += 1) {
40396             ma_int16 x = src_s16[i];
40397             x = (ma_int16)(x >> 8);
40398             x = (ma_int16)(x + 128);
40399             dst_u8[i] = (ma_uint8)x;
40400         }
40401     } else {
40402         ma_uint64 i;
40403         for (i = 0; i < count; i += 1) {
40404             ma_int16 x = src_s16[i];
40405
40406             /* Dither. Don't overflow. */
40407             ma_int32 dither = ma_dither_s32(ditherMode, -0x80, 0x7F);
40408             if ((x + dither) <= 0x7FFF) {
40409                 x = (ma_int16)(x + dither);
40410             } else {
40411                 x = 0x7FFF;
40412             }
40413
40414             x = (ma_int16)(x >> 8);
40415             x = (ma_int16)(x + 128);
40416             dst_u8[i] = (ma_uint8)x;
40417         }
40418     }
40419 }
40420
40421 static MA_INLINE void ma_pcm_s16_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40422 {
40423     ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode);
40424 }
40425
40426 #if defined(MA_SUPPORT_SSE2)
40427 static MA_INLINE void ma_pcm_s16_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40428 {
40429     ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
40430 }
40431 #endif
40432 #if defined(MA_SUPPORT_AVX2)
40433 static MA_INLINE void ma_pcm_s16_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40434 {
40435     ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
40436 }
40437 #endif
40438 #if defined(MA_SUPPORT_NEON)
40439 static MA_INLINE void ma_pcm_s16_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40440 {
40441     ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
40442 }
40443 #endif
40444
40445 MA_API void ma_pcm_s16_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40446 {
40447 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40448     ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode);
40449 #else
40450     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
40451         if (ma_has_avx2()) {
40452             ma_pcm_s16_to_u8__avx2(dst, src, count, ditherMode);
40453         } else
40454     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
40455         if (ma_has_sse2()) {
40456             ma_pcm_s16_to_u8__sse2(dst, src, count, ditherMode);
40457         } else
40458     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
40459         if (ma_has_neon()) {
40460             ma_pcm_s16_to_u8__neon(dst, src, count, ditherMode);
40461         } else
40462     #endif
40463         {
40464             ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
40465         }
40466 #endif
40467 }
40468
40469
40470 MA_API void ma_pcm_s16_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40471 {
40472     (void)ditherMode;
40473     ma_copy_memory_64(dst, src, count * sizeof(ma_int16));
40474 }
40475
40476
40477 static MA_INLINE void ma_pcm_s16_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40478 {
40479     ma_uint8* dst_s24 = (ma_uint8*)dst;
40480     const ma_int16* src_s16 = (const ma_int16*)src;
40481
40482     ma_uint64 i;
40483     for (i = 0; i < count; i += 1) {
40484         dst_s24[i*3+0] = 0;
40485         dst_s24[i*3+1] = (ma_uint8)(src_s16[i] & 0xFF);
40486         dst_s24[i*3+2] = (ma_uint8)(src_s16[i] >> 8);
40487     }
40488
40489     (void)ditherMode;
40490 }
40491
40492 static MA_INLINE void ma_pcm_s16_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40493 {
40494     ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode);
40495 }
40496
40497 #if defined(MA_SUPPORT_SSE2)
40498 static MA_INLINE void ma_pcm_s16_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40499 {
40500     ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
40501 }
40502 #endif
40503 #if defined(MA_SUPPORT_AVX2)
40504 static MA_INLINE void ma_pcm_s16_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40505 {
40506     ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
40507 }
40508 #endif
40509 #if defined(MA_SUPPORT_NEON)
40510 static MA_INLINE void ma_pcm_s16_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40511 {
40512     ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
40513 }
40514 #endif
40515
40516 MA_API void ma_pcm_s16_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40517 {
40518 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40519     ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode);
40520 #else
40521     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
40522         if (ma_has_avx2()) {
40523             ma_pcm_s16_to_s24__avx2(dst, src, count, ditherMode);
40524         } else
40525     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
40526         if (ma_has_sse2()) {
40527             ma_pcm_s16_to_s24__sse2(dst, src, count, ditherMode);
40528         } else
40529     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
40530         if (ma_has_neon()) {
40531             ma_pcm_s16_to_s24__neon(dst, src, count, ditherMode);
40532         } else
40533     #endif
40534         {
40535             ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
40536         }
40537 #endif
40538 }
40539
40540
40541 static MA_INLINE void ma_pcm_s16_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40542 {
40543     ma_int32* dst_s32 = (ma_int32*)dst;
40544     const ma_int16* src_s16 = (const ma_int16*)src;
40545
40546     ma_uint64 i;
40547     for (i = 0; i < count; i += 1) {
40548         dst_s32[i] = src_s16[i] << 16;
40549     }
40550
40551     (void)ditherMode;
40552 }
40553
40554 static MA_INLINE void ma_pcm_s16_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40555 {
40556     ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode);
40557 }
40558
40559 #if defined(MA_SUPPORT_SSE2)
40560 static MA_INLINE void ma_pcm_s16_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40561 {
40562     ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
40563 }
40564 #endif
40565 #if defined(MA_SUPPORT_AVX2)
40566 static MA_INLINE void ma_pcm_s16_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40567 {
40568     ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
40569 }
40570 #endif
40571 #if defined(MA_SUPPORT_NEON)
40572 static MA_INLINE void ma_pcm_s16_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40573 {
40574     ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
40575 }
40576 #endif
40577
40578 MA_API void ma_pcm_s16_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40579 {
40580 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40581     ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode);
40582 #else
40583     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
40584         if (ma_has_avx2()) {
40585             ma_pcm_s16_to_s32__avx2(dst, src, count, ditherMode);
40586         } else
40587     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
40588         if (ma_has_sse2()) {
40589             ma_pcm_s16_to_s32__sse2(dst, src, count, ditherMode);
40590         } else
40591     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
40592         if (ma_has_neon()) {
40593             ma_pcm_s16_to_s32__neon(dst, src, count, ditherMode);
40594         } else
40595     #endif
40596         {
40597             ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
40598         }
40599 #endif
40600 }
40601
40602
40603 static MA_INLINE void ma_pcm_s16_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40604 {
40605     float* dst_f32 = (float*)dst;
40606     const ma_int16* src_s16 = (const ma_int16*)src;
40607
40608     ma_uint64 i;
40609     for (i = 0; i < count; i += 1) {
40610         float x = (float)src_s16[i];
40611
40612 #if 0
40613         /* The accurate way. */
40614         x = x + 32768.0f;                   /* -32768..32767 to 0..65535 */
40615         x = x * 0.00003051804379339284f;    /* 0..65535 to 0..2 */
40616         x = x - 1;                          /* 0..2 to -1..1 */
40617 #else
40618         /* The fast way. */
40619         x = x * 0.000030517578125f;         /* -32768..32767 to -1..0.999969482421875 */
40620 #endif
40621
40622         dst_f32[i] = x;
40623     }
40624
40625     (void)ditherMode;
40626 }
40627
40628 static MA_INLINE void ma_pcm_s16_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40629 {
40630     ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode);
40631 }
40632
40633 #if defined(MA_SUPPORT_SSE2)
40634 static MA_INLINE void ma_pcm_s16_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40635 {
40636     ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
40637 }
40638 #endif
40639 #if defined(MA_SUPPORT_AVX2)
40640 static MA_INLINE void ma_pcm_s16_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40641 {
40642     ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
40643 }
40644 #endif
40645 #if defined(MA_SUPPORT_NEON)
40646 static MA_INLINE void ma_pcm_s16_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40647 {
40648     ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
40649 }
40650 #endif
40651
40652 MA_API void ma_pcm_s16_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40653 {
40654 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40655     ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode);
40656 #else
40657     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
40658         if (ma_has_avx2()) {
40659             ma_pcm_s16_to_f32__avx2(dst, src, count, ditherMode);
40660         } else
40661     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
40662         if (ma_has_sse2()) {
40663             ma_pcm_s16_to_f32__sse2(dst, src, count, ditherMode);
40664         } else
40665     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
40666         if (ma_has_neon()) {
40667             ma_pcm_s16_to_f32__neon(dst, src, count, ditherMode);
40668         } else
40669     #endif
40670         {
40671             ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
40672         }
40673 #endif
40674 }
40675
40676
40677 static MA_INLINE void ma_pcm_interleave_s16__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
40678 {
40679     ma_int16* dst_s16 = (ma_int16*)dst;
40680     const ma_int16** src_s16 = (const ma_int16**)src;
40681
40682     ma_uint64 iFrame;
40683     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
40684         ma_uint32 iChannel;
40685         for (iChannel = 0; iChannel < channels; iChannel += 1) {
40686             dst_s16[iFrame*channels + iChannel] = src_s16[iChannel][iFrame];
40687         }
40688     }
40689 }
40690
40691 static MA_INLINE void ma_pcm_interleave_s16__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
40692 {
40693     ma_pcm_interleave_s16__reference(dst, src, frameCount, channels);
40694 }
40695
40696 MA_API void ma_pcm_interleave_s16(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
40697 {
40698 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40699     ma_pcm_interleave_s16__reference(dst, src, frameCount, channels);
40700 #else
40701     ma_pcm_interleave_s16__optimized(dst, src, frameCount, channels);
40702 #endif
40703 }
40704
40705
40706 static MA_INLINE void ma_pcm_deinterleave_s16__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
40707 {
40708     ma_int16** dst_s16 = (ma_int16**)dst;
40709     const ma_int16* src_s16 = (const ma_int16*)src;
40710
40711     ma_uint64 iFrame;
40712     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
40713         ma_uint32 iChannel;
40714         for (iChannel = 0; iChannel < channels; iChannel += 1) {
40715             dst_s16[iChannel][iFrame] = src_s16[iFrame*channels + iChannel];
40716         }
40717     }
40718 }
40719
40720 static MA_INLINE void ma_pcm_deinterleave_s16__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
40721 {
40722     ma_pcm_deinterleave_s16__reference(dst, src, frameCount, channels);
40723 }
40724
40725 MA_API void ma_pcm_deinterleave_s16(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
40726 {
40727 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40728     ma_pcm_deinterleave_s16__reference(dst, src, frameCount, channels);
40729 #else
40730     ma_pcm_deinterleave_s16__optimized(dst, src, frameCount, channels);
40731 #endif
40732 }
40733
40734
40735 /* s24 */
40736 static MA_INLINE void ma_pcm_s24_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40737 {
40738     ma_uint8* dst_u8 = (ma_uint8*)dst;
40739     const ma_uint8* src_s24 = (const ma_uint8*)src;
40740
40741     if (ditherMode == ma_dither_mode_none) {
40742         ma_uint64 i;
40743         for (i = 0; i < count; i += 1) {
40744             dst_u8[i] = (ma_uint8)((ma_int8)src_s24[i*3 + 2] + 128);
40745         }
40746     } else {
40747         ma_uint64 i;
40748         for (i = 0; i < count; i += 1) {
40749             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);
40750
40751             /* Dither. Don't overflow. */
40752             ma_int32 dither = ma_dither_s32(ditherMode, -0x800000, 0x7FFFFF);
40753             if ((ma_int64)x + dither <= 0x7FFFFFFF) {
40754                 x = x + dither;
40755             } else {
40756                 x = 0x7FFFFFFF;
40757             }
40758
40759             x = x >> 24;
40760             x = x + 128;
40761             dst_u8[i] = (ma_uint8)x;
40762         }
40763     }
40764 }
40765
40766 static MA_INLINE void ma_pcm_s24_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40767 {
40768     ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode);
40769 }
40770
40771 #if defined(MA_SUPPORT_SSE2)
40772 static MA_INLINE void ma_pcm_s24_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40773 {
40774     ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
40775 }
40776 #endif
40777 #if defined(MA_SUPPORT_AVX2)
40778 static MA_INLINE void ma_pcm_s24_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40779 {
40780     ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
40781 }
40782 #endif
40783 #if defined(MA_SUPPORT_NEON)
40784 static MA_INLINE void ma_pcm_s24_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40785 {
40786     ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
40787 }
40788 #endif
40789
40790 MA_API void ma_pcm_s24_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40791 {
40792 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40793     ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode);
40794 #else
40795     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
40796         if (ma_has_avx2()) {
40797             ma_pcm_s24_to_u8__avx2(dst, src, count, ditherMode);
40798         } else
40799     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
40800         if (ma_has_sse2()) {
40801             ma_pcm_s24_to_u8__sse2(dst, src, count, ditherMode);
40802         } else
40803     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
40804         if (ma_has_neon()) {
40805             ma_pcm_s24_to_u8__neon(dst, src, count, ditherMode);
40806         } else
40807     #endif
40808         {
40809             ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
40810         }
40811 #endif
40812 }
40813
40814
40815 static MA_INLINE void ma_pcm_s24_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40816 {
40817     ma_int16* dst_s16 = (ma_int16*)dst;
40818     const ma_uint8* src_s24 = (const ma_uint8*)src;
40819
40820     if (ditherMode == ma_dither_mode_none) {
40821         ma_uint64 i;
40822         for (i = 0; i < count; i += 1) {
40823             ma_uint16 dst_lo =            ((ma_uint16)src_s24[i*3 + 1]);
40824             ma_uint16 dst_hi = (ma_uint16)((ma_uint16)src_s24[i*3 + 2] << 8);
40825             dst_s16[i] = (ma_int16)(dst_lo | dst_hi);
40826         }
40827     } else {
40828         ma_uint64 i;
40829         for (i = 0; i < count; i += 1) {
40830             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);
40831
40832             /* Dither. Don't overflow. */
40833             ma_int32 dither = ma_dither_s32(ditherMode, -0x8000, 0x7FFF);
40834             if ((ma_int64)x + dither <= 0x7FFFFFFF) {
40835                 x = x + dither;
40836             } else {
40837                 x = 0x7FFFFFFF;
40838             }
40839
40840             x = x >> 16;
40841             dst_s16[i] = (ma_int16)x;
40842         }
40843     }
40844 }
40845
40846 static MA_INLINE void ma_pcm_s24_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40847 {
40848     ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode);
40849 }
40850
40851 #if defined(MA_SUPPORT_SSE2)
40852 static MA_INLINE void ma_pcm_s24_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40853 {
40854     ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
40855 }
40856 #endif
40857 #if defined(MA_SUPPORT_AVX2)
40858 static MA_INLINE void ma_pcm_s24_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40859 {
40860     ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
40861 }
40862 #endif
40863 #if defined(MA_SUPPORT_NEON)
40864 static MA_INLINE void ma_pcm_s24_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40865 {
40866     ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
40867 }
40868 #endif
40869
40870 MA_API void ma_pcm_s24_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40871 {
40872 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40873     ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode);
40874 #else
40875     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
40876         if (ma_has_avx2()) {
40877             ma_pcm_s24_to_s16__avx2(dst, src, count, ditherMode);
40878         } else
40879     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
40880         if (ma_has_sse2()) {
40881             ma_pcm_s24_to_s16__sse2(dst, src, count, ditherMode);
40882         } else
40883     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
40884         if (ma_has_neon()) {
40885             ma_pcm_s24_to_s16__neon(dst, src, count, ditherMode);
40886         } else
40887     #endif
40888         {
40889             ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
40890         }
40891 #endif
40892 }
40893
40894
40895 MA_API void ma_pcm_s24_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40896 {
40897     (void)ditherMode;
40898
40899     ma_copy_memory_64(dst, src, count * 3);
40900 }
40901
40902
40903 static MA_INLINE void ma_pcm_s24_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40904 {
40905     ma_int32* dst_s32 = (ma_int32*)dst;
40906     const ma_uint8* src_s24 = (const ma_uint8*)src;
40907
40908     ma_uint64 i;
40909     for (i = 0; i < count; i += 1) {
40910         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);
40911     }
40912
40913     (void)ditherMode;
40914 }
40915
40916 static MA_INLINE void ma_pcm_s24_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40917 {
40918     ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode);
40919 }
40920
40921 #if defined(MA_SUPPORT_SSE2)
40922 static MA_INLINE void ma_pcm_s24_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40923 {
40924     ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
40925 }
40926 #endif
40927 #if defined(MA_SUPPORT_AVX2)
40928 static MA_INLINE void ma_pcm_s24_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40929 {
40930     ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
40931 }
40932 #endif
40933 #if defined(MA_SUPPORT_NEON)
40934 static MA_INLINE void ma_pcm_s24_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40935 {
40936     ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
40937 }
40938 #endif
40939
40940 MA_API void ma_pcm_s24_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40941 {
40942 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
40943     ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode);
40944 #else
40945     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
40946         if (ma_has_avx2()) {
40947             ma_pcm_s24_to_s32__avx2(dst, src, count, ditherMode);
40948         } else
40949     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
40950         if (ma_has_sse2()) {
40951             ma_pcm_s24_to_s32__sse2(dst, src, count, ditherMode);
40952         } else
40953     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
40954         if (ma_has_neon()) {
40955             ma_pcm_s24_to_s32__neon(dst, src, count, ditherMode);
40956         } else
40957     #endif
40958         {
40959             ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
40960         }
40961 #endif
40962 }
40963
40964
40965 static MA_INLINE void ma_pcm_s24_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40966 {
40967     float* dst_f32 = (float*)dst;
40968     const ma_uint8* src_s24 = (const ma_uint8*)src;
40969
40970     ma_uint64 i;
40971     for (i = 0; i < count; i += 1) {
40972         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);
40973
40974 #if 0
40975         /* The accurate way. */
40976         x = x + 8388608.0f;                 /* -8388608..8388607 to 0..16777215 */
40977         x = x * 0.00000011920929665621f;    /* 0..16777215 to 0..2 */
40978         x = x - 1;                          /* 0..2 to -1..1 */
40979 #else
40980         /* The fast way. */
40981         x = x * 0.00000011920928955078125f; /* -8388608..8388607 to -1..0.999969482421875 */
40982 #endif
40983
40984         dst_f32[i] = x;
40985     }
40986
40987     (void)ditherMode;
40988 }
40989
40990 static MA_INLINE void ma_pcm_s24_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40991 {
40992     ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode);
40993 }
40994
40995 #if defined(MA_SUPPORT_SSE2)
40996 static MA_INLINE void ma_pcm_s24_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
40997 {
40998     ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
40999 }
41000 #endif
41001 #if defined(MA_SUPPORT_AVX2)
41002 static MA_INLINE void ma_pcm_s24_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41003 {
41004     ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
41005 }
41006 #endif
41007 #if defined(MA_SUPPORT_NEON)
41008 static MA_INLINE void ma_pcm_s24_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41009 {
41010     ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
41011 }
41012 #endif
41013
41014 MA_API void ma_pcm_s24_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41015 {
41016 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41017     ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode);
41018 #else
41019     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
41020         if (ma_has_avx2()) {
41021             ma_pcm_s24_to_f32__avx2(dst, src, count, ditherMode);
41022         } else
41023     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
41024         if (ma_has_sse2()) {
41025             ma_pcm_s24_to_f32__sse2(dst, src, count, ditherMode);
41026         } else
41027     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
41028         if (ma_has_neon()) {
41029             ma_pcm_s24_to_f32__neon(dst, src, count, ditherMode);
41030         } else
41031     #endif
41032         {
41033             ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
41034         }
41035 #endif
41036 }
41037
41038
41039 static MA_INLINE void ma_pcm_interleave_s24__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
41040 {
41041     ma_uint8* dst8 = (ma_uint8*)dst;
41042     const ma_uint8** src8 = (const ma_uint8**)src;
41043
41044     ma_uint64 iFrame;
41045     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41046         ma_uint32 iChannel;
41047         for (iChannel = 0; iChannel < channels; iChannel += 1) {
41048             dst8[iFrame*3*channels + iChannel*3 + 0] = src8[iChannel][iFrame*3 + 0];
41049             dst8[iFrame*3*channels + iChannel*3 + 1] = src8[iChannel][iFrame*3 + 1];
41050             dst8[iFrame*3*channels + iChannel*3 + 2] = src8[iChannel][iFrame*3 + 2];
41051         }
41052     }
41053 }
41054
41055 static MA_INLINE void ma_pcm_interleave_s24__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
41056 {
41057     ma_pcm_interleave_s24__reference(dst, src, frameCount, channels);
41058 }
41059
41060 MA_API void ma_pcm_interleave_s24(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
41061 {
41062 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41063     ma_pcm_interleave_s24__reference(dst, src, frameCount, channels);
41064 #else
41065     ma_pcm_interleave_s24__optimized(dst, src, frameCount, channels);
41066 #endif
41067 }
41068
41069
41070 static MA_INLINE void ma_pcm_deinterleave_s24__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
41071 {
41072     ma_uint8** dst8 = (ma_uint8**)dst;
41073     const ma_uint8* src8 = (const ma_uint8*)src;
41074
41075     ma_uint32 iFrame;
41076     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41077         ma_uint32 iChannel;
41078         for (iChannel = 0; iChannel < channels; iChannel += 1) {
41079             dst8[iChannel][iFrame*3 + 0] = src8[iFrame*3*channels + iChannel*3 + 0];
41080             dst8[iChannel][iFrame*3 + 1] = src8[iFrame*3*channels + iChannel*3 + 1];
41081             dst8[iChannel][iFrame*3 + 2] = src8[iFrame*3*channels + iChannel*3 + 2];
41082         }
41083     }
41084 }
41085
41086 static MA_INLINE void ma_pcm_deinterleave_s24__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
41087 {
41088     ma_pcm_deinterleave_s24__reference(dst, src, frameCount, channels);
41089 }
41090
41091 MA_API void ma_pcm_deinterleave_s24(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
41092 {
41093 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41094     ma_pcm_deinterleave_s24__reference(dst, src, frameCount, channels);
41095 #else
41096     ma_pcm_deinterleave_s24__optimized(dst, src, frameCount, channels);
41097 #endif
41098 }
41099
41100
41101
41102 /* s32 */
41103 static MA_INLINE void ma_pcm_s32_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41104 {
41105     ma_uint8* dst_u8 = (ma_uint8*)dst;
41106     const ma_int32* src_s32 = (const ma_int32*)src;
41107
41108     if (ditherMode == ma_dither_mode_none) {
41109         ma_uint64 i;
41110         for (i = 0; i < count; i += 1) {
41111             ma_int32 x = src_s32[i];
41112             x = x >> 24;
41113             x = x + 128;
41114             dst_u8[i] = (ma_uint8)x;
41115         }
41116     } else {
41117         ma_uint64 i;
41118         for (i = 0; i < count; i += 1) {
41119             ma_int32 x = src_s32[i];
41120
41121             /* Dither. Don't overflow. */
41122             ma_int32 dither = ma_dither_s32(ditherMode, -0x800000, 0x7FFFFF);
41123             if ((ma_int64)x + dither <= 0x7FFFFFFF) {
41124                 x = x + dither;
41125             } else {
41126                 x = 0x7FFFFFFF;
41127             }
41128
41129             x = x >> 24;
41130             x = x + 128;
41131             dst_u8[i] = (ma_uint8)x;
41132         }
41133     }
41134 }
41135
41136 static MA_INLINE void ma_pcm_s32_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41137 {
41138     ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode);
41139 }
41140
41141 #if defined(MA_SUPPORT_SSE2)
41142 static MA_INLINE void ma_pcm_s32_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41143 {
41144     ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
41145 }
41146 #endif
41147 #if defined(MA_SUPPORT_AVX2)
41148 static MA_INLINE void ma_pcm_s32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41149 {
41150     ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
41151 }
41152 #endif
41153 #if defined(MA_SUPPORT_NEON)
41154 static MA_INLINE void ma_pcm_s32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41155 {
41156     ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
41157 }
41158 #endif
41159
41160 MA_API void ma_pcm_s32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41161 {
41162 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41163     ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode);
41164 #else
41165     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
41166         if (ma_has_avx2()) {
41167             ma_pcm_s32_to_u8__avx2(dst, src, count, ditherMode);
41168         } else
41169     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
41170         if (ma_has_sse2()) {
41171             ma_pcm_s32_to_u8__sse2(dst, src, count, ditherMode);
41172         } else
41173     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
41174         if (ma_has_neon()) {
41175             ma_pcm_s32_to_u8__neon(dst, src, count, ditherMode);
41176         } else
41177     #endif
41178         {
41179             ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
41180         }
41181 #endif
41182 }
41183
41184
41185 static MA_INLINE void ma_pcm_s32_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41186 {
41187     ma_int16* dst_s16 = (ma_int16*)dst;
41188     const ma_int32* src_s32 = (const ma_int32*)src;
41189
41190     if (ditherMode == ma_dither_mode_none) {
41191         ma_uint64 i;
41192         for (i = 0; i < count; i += 1) {
41193             ma_int32 x = src_s32[i];
41194             x = x >> 16;
41195             dst_s16[i] = (ma_int16)x;
41196         }
41197     } else {
41198         ma_uint64 i;
41199         for (i = 0; i < count; i += 1) {
41200             ma_int32 x = src_s32[i];
41201
41202             /* Dither. Don't overflow. */
41203             ma_int32 dither = ma_dither_s32(ditherMode, -0x8000, 0x7FFF);
41204             if ((ma_int64)x + dither <= 0x7FFFFFFF) {
41205                 x = x + dither;
41206             } else {
41207                 x = 0x7FFFFFFF;
41208             }
41209
41210             x = x >> 16;
41211             dst_s16[i] = (ma_int16)x;
41212         }
41213     }
41214 }
41215
41216 static MA_INLINE void ma_pcm_s32_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41217 {
41218     ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode);
41219 }
41220
41221 #if defined(MA_SUPPORT_SSE2)
41222 static MA_INLINE void ma_pcm_s32_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41223 {
41224     ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
41225 }
41226 #endif
41227 #if defined(MA_SUPPORT_AVX2)
41228 static MA_INLINE void ma_pcm_s32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41229 {
41230     ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
41231 }
41232 #endif
41233 #if defined(MA_SUPPORT_NEON)
41234 static MA_INLINE void ma_pcm_s32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41235 {
41236     ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
41237 }
41238 #endif
41239
41240 MA_API void ma_pcm_s32_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41241 {
41242 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41243     ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode);
41244 #else
41245     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
41246         if (ma_has_avx2()) {
41247             ma_pcm_s32_to_s16__avx2(dst, src, count, ditherMode);
41248         } else
41249     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
41250         if (ma_has_sse2()) {
41251             ma_pcm_s32_to_s16__sse2(dst, src, count, ditherMode);
41252         } else
41253     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
41254         if (ma_has_neon()) {
41255             ma_pcm_s32_to_s16__neon(dst, src, count, ditherMode);
41256         } else
41257     #endif
41258         {
41259             ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
41260         }
41261 #endif
41262 }
41263
41264
41265 static MA_INLINE void ma_pcm_s32_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41266 {
41267     ma_uint8* dst_s24 = (ma_uint8*)dst;
41268     const ma_int32* src_s32 = (const ma_int32*)src;
41269
41270     ma_uint64 i;
41271     for (i = 0; i < count; i += 1) {
41272         ma_uint32 x = (ma_uint32)src_s32[i];
41273         dst_s24[i*3+0] = (ma_uint8)((x & 0x0000FF00) >>  8);
41274         dst_s24[i*3+1] = (ma_uint8)((x & 0x00FF0000) >> 16);
41275         dst_s24[i*3+2] = (ma_uint8)((x & 0xFF000000) >> 24);
41276     }
41277
41278     (void)ditherMode;   /* No dithering for s32 -> s24. */
41279 }
41280
41281 static MA_INLINE void ma_pcm_s32_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41282 {
41283     ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode);
41284 }
41285
41286 #if defined(MA_SUPPORT_SSE2)
41287 static MA_INLINE void ma_pcm_s32_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41288 {
41289     ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
41290 }
41291 #endif
41292 #if defined(MA_SUPPORT_AVX2)
41293 static MA_INLINE void ma_pcm_s32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41294 {
41295     ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
41296 }
41297 #endif
41298 #if defined(MA_SUPPORT_NEON)
41299 static MA_INLINE void ma_pcm_s32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41300 {
41301     ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
41302 }
41303 #endif
41304
41305 MA_API void ma_pcm_s32_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41306 {
41307 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41308     ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode);
41309 #else
41310     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
41311         if (ma_has_avx2()) {
41312             ma_pcm_s32_to_s24__avx2(dst, src, count, ditherMode);
41313         } else
41314     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
41315         if (ma_has_sse2()) {
41316             ma_pcm_s32_to_s24__sse2(dst, src, count, ditherMode);
41317         } else
41318     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
41319         if (ma_has_neon()) {
41320             ma_pcm_s32_to_s24__neon(dst, src, count, ditherMode);
41321         } else
41322     #endif
41323         {
41324             ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
41325         }
41326 #endif
41327 }
41328
41329
41330 MA_API void ma_pcm_s32_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41331 {
41332     (void)ditherMode;
41333
41334     ma_copy_memory_64(dst, src, count * sizeof(ma_int32));
41335 }
41336
41337
41338 static MA_INLINE void ma_pcm_s32_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41339 {
41340     float* dst_f32 = (float*)dst;
41341     const ma_int32* src_s32 = (const ma_int32*)src;
41342
41343     ma_uint64 i;
41344     for (i = 0; i < count; i += 1) {
41345         double x = src_s32[i];
41346
41347 #if 0
41348         x = x + 2147483648.0;
41349         x = x * 0.0000000004656612873077392578125;
41350         x = x - 1;
41351 #else
41352         x = x / 2147483648.0;
41353 #endif
41354
41355         dst_f32[i] = (float)x;
41356     }
41357
41358     (void)ditherMode;   /* No dithering for s32 -> f32. */
41359 }
41360
41361 static MA_INLINE void ma_pcm_s32_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41362 {
41363     ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode);
41364 }
41365
41366 #if defined(MA_SUPPORT_SSE2)
41367 static MA_INLINE void ma_pcm_s32_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41368 {
41369     ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
41370 }
41371 #endif
41372 #if defined(MA_SUPPORT_AVX2)
41373 static MA_INLINE void ma_pcm_s32_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41374 {
41375     ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
41376 }
41377 #endif
41378 #if defined(MA_SUPPORT_NEON)
41379 static MA_INLINE void ma_pcm_s32_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41380 {
41381     ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
41382 }
41383 #endif
41384
41385 MA_API void ma_pcm_s32_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41386 {
41387 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41388     ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode);
41389 #else
41390     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
41391         if (ma_has_avx2()) {
41392             ma_pcm_s32_to_f32__avx2(dst, src, count, ditherMode);
41393         } else
41394     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
41395         if (ma_has_sse2()) {
41396             ma_pcm_s32_to_f32__sse2(dst, src, count, ditherMode);
41397         } else
41398     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
41399         if (ma_has_neon()) {
41400             ma_pcm_s32_to_f32__neon(dst, src, count, ditherMode);
41401         } else
41402     #endif
41403         {
41404             ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
41405         }
41406 #endif
41407 }
41408
41409
41410 static MA_INLINE void ma_pcm_interleave_s32__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
41411 {
41412     ma_int32* dst_s32 = (ma_int32*)dst;
41413     const ma_int32** src_s32 = (const ma_int32**)src;
41414
41415     ma_uint64 iFrame;
41416     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41417         ma_uint32 iChannel;
41418         for (iChannel = 0; iChannel < channels; iChannel += 1) {
41419             dst_s32[iFrame*channels + iChannel] = src_s32[iChannel][iFrame];
41420         }
41421     }
41422 }
41423
41424 static MA_INLINE void ma_pcm_interleave_s32__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
41425 {
41426     ma_pcm_interleave_s32__reference(dst, src, frameCount, channels);
41427 }
41428
41429 MA_API void ma_pcm_interleave_s32(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
41430 {
41431 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41432     ma_pcm_interleave_s32__reference(dst, src, frameCount, channels);
41433 #else
41434     ma_pcm_interleave_s32__optimized(dst, src, frameCount, channels);
41435 #endif
41436 }
41437
41438
41439 static MA_INLINE void ma_pcm_deinterleave_s32__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
41440 {
41441     ma_int32** dst_s32 = (ma_int32**)dst;
41442     const ma_int32* src_s32 = (const ma_int32*)src;
41443
41444     ma_uint64 iFrame;
41445     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
41446         ma_uint32 iChannel;
41447         for (iChannel = 0; iChannel < channels; iChannel += 1) {
41448             dst_s32[iChannel][iFrame] = src_s32[iFrame*channels + iChannel];
41449         }
41450     }
41451 }
41452
41453 static MA_INLINE void ma_pcm_deinterleave_s32__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
41454 {
41455     ma_pcm_deinterleave_s32__reference(dst, src, frameCount, channels);
41456 }
41457
41458 MA_API void ma_pcm_deinterleave_s32(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
41459 {
41460 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41461     ma_pcm_deinterleave_s32__reference(dst, src, frameCount, channels);
41462 #else
41463     ma_pcm_deinterleave_s32__optimized(dst, src, frameCount, channels);
41464 #endif
41465 }
41466
41467
41468 /* f32 */
41469 static MA_INLINE void ma_pcm_f32_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41470 {
41471     ma_uint64 i;
41472
41473     ma_uint8* dst_u8 = (ma_uint8*)dst;
41474     const float* src_f32 = (const float*)src;
41475
41476     float ditherMin = 0;
41477     float ditherMax = 0;
41478     if (ditherMode != ma_dither_mode_none) {
41479         ditherMin = 1.0f / -128;
41480         ditherMax = 1.0f /  127;
41481     }
41482
41483     for (i = 0; i < count; i += 1) {
41484         float x = src_f32[i];
41485         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
41486         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
41487         x = x + 1;                                  /* -1..1 to 0..2 */
41488         x = x * 127.5f;                             /* 0..2 to 0..255 */
41489
41490         dst_u8[i] = (ma_uint8)x;
41491     }
41492 }
41493
41494 static MA_INLINE void ma_pcm_f32_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41495 {
41496     ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode);
41497 }
41498
41499 #if defined(MA_SUPPORT_SSE2)
41500 static MA_INLINE void ma_pcm_f32_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41501 {
41502     ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
41503 }
41504 #endif
41505 #if defined(MA_SUPPORT_AVX2)
41506 static MA_INLINE void ma_pcm_f32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41507 {
41508     ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
41509 }
41510 #endif
41511 #if defined(MA_SUPPORT_NEON)
41512 static MA_INLINE void ma_pcm_f32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41513 {
41514     ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
41515 }
41516 #endif
41517
41518 MA_API void ma_pcm_f32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41519 {
41520 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41521     ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode);
41522 #else
41523     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
41524         if (ma_has_avx2()) {
41525             ma_pcm_f32_to_u8__avx2(dst, src, count, ditherMode);
41526         } else
41527     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
41528         if (ma_has_sse2()) {
41529             ma_pcm_f32_to_u8__sse2(dst, src, count, ditherMode);
41530         } else
41531     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
41532         if (ma_has_neon()) {
41533             ma_pcm_f32_to_u8__neon(dst, src, count, ditherMode);
41534         } else
41535     #endif
41536         {
41537             ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
41538         }
41539 #endif
41540 }
41541
41542 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41543 static MA_INLINE void ma_pcm_f32_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41544 {
41545     ma_uint64 i;
41546
41547     ma_int16* dst_s16 = (ma_int16*)dst;
41548     const float* src_f32 = (const float*)src;
41549
41550     float ditherMin = 0;
41551     float ditherMax = 0;
41552     if (ditherMode != ma_dither_mode_none) {
41553         ditherMin = 1.0f / -32768;
41554         ditherMax = 1.0f /  32767;
41555     }
41556
41557     for (i = 0; i < count; i += 1) {
41558         float x = src_f32[i];
41559         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
41560         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
41561
41562 #if 0
41563         /* The accurate way. */
41564         x = x + 1;                                  /* -1..1 to 0..2 */
41565         x = x * 32767.5f;                           /* 0..2 to 0..65535 */
41566         x = x - 32768.0f;                           /* 0...65535 to -32768..32767 */
41567 #else
41568         /* The fast way. */
41569         x = x * 32767.0f;                           /* -1..1 to -32767..32767 */
41570 #endif
41571
41572         dst_s16[i] = (ma_int16)x;
41573     }
41574 }
41575 #else
41576 static MA_INLINE void ma_pcm_f32_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41577 {
41578     ma_uint64 i;
41579     ma_uint64 i4;
41580     ma_uint64 count4;
41581
41582     ma_int16* dst_s16 = (ma_int16*)dst;
41583     const float* src_f32 = (const float*)src;
41584
41585     float ditherMin = 0;
41586     float ditherMax = 0;
41587     if (ditherMode != ma_dither_mode_none) {
41588         ditherMin = 1.0f / -32768;
41589         ditherMax = 1.0f /  32767;
41590     }
41591
41592     /* Unrolled. */
41593     i = 0;
41594     count4 = count >> 2;
41595     for (i4 = 0; i4 < count4; i4 += 1) {
41596         float d0 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
41597         float d1 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
41598         float d2 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
41599         float d3 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
41600
41601         float x0 = src_f32[i+0];
41602         float x1 = src_f32[i+1];
41603         float x2 = src_f32[i+2];
41604         float x3 = src_f32[i+3];
41605
41606         x0 = x0 + d0;
41607         x1 = x1 + d1;
41608         x2 = x2 + d2;
41609         x3 = x3 + d3;
41610
41611         x0 = ((x0 < -1) ? -1 : ((x0 > 1) ? 1 : x0));
41612         x1 = ((x1 < -1) ? -1 : ((x1 > 1) ? 1 : x1));
41613         x2 = ((x2 < -1) ? -1 : ((x2 > 1) ? 1 : x2));
41614         x3 = ((x3 < -1) ? -1 : ((x3 > 1) ? 1 : x3));
41615
41616         x0 = x0 * 32767.0f;
41617         x1 = x1 * 32767.0f;
41618         x2 = x2 * 32767.0f;
41619         x3 = x3 * 32767.0f;
41620
41621         dst_s16[i+0] = (ma_int16)x0;
41622         dst_s16[i+1] = (ma_int16)x1;
41623         dst_s16[i+2] = (ma_int16)x2;
41624         dst_s16[i+3] = (ma_int16)x3;
41625
41626         i += 4;
41627     }
41628
41629     /* Leftover. */
41630     for (; i < count; i += 1) {
41631         float x = src_f32[i];
41632         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
41633         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
41634         x = x * 32767.0f;                           /* -1..1 to -32767..32767 */
41635
41636         dst_s16[i] = (ma_int16)x;
41637     }
41638 }
41639
41640 #if defined(MA_SUPPORT_SSE2)
41641 static MA_INLINE void ma_pcm_f32_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41642 {
41643     ma_uint64 i;
41644     ma_uint64 i8;
41645     ma_uint64 count8;
41646     ma_int16* dst_s16;
41647     const float* src_f32;
41648     float ditherMin;
41649     float ditherMax;
41650
41651     /* Both the input and output buffers need to be aligned to 16 bytes. */
41652     if ((((ma_uintptr)dst & 15) != 0) || (((ma_uintptr)src & 15) != 0)) {
41653         ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
41654         return;
41655     }
41656
41657     dst_s16 = (ma_int16*)dst;
41658     src_f32 = (const float*)src;
41659
41660     ditherMin = 0;
41661     ditherMax = 0;
41662     if (ditherMode != ma_dither_mode_none) {
41663         ditherMin = 1.0f / -32768;
41664         ditherMax = 1.0f /  32767;
41665     }
41666
41667     i = 0;
41668
41669     /* SSE2. SSE allows us to output 8 s16's at a time which means our loop is unrolled 8 times. */
41670     count8 = count >> 3;
41671     for (i8 = 0; i8 < count8; i8 += 1) {
41672         __m128 d0;
41673         __m128 d1;
41674         __m128 x0;
41675         __m128 x1;
41676
41677         if (ditherMode == ma_dither_mode_none) {
41678             d0 = _mm_set1_ps(0);
41679             d1 = _mm_set1_ps(0);
41680         } else if (ditherMode == ma_dither_mode_rectangle) {
41681             d0 = _mm_set_ps(
41682                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41683                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41684                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41685                 ma_dither_f32_rectangle(ditherMin, ditherMax)
41686             );
41687             d1 = _mm_set_ps(
41688                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41689                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41690                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41691                 ma_dither_f32_rectangle(ditherMin, ditherMax)
41692             );
41693         } else {
41694             d0 = _mm_set_ps(
41695                 ma_dither_f32_triangle(ditherMin, ditherMax),
41696                 ma_dither_f32_triangle(ditherMin, ditherMax),
41697                 ma_dither_f32_triangle(ditherMin, ditherMax),
41698                 ma_dither_f32_triangle(ditherMin, ditherMax)
41699             );
41700             d1 = _mm_set_ps(
41701                 ma_dither_f32_triangle(ditherMin, ditherMax),
41702                 ma_dither_f32_triangle(ditherMin, ditherMax),
41703                 ma_dither_f32_triangle(ditherMin, ditherMax),
41704                 ma_dither_f32_triangle(ditherMin, ditherMax)
41705             );
41706         }
41707
41708         x0 = *((__m128*)(src_f32 + i) + 0);
41709         x1 = *((__m128*)(src_f32 + i) + 1);
41710
41711         x0 = _mm_add_ps(x0, d0);
41712         x1 = _mm_add_ps(x1, d1);
41713
41714         x0 = _mm_mul_ps(x0, _mm_set1_ps(32767.0f));
41715         x1 = _mm_mul_ps(x1, _mm_set1_ps(32767.0f));
41716
41717         _mm_stream_si128(((__m128i*)(dst_s16 + i)), _mm_packs_epi32(_mm_cvttps_epi32(x0), _mm_cvttps_epi32(x1)));
41718
41719         i += 8;
41720     }
41721
41722
41723     /* Leftover. */
41724     for (; i < count; i += 1) {
41725         float x = src_f32[i];
41726         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
41727         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
41728         x = x * 32767.0f;                           /* -1..1 to -32767..32767 */
41729
41730         dst_s16[i] = (ma_int16)x;
41731     }
41732 }
41733 #endif  /* SSE2 */
41734
41735 #if defined(MA_SUPPORT_AVX2)
41736 static MA_INLINE void ma_pcm_f32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41737 {
41738     ma_uint64 i;
41739     ma_uint64 i16;
41740     ma_uint64 count16;
41741     ma_int16* dst_s16;
41742     const float* src_f32;
41743     float ditherMin;
41744     float ditherMax;
41745
41746     /* Both the input and output buffers need to be aligned to 32 bytes. */
41747     if ((((ma_uintptr)dst & 31) != 0) || (((ma_uintptr)src & 31) != 0)) {
41748         ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
41749         return;
41750     }
41751
41752     dst_s16 = (ma_int16*)dst;
41753     src_f32 = (const float*)src;
41754
41755     ditherMin = 0;
41756     ditherMax = 0;
41757     if (ditherMode != ma_dither_mode_none) {
41758         ditherMin = 1.0f / -32768;
41759         ditherMax = 1.0f /  32767;
41760     }
41761
41762     i = 0;
41763
41764     /* AVX2. AVX2 allows us to output 16 s16's at a time which means our loop is unrolled 16 times. */
41765     count16 = count >> 4;
41766     for (i16 = 0; i16 < count16; i16 += 1) {
41767         __m256 d0;
41768         __m256 d1;
41769         __m256 x0;
41770         __m256 x1;
41771         __m256i i0;
41772         __m256i i1;
41773         __m256i p0;
41774         __m256i p1;
41775         __m256i r;
41776
41777         if (ditherMode == ma_dither_mode_none) {
41778             d0 = _mm256_set1_ps(0);
41779             d1 = _mm256_set1_ps(0);
41780         } else if (ditherMode == ma_dither_mode_rectangle) {
41781             d0 = _mm256_set_ps(
41782                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41783                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41784                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41785                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41786                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41787                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41788                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41789                 ma_dither_f32_rectangle(ditherMin, ditherMax)
41790             );
41791             d1 = _mm256_set_ps(
41792                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41793                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41794                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41795                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41796                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41797                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41798                 ma_dither_f32_rectangle(ditherMin, ditherMax),
41799                 ma_dither_f32_rectangle(ditherMin, ditherMax)
41800             );
41801         } else {
41802             d0 = _mm256_set_ps(
41803                 ma_dither_f32_triangle(ditherMin, ditherMax),
41804                 ma_dither_f32_triangle(ditherMin, ditherMax),
41805                 ma_dither_f32_triangle(ditherMin, ditherMax),
41806                 ma_dither_f32_triangle(ditherMin, ditherMax),
41807                 ma_dither_f32_triangle(ditherMin, ditherMax),
41808                 ma_dither_f32_triangle(ditherMin, ditherMax),
41809                 ma_dither_f32_triangle(ditherMin, ditherMax),
41810                 ma_dither_f32_triangle(ditherMin, ditherMax)
41811             );
41812             d1 = _mm256_set_ps(
41813                 ma_dither_f32_triangle(ditherMin, ditherMax),
41814                 ma_dither_f32_triangle(ditherMin, ditherMax),
41815                 ma_dither_f32_triangle(ditherMin, ditherMax),
41816                 ma_dither_f32_triangle(ditherMin, ditherMax),
41817                 ma_dither_f32_triangle(ditherMin, ditherMax),
41818                 ma_dither_f32_triangle(ditherMin, ditherMax),
41819                 ma_dither_f32_triangle(ditherMin, ditherMax),
41820                 ma_dither_f32_triangle(ditherMin, ditherMax)
41821             );
41822         }
41823
41824         x0 = *((__m256*)(src_f32 + i) + 0);
41825         x1 = *((__m256*)(src_f32 + i) + 1);
41826
41827         x0 = _mm256_add_ps(x0, d0);
41828         x1 = _mm256_add_ps(x1, d1);
41829
41830         x0 = _mm256_mul_ps(x0, _mm256_set1_ps(32767.0f));
41831         x1 = _mm256_mul_ps(x1, _mm256_set1_ps(32767.0f));
41832
41833         /* Computing the final result is a little more complicated for AVX2 than SSE2. */
41834         i0 = _mm256_cvttps_epi32(x0);
41835         i1 = _mm256_cvttps_epi32(x1);
41836         p0 = _mm256_permute2x128_si256(i0, i1, 0 | 32);
41837         p1 = _mm256_permute2x128_si256(i0, i1, 1 | 48);
41838         r  = _mm256_packs_epi32(p0, p1);
41839
41840         _mm256_stream_si256(((__m256i*)(dst_s16 + i)), r);
41841
41842         i += 16;
41843     }
41844
41845
41846     /* Leftover. */
41847     for (; i < count; i += 1) {
41848         float x = src_f32[i];
41849         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
41850         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
41851         x = x * 32767.0f;                           /* -1..1 to -32767..32767 */
41852
41853         dst_s16[i] = (ma_int16)x;
41854     }
41855 }
41856 #endif  /* AVX2 */
41857
41858 #if defined(MA_SUPPORT_NEON)
41859 static MA_INLINE void ma_pcm_f32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41860 {
41861     ma_uint64 i;
41862     ma_uint64 i8;
41863     ma_uint64 count8;
41864     ma_int16* dst_s16;
41865     const float* src_f32;
41866     float ditherMin;
41867     float ditherMax;
41868
41869     if (!ma_has_neon()) {
41870         return ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
41871     }
41872
41873     /* Both the input and output buffers need to be aligned to 16 bytes. */
41874     if ((((ma_uintptr)dst & 15) != 0) || (((ma_uintptr)src & 15) != 0)) {
41875         ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
41876         return;
41877     }
41878
41879     dst_s16 = (ma_int16*)dst;
41880     src_f32 = (const float*)src;
41881
41882     ditherMin = 0;
41883     ditherMax = 0;
41884     if (ditherMode != ma_dither_mode_none) {
41885         ditherMin = 1.0f / -32768;
41886         ditherMax = 1.0f /  32767;
41887     }
41888
41889     i = 0;
41890
41891     /* NEON. NEON allows us to output 8 s16's at a time which means our loop is unrolled 8 times. */
41892     count8 = count >> 3;
41893     for (i8 = 0; i8 < count8; i8 += 1) {
41894         float32x4_t d0;
41895         float32x4_t d1;
41896         float32x4_t x0;
41897         float32x4_t x1;
41898         int32x4_t i0;
41899         int32x4_t i1;
41900
41901         if (ditherMode == ma_dither_mode_none) {
41902             d0 = vmovq_n_f32(0);
41903             d1 = vmovq_n_f32(0);
41904         } else if (ditherMode == ma_dither_mode_rectangle) {
41905             float d0v[4];
41906             d0v[0] = ma_dither_f32_rectangle(ditherMin, ditherMax);
41907             d0v[1] = ma_dither_f32_rectangle(ditherMin, ditherMax);
41908             d0v[2] = ma_dither_f32_rectangle(ditherMin, ditherMax);
41909             d0v[3] = ma_dither_f32_rectangle(ditherMin, ditherMax);
41910             d0 = vld1q_f32(d0v);
41911
41912             float d1v[4];
41913             d1v[0] = ma_dither_f32_rectangle(ditherMin, ditherMax);
41914             d1v[1] = ma_dither_f32_rectangle(ditherMin, ditherMax);
41915             d1v[2] = ma_dither_f32_rectangle(ditherMin, ditherMax);
41916             d1v[3] = ma_dither_f32_rectangle(ditherMin, ditherMax);
41917             d1 = vld1q_f32(d1v);
41918         } else {
41919             float d0v[4];
41920             d0v[0] = ma_dither_f32_triangle(ditherMin, ditherMax);
41921             d0v[1] = ma_dither_f32_triangle(ditherMin, ditherMax);
41922             d0v[2] = ma_dither_f32_triangle(ditherMin, ditherMax);
41923             d0v[3] = ma_dither_f32_triangle(ditherMin, ditherMax);
41924             d0 = vld1q_f32(d0v);
41925
41926             float d1v[4];
41927             d1v[0] = ma_dither_f32_triangle(ditherMin, ditherMax);
41928             d1v[1] = ma_dither_f32_triangle(ditherMin, ditherMax);
41929             d1v[2] = ma_dither_f32_triangle(ditherMin, ditherMax);
41930             d1v[3] = ma_dither_f32_triangle(ditherMin, ditherMax);
41931             d1 = vld1q_f32(d1v);
41932         }
41933
41934         x0 = *((float32x4_t*)(src_f32 + i) + 0);
41935         x1 = *((float32x4_t*)(src_f32 + i) + 1);
41936
41937         x0 = vaddq_f32(x0, d0);
41938         x1 = vaddq_f32(x1, d1);
41939
41940         x0 = vmulq_n_f32(x0, 32767.0f);
41941         x1 = vmulq_n_f32(x1, 32767.0f);
41942
41943         i0 = vcvtq_s32_f32(x0);
41944         i1 = vcvtq_s32_f32(x1);
41945         *((int16x8_t*)(dst_s16 + i)) = vcombine_s16(vqmovn_s32(i0), vqmovn_s32(i1));
41946
41947         i += 8;
41948     }
41949
41950
41951     /* Leftover. */
41952     for (; i < count; i += 1) {
41953         float x = src_f32[i];
41954         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
41955         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
41956         x = x * 32767.0f;                           /* -1..1 to -32767..32767 */
41957
41958         dst_s16[i] = (ma_int16)x;
41959     }
41960 }
41961 #endif  /* Neon */
41962 #endif  /* MA_USE_REFERENCE_CONVERSION_APIS */
41963
41964 MA_API void ma_pcm_f32_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41965 {
41966 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
41967     ma_pcm_f32_to_s16__reference(dst, src, count, ditherMode);
41968 #else
41969     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
41970         if (ma_has_avx2()) {
41971             ma_pcm_f32_to_s16__avx2(dst, src, count, ditherMode);
41972         } else
41973     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
41974         if (ma_has_sse2()) {
41975             ma_pcm_f32_to_s16__sse2(dst, src, count, ditherMode);
41976         } else
41977     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
41978         if (ma_has_neon()) {
41979             ma_pcm_f32_to_s16__neon(dst, src, count, ditherMode);
41980         } else
41981     #endif
41982         {
41983             ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
41984         }
41985 #endif
41986 }
41987
41988
41989 static MA_INLINE void ma_pcm_f32_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
41990 {
41991     ma_uint8* dst_s24 = (ma_uint8*)dst;
41992     const float* src_f32 = (const float*)src;
41993
41994     ma_uint64 i;
41995     for (i = 0; i < count; i += 1) {
41996         ma_int32 r;
41997         float x = src_f32[i];
41998         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
41999
42000 #if 0
42001         /* The accurate way. */
42002         x = x + 1;                                  /* -1..1 to 0..2 */
42003         x = x * 8388607.5f;                         /* 0..2 to 0..16777215 */
42004         x = x - 8388608.0f;                         /* 0..16777215 to -8388608..8388607 */
42005 #else
42006         /* The fast way. */
42007         x = x * 8388607.0f;                         /* -1..1 to -8388607..8388607 */
42008 #endif
42009
42010         r = (ma_int32)x;
42011         dst_s24[(i*3)+0] = (ma_uint8)((r & 0x0000FF) >>  0);
42012         dst_s24[(i*3)+1] = (ma_uint8)((r & 0x00FF00) >>  8);
42013         dst_s24[(i*3)+2] = (ma_uint8)((r & 0xFF0000) >> 16);
42014     }
42015
42016     (void)ditherMode;   /* No dithering for f32 -> s24. */
42017 }
42018
42019 static MA_INLINE void ma_pcm_f32_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42020 {
42021     ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode);
42022 }
42023
42024 #if defined(MA_SUPPORT_SSE2)
42025 static MA_INLINE void ma_pcm_f32_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42026 {
42027     ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
42028 }
42029 #endif
42030 #if defined(MA_SUPPORT_AVX2)
42031 static MA_INLINE void ma_pcm_f32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42032 {
42033     ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
42034 }
42035 #endif
42036 #if defined(MA_SUPPORT_NEON)
42037 static MA_INLINE void ma_pcm_f32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42038 {
42039     ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
42040 }
42041 #endif
42042
42043 MA_API void ma_pcm_f32_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42044 {
42045 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
42046     ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode);
42047 #else
42048     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
42049         if (ma_has_avx2()) {
42050             ma_pcm_f32_to_s24__avx2(dst, src, count, ditherMode);
42051         } else
42052     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
42053         if (ma_has_sse2()) {
42054             ma_pcm_f32_to_s24__sse2(dst, src, count, ditherMode);
42055         } else
42056     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
42057         if (ma_has_neon()) {
42058             ma_pcm_f32_to_s24__neon(dst, src, count, ditherMode);
42059         } else
42060     #endif
42061         {
42062             ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
42063         }
42064 #endif
42065 }
42066
42067
42068 static MA_INLINE void ma_pcm_f32_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42069 {
42070     ma_int32* dst_s32 = (ma_int32*)dst;
42071     const float* src_f32 = (const float*)src;
42072
42073     ma_uint32 i;
42074     for (i = 0; i < count; i += 1) {
42075         double x = src_f32[i];
42076         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
42077
42078 #if 0
42079         /* The accurate way. */
42080         x = x + 1;                                  /* -1..1 to 0..2 */
42081         x = x * 2147483647.5;                       /* 0..2 to 0..4294967295 */
42082         x = x - 2147483648.0;                       /* 0...4294967295 to -2147483648..2147483647 */
42083 #else
42084         /* The fast way. */
42085         x = x * 2147483647.0;                       /* -1..1 to -2147483647..2147483647 */
42086 #endif
42087
42088         dst_s32[i] = (ma_int32)x;
42089     }
42090
42091     (void)ditherMode;   /* No dithering for f32 -> s32. */
42092 }
42093
42094 static MA_INLINE void ma_pcm_f32_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42095 {
42096     ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode);
42097 }
42098
42099 #if defined(MA_SUPPORT_SSE2)
42100 static MA_INLINE void ma_pcm_f32_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42101 {
42102     ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
42103 }
42104 #endif
42105 #if defined(MA_SUPPORT_AVX2)
42106 static MA_INLINE void ma_pcm_f32_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42107 {
42108     ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
42109 }
42110 #endif
42111 #if defined(MA_SUPPORT_NEON)
42112 static MA_INLINE void ma_pcm_f32_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42113 {
42114     ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
42115 }
42116 #endif
42117
42118 MA_API void ma_pcm_f32_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42119 {
42120 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
42121     ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode);
42122 #else
42123     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
42124         if (ma_has_avx2()) {
42125             ma_pcm_f32_to_s32__avx2(dst, src, count, ditherMode);
42126         } else
42127     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
42128         if (ma_has_sse2()) {
42129             ma_pcm_f32_to_s32__sse2(dst, src, count, ditherMode);
42130         } else
42131     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
42132         if (ma_has_neon()) {
42133             ma_pcm_f32_to_s32__neon(dst, src, count, ditherMode);
42134         } else
42135     #endif
42136         {
42137             ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
42138         }
42139 #endif
42140 }
42141
42142
42143 MA_API void ma_pcm_f32_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
42144 {
42145     (void)ditherMode;
42146
42147     ma_copy_memory_64(dst, src, count * sizeof(float));
42148 }
42149
42150
42151 static void ma_pcm_interleave_f32__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
42152 {
42153     float* dst_f32 = (float*)dst;
42154     const float** src_f32 = (const float**)src;
42155
42156     ma_uint64 iFrame;
42157     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
42158         ma_uint32 iChannel;
42159         for (iChannel = 0; iChannel < channels; iChannel += 1) {
42160             dst_f32[iFrame*channels + iChannel] = src_f32[iChannel][iFrame];
42161         }
42162     }
42163 }
42164
42165 static void ma_pcm_interleave_f32__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
42166 {
42167     ma_pcm_interleave_f32__reference(dst, src, frameCount, channels);
42168 }
42169
42170 MA_API void ma_pcm_interleave_f32(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
42171 {
42172 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
42173     ma_pcm_interleave_f32__reference(dst, src, frameCount, channels);
42174 #else
42175     ma_pcm_interleave_f32__optimized(dst, src, frameCount, channels);
42176 #endif
42177 }
42178
42179
42180 static void ma_pcm_deinterleave_f32__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
42181 {
42182     float** dst_f32 = (float**)dst;
42183     const float* src_f32 = (const float*)src;
42184
42185     ma_uint64 iFrame;
42186     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
42187         ma_uint32 iChannel;
42188         for (iChannel = 0; iChannel < channels; iChannel += 1) {
42189             dst_f32[iChannel][iFrame] = src_f32[iFrame*channels + iChannel];
42190         }
42191     }
42192 }
42193
42194 static void ma_pcm_deinterleave_f32__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
42195 {
42196     ma_pcm_deinterleave_f32__reference(dst, src, frameCount, channels);
42197 }
42198
42199 MA_API void ma_pcm_deinterleave_f32(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
42200 {
42201 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
42202     ma_pcm_deinterleave_f32__reference(dst, src, frameCount, channels);
42203 #else
42204     ma_pcm_deinterleave_f32__optimized(dst, src, frameCount, channels);
42205 #endif
42206 }
42207
42208
42209 MA_API void ma_pcm_convert(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 sampleCount, ma_dither_mode ditherMode)
42210 {
42211     if (formatOut == formatIn) {
42212         ma_copy_memory_64(pOut, pIn, sampleCount * ma_get_bytes_per_sample(formatOut));
42213         return;
42214     }
42215
42216     switch (formatIn)
42217     {
42218         case ma_format_u8:
42219         {
42220             switch (formatOut)
42221             {
42222                 case ma_format_s16: ma_pcm_u8_to_s16(pOut, pIn, sampleCount, ditherMode); return;
42223                 case ma_format_s24: ma_pcm_u8_to_s24(pOut, pIn, sampleCount, ditherMode); return;
42224                 case ma_format_s32: ma_pcm_u8_to_s32(pOut, pIn, sampleCount, ditherMode); return;
42225                 case ma_format_f32: ma_pcm_u8_to_f32(pOut, pIn, sampleCount, ditherMode); return;
42226                 default: break;
42227             }
42228         } break;
42229
42230         case ma_format_s16:
42231         {
42232             switch (formatOut)
42233             {
42234                 case ma_format_u8:  ma_pcm_s16_to_u8( pOut, pIn, sampleCount, ditherMode); return;
42235                 case ma_format_s24: ma_pcm_s16_to_s24(pOut, pIn, sampleCount, ditherMode); return;
42236                 case ma_format_s32: ma_pcm_s16_to_s32(pOut, pIn, sampleCount, ditherMode); return;
42237                 case ma_format_f32: ma_pcm_s16_to_f32(pOut, pIn, sampleCount, ditherMode); return;
42238                 default: break;
42239             }
42240         } break;
42241
42242         case ma_format_s24:
42243         {
42244             switch (formatOut)
42245             {
42246                 case ma_format_u8:  ma_pcm_s24_to_u8( pOut, pIn, sampleCount, ditherMode); return;
42247                 case ma_format_s16: ma_pcm_s24_to_s16(pOut, pIn, sampleCount, ditherMode); return;
42248                 case ma_format_s32: ma_pcm_s24_to_s32(pOut, pIn, sampleCount, ditherMode); return;
42249                 case ma_format_f32: ma_pcm_s24_to_f32(pOut, pIn, sampleCount, ditherMode); return;
42250                 default: break;
42251             }
42252         } break;
42253
42254         case ma_format_s32:
42255         {
42256             switch (formatOut)
42257             {
42258                 case ma_format_u8:  ma_pcm_s32_to_u8( pOut, pIn, sampleCount, ditherMode); return;
42259                 case ma_format_s16: ma_pcm_s32_to_s16(pOut, pIn, sampleCount, ditherMode); return;
42260                 case ma_format_s24: ma_pcm_s32_to_s24(pOut, pIn, sampleCount, ditherMode); return;
42261                 case ma_format_f32: ma_pcm_s32_to_f32(pOut, pIn, sampleCount, ditherMode); return;
42262                 default: break;
42263             }
42264         } break;
42265
42266         case ma_format_f32:
42267         {
42268             switch (formatOut)
42269             {
42270                 case ma_format_u8:  ma_pcm_f32_to_u8( pOut, pIn, sampleCount, ditherMode); return;
42271                 case ma_format_s16: ma_pcm_f32_to_s16(pOut, pIn, sampleCount, ditherMode); return;
42272                 case ma_format_s24: ma_pcm_f32_to_s24(pOut, pIn, sampleCount, ditherMode); return;
42273                 case ma_format_s32: ma_pcm_f32_to_s32(pOut, pIn, sampleCount, ditherMode); return;
42274                 default: break;
42275             }
42276         } break;
42277
42278         default: break;
42279     }
42280 }
42281
42282 MA_API 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)
42283 {
42284     ma_pcm_convert(pOut, formatOut, pIn, formatIn, frameCount * channels, ditherMode);
42285 }
42286
42287 MA_API void ma_deinterleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void* pInterleavedPCMFrames, void** ppDeinterleavedPCMFrames)
42288 {
42289     if (pInterleavedPCMFrames == NULL || ppDeinterleavedPCMFrames == NULL) {
42290         return; /* Invalid args. */
42291     }
42292
42293     /* For efficiency we do this per format. */
42294     switch (format) {
42295         case ma_format_s16:
42296         {
42297             const ma_int16* pSrcS16 = (const ma_int16*)pInterleavedPCMFrames;
42298             ma_uint64 iPCMFrame;
42299             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
42300                 ma_uint32 iChannel;
42301                 for (iChannel = 0; iChannel < channels; ++iChannel) {
42302                     ma_int16* pDstS16 = (ma_int16*)ppDeinterleavedPCMFrames[iChannel];
42303                     pDstS16[iPCMFrame] = pSrcS16[iPCMFrame*channels+iChannel];
42304                 }
42305             }
42306         } break;
42307
42308         case ma_format_f32:
42309         {
42310             const float* pSrcF32 = (const float*)pInterleavedPCMFrames;
42311             ma_uint64 iPCMFrame;
42312             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
42313                 ma_uint32 iChannel;
42314                 for (iChannel = 0; iChannel < channels; ++iChannel) {
42315                     float* pDstF32 = (float*)ppDeinterleavedPCMFrames[iChannel];
42316                     pDstF32[iPCMFrame] = pSrcF32[iPCMFrame*channels+iChannel];
42317                 }
42318             }
42319         } break;
42320
42321         default:
42322         {
42323             ma_uint32 sampleSizeInBytes = ma_get_bytes_per_sample(format);
42324             ma_uint64 iPCMFrame;
42325             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
42326                 ma_uint32 iChannel;
42327                 for (iChannel = 0; iChannel < channels; ++iChannel) {
42328                           void* pDst = ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel], iPCMFrame*sampleSizeInBytes);
42329                     const void* pSrc = ma_offset_ptr(pInterleavedPCMFrames, (iPCMFrame*channels+iChannel)*sampleSizeInBytes);
42330                     memcpy(pDst, pSrc, sampleSizeInBytes);
42331                 }
42332             }
42333         } break;
42334     }
42335 }
42336
42337 MA_API void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames)
42338 {
42339     switch (format)
42340     {
42341         case ma_format_s16:
42342         {
42343             ma_int16* pDstS16 = (ma_int16*)pInterleavedPCMFrames;
42344             ma_uint64 iPCMFrame;
42345             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
42346                 ma_uint32 iChannel;
42347                 for (iChannel = 0; iChannel < channels; ++iChannel) {
42348                     const ma_int16* pSrcS16 = (const ma_int16*)ppDeinterleavedPCMFrames[iChannel];
42349                     pDstS16[iPCMFrame*channels+iChannel] = pSrcS16[iPCMFrame];
42350                 }
42351             }
42352         } break;
42353
42354         case ma_format_f32:
42355         {
42356             float* pDstF32 = (float*)pInterleavedPCMFrames;
42357             ma_uint64 iPCMFrame;
42358             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
42359                 ma_uint32 iChannel;
42360                 for (iChannel = 0; iChannel < channels; ++iChannel) {
42361                     const float* pSrcF32 = (const float*)ppDeinterleavedPCMFrames[iChannel];
42362                     pDstF32[iPCMFrame*channels+iChannel] = pSrcF32[iPCMFrame];
42363                 }
42364             }
42365         } break;
42366
42367         default:
42368         {
42369             ma_uint32 sampleSizeInBytes = ma_get_bytes_per_sample(format);
42370             ma_uint64 iPCMFrame;
42371             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
42372                 ma_uint32 iChannel;
42373                 for (iChannel = 0; iChannel < channels; ++iChannel) {
42374                           void* pDst = ma_offset_ptr(pInterleavedPCMFrames, (iPCMFrame*channels+iChannel)*sampleSizeInBytes);
42375                     const void* pSrc = ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel], iPCMFrame*sampleSizeInBytes);
42376                     memcpy(pDst, pSrc, sampleSizeInBytes);
42377                 }
42378             }
42379         } break;
42380     }
42381 }
42382
42383
42384 /**************************************************************************************************************************************************************
42385
42386 Biquad Filter
42387
42388 **************************************************************************************************************************************************************/
42389 #ifndef MA_BIQUAD_FIXED_POINT_SHIFT
42390 #define MA_BIQUAD_FIXED_POINT_SHIFT 14
42391 #endif
42392
42393 static ma_int32 ma_biquad_float_to_fp(double x)
42394 {
42395     return (ma_int32)(x * (1 << MA_BIQUAD_FIXED_POINT_SHIFT));
42396 }
42397
42398 MA_API 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)
42399 {
42400     ma_biquad_config config;
42401
42402     MA_ZERO_OBJECT(&config);
42403     config.format = format;
42404     config.channels = channels;
42405     config.b0 = b0;
42406     config.b1 = b1;
42407     config.b2 = b2;
42408     config.a0 = a0;
42409     config.a1 = a1;
42410     config.a2 = a2;
42411
42412     return config;
42413 }
42414
42415
42416 typedef struct
42417 {
42418     size_t sizeInBytes;
42419     size_t r1Offset;
42420     size_t r2Offset;
42421 } ma_biquad_heap_layout;
42422
42423 static ma_result ma_biquad_get_heap_layout(const ma_biquad_config* pConfig, ma_biquad_heap_layout* pHeapLayout)
42424 {
42425     MA_ASSERT(pHeapLayout != NULL);
42426
42427     MA_ZERO_OBJECT(pHeapLayout);
42428
42429     if (pConfig == NULL) {
42430         return MA_INVALID_ARGS;
42431     }
42432
42433     if (pConfig->channels == 0) {
42434         return MA_INVALID_ARGS;
42435     }
42436
42437     pHeapLayout->sizeInBytes = 0;
42438
42439     /* R0 */
42440     pHeapLayout->r1Offset = pHeapLayout->sizeInBytes;
42441     pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels;
42442
42443     /* R1 */
42444     pHeapLayout->r2Offset = pHeapLayout->sizeInBytes;
42445     pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels;
42446
42447     /* Make sure allocation size is aligned. */
42448     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
42449
42450     return MA_SUCCESS;
42451 }
42452
42453 MA_API ma_result ma_biquad_get_heap_size(const ma_biquad_config* pConfig, size_t* pHeapSizeInBytes)
42454 {
42455     ma_result result;
42456     ma_biquad_heap_layout heapLayout;
42457
42458     if (pHeapSizeInBytes == NULL) {
42459         return MA_INVALID_ARGS;
42460     }
42461
42462     *pHeapSizeInBytes = 0;
42463
42464     result = ma_biquad_get_heap_layout(pConfig, &heapLayout);
42465     if (result != MA_SUCCESS) {
42466         return result;
42467     }
42468
42469     *pHeapSizeInBytes = heapLayout.sizeInBytes;
42470
42471     return MA_SUCCESS;
42472 }
42473
42474 MA_API ma_result ma_biquad_init_preallocated(const ma_biquad_config* pConfig, void* pHeap, ma_biquad* pBQ)
42475 {
42476     ma_result result;
42477     ma_biquad_heap_layout heapLayout;
42478
42479     if (pBQ == NULL) {
42480         return MA_INVALID_ARGS;
42481     }
42482
42483     MA_ZERO_OBJECT(pBQ);
42484
42485     result = ma_biquad_get_heap_layout(pConfig, &heapLayout);
42486     if (result != MA_SUCCESS) {
42487         return result;
42488     }
42489
42490     pBQ->_pHeap = pHeap;
42491     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
42492
42493     pBQ->pR1 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r1Offset);
42494     pBQ->pR2 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r2Offset);
42495
42496     return ma_biquad_reinit(pConfig, pBQ);
42497 }
42498
42499 MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad* pBQ)
42500 {
42501     ma_result result;
42502     size_t heapSizeInBytes;
42503     void* pHeap;
42504
42505     result = ma_biquad_get_heap_size(pConfig, &heapSizeInBytes);
42506     if (result != MA_SUCCESS) {
42507         return result;
42508     }
42509
42510     if (heapSizeInBytes > 0) {
42511         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
42512         if (pHeap == NULL) {
42513             return MA_OUT_OF_MEMORY;
42514         }
42515     } else {
42516         pHeap = NULL;
42517     }
42518
42519     result = ma_biquad_init_preallocated(pConfig, pHeap, pBQ);
42520     if (result != MA_SUCCESS) {
42521         ma_free(pHeap, pAllocationCallbacks);
42522         return result;
42523     }
42524
42525     pBQ->_ownsHeap = MA_TRUE;
42526     return MA_SUCCESS;
42527 }
42528
42529 MA_API void ma_biquad_uninit(ma_biquad* pBQ, const ma_allocation_callbacks* pAllocationCallbacks)
42530 {
42531     if (pBQ == NULL) {
42532         return;
42533     }
42534
42535     if (pBQ->_ownsHeap) {
42536         ma_free(pBQ->_pHeap, pAllocationCallbacks);
42537     }
42538 }
42539
42540 MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pBQ)
42541 {
42542     if (pBQ == NULL || pConfig == NULL) {
42543         return MA_INVALID_ARGS;
42544     }
42545
42546     if (pConfig->a0 == 0) {
42547         return MA_INVALID_ARGS; /* Division by zero. */
42548     }
42549
42550     /* Only supporting f32 and s16. */
42551     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
42552         return MA_INVALID_ARGS;
42553     }
42554
42555     /* The format cannot be changed after initialization. */
42556     if (pBQ->format != ma_format_unknown && pBQ->format != pConfig->format) {
42557         return MA_INVALID_OPERATION;
42558     }
42559
42560     /* The channel count cannot be changed after initialization. */
42561     if (pBQ->channels != 0 && pBQ->channels != pConfig->channels) {
42562         return MA_INVALID_OPERATION;
42563     }
42564
42565
42566     pBQ->format   = pConfig->format;
42567     pBQ->channels = pConfig->channels;
42568
42569     /* Normalize. */
42570     if (pConfig->format == ma_format_f32) {
42571         pBQ->b0.f32 = (float)(pConfig->b0 / pConfig->a0);
42572         pBQ->b1.f32 = (float)(pConfig->b1 / pConfig->a0);
42573         pBQ->b2.f32 = (float)(pConfig->b2 / pConfig->a0);
42574         pBQ->a1.f32 = (float)(pConfig->a1 / pConfig->a0);
42575         pBQ->a2.f32 = (float)(pConfig->a2 / pConfig->a0);
42576     } else {
42577         pBQ->b0.s32 = ma_biquad_float_to_fp(pConfig->b0 / pConfig->a0);
42578         pBQ->b1.s32 = ma_biquad_float_to_fp(pConfig->b1 / pConfig->a0);
42579         pBQ->b2.s32 = ma_biquad_float_to_fp(pConfig->b2 / pConfig->a0);
42580         pBQ->a1.s32 = ma_biquad_float_to_fp(pConfig->a1 / pConfig->a0);
42581         pBQ->a2.s32 = ma_biquad_float_to_fp(pConfig->a2 / pConfig->a0);
42582     }
42583
42584     return MA_SUCCESS;
42585 }
42586
42587 static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(ma_biquad* pBQ, float* pY, const float* pX)
42588 {
42589     ma_uint32 c;
42590     const ma_uint32 channels = pBQ->channels;
42591     const float b0 = pBQ->b0.f32;
42592     const float b1 = pBQ->b1.f32;
42593     const float b2 = pBQ->b2.f32;
42594     const float a1 = pBQ->a1.f32;
42595     const float a2 = pBQ->a2.f32;
42596
42597     MA_ASSUME(channels > 0);
42598     for (c = 0; c < channels; c += 1) {
42599         float r1 = pBQ->pR1[c].f32;
42600         float r2 = pBQ->pR2[c].f32;
42601         float x  = pX[c];
42602         float y;
42603
42604         y  = b0*x        + r1;
42605         r1 = b1*x - a1*y + r2;
42606         r2 = b2*x - a2*y;
42607
42608         pY[c]           = y;
42609         pBQ->pR1[c].f32 = r1;
42610         pBQ->pR2[c].f32 = r2;
42611     }
42612 }
42613
42614 static MA_INLINE void ma_biquad_process_pcm_frame_f32(ma_biquad* pBQ, float* pY, const float* pX)
42615 {
42616     ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(pBQ, pY, pX);
42617 }
42618
42619 static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(ma_biquad* pBQ, ma_int16* pY, const ma_int16* pX)
42620 {
42621     ma_uint32 c;
42622     const ma_uint32 channels = pBQ->channels;
42623     const ma_int32 b0 = pBQ->b0.s32;
42624     const ma_int32 b1 = pBQ->b1.s32;
42625     const ma_int32 b2 = pBQ->b2.s32;
42626     const ma_int32 a1 = pBQ->a1.s32;
42627     const ma_int32 a2 = pBQ->a2.s32;
42628
42629     MA_ASSUME(channels > 0);
42630     for (c = 0; c < channels; c += 1) {
42631         ma_int32 r1 = pBQ->pR1[c].s32;
42632         ma_int32 r2 = pBQ->pR2[c].s32;
42633         ma_int32 x  = pX[c];
42634         ma_int32 y;
42635
42636         y  = (b0*x        + r1) >> MA_BIQUAD_FIXED_POINT_SHIFT;
42637         r1 = (b1*x - a1*y + r2);
42638         r2 = (b2*x - a2*y);
42639
42640         pY[c]           = (ma_int16)ma_clamp(y, -32768, 32767);
42641         pBQ->pR1[c].s32 = r1;
42642         pBQ->pR2[c].s32 = r2;
42643     }
42644 }
42645
42646 static MA_INLINE void ma_biquad_process_pcm_frame_s16(ma_biquad* pBQ, ma_int16* pY, const ma_int16* pX)
42647 {
42648     ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(pBQ, pY, pX);
42649 }
42650
42651 MA_API ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
42652 {
42653     ma_uint32 n;
42654
42655     if (pBQ == NULL || pFramesOut == NULL || pFramesIn == NULL) {
42656         return MA_INVALID_ARGS;
42657     }
42658
42659     /* 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. */
42660
42661     if (pBQ->format == ma_format_f32) {
42662         /* */ float* pY = (      float*)pFramesOut;
42663         const float* pX = (const float*)pFramesIn;
42664
42665         for (n = 0; n < frameCount; n += 1) {
42666             ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(pBQ, pY, pX);
42667             pY += pBQ->channels;
42668             pX += pBQ->channels;
42669         }
42670     } else if (pBQ->format == ma_format_s16) {
42671         /* */ ma_int16* pY = (      ma_int16*)pFramesOut;
42672         const ma_int16* pX = (const ma_int16*)pFramesIn;
42673
42674         for (n = 0; n < frameCount; n += 1) {
42675             ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(pBQ, pY, pX);
42676             pY += pBQ->channels;
42677             pX += pBQ->channels;
42678         }
42679     } else {
42680         MA_ASSERT(MA_FALSE);
42681         return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */
42682     }
42683
42684     return MA_SUCCESS;
42685 }
42686
42687 MA_API ma_uint32 ma_biquad_get_latency(const ma_biquad* pBQ)
42688 {
42689     if (pBQ == NULL) {
42690         return 0;
42691     }
42692
42693     return 2;
42694 }
42695
42696
42697 /**************************************************************************************************************************************************************
42698
42699 Low-Pass Filter
42700
42701 **************************************************************************************************************************************************************/
42702 MA_API ma_lpf1_config ma_lpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency)
42703 {
42704     ma_lpf1_config config;
42705
42706     MA_ZERO_OBJECT(&config);
42707     config.format = format;
42708     config.channels = channels;
42709     config.sampleRate = sampleRate;
42710     config.cutoffFrequency = cutoffFrequency;
42711     config.q = 0.5;
42712
42713     return config;
42714 }
42715
42716 MA_API ma_lpf2_config ma_lpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
42717 {
42718     ma_lpf2_config config;
42719
42720     MA_ZERO_OBJECT(&config);
42721     config.format = format;
42722     config.channels = channels;
42723     config.sampleRate = sampleRate;
42724     config.cutoffFrequency = cutoffFrequency;
42725     config.q = q;
42726
42727     /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */
42728     if (config.q == 0) {
42729         config.q = 0.707107;
42730     }
42731
42732     return config;
42733 }
42734
42735
42736 typedef struct
42737 {
42738     size_t sizeInBytes;
42739     size_t r1Offset;
42740 } ma_lpf1_heap_layout;
42741
42742 static ma_result ma_lpf1_get_heap_layout(const ma_lpf1_config* pConfig, ma_lpf1_heap_layout* pHeapLayout)
42743 {
42744     MA_ASSERT(pHeapLayout != NULL);
42745
42746     MA_ZERO_OBJECT(pHeapLayout);
42747
42748     if (pConfig == NULL) {
42749         return MA_INVALID_ARGS;
42750     }
42751
42752     if (pConfig->channels == 0) {
42753         return MA_INVALID_ARGS;
42754     }
42755
42756     pHeapLayout->sizeInBytes = 0;
42757
42758     /* R1 */
42759     pHeapLayout->r1Offset = pHeapLayout->sizeInBytes;
42760     pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels;
42761
42762     /* Make sure allocation size is aligned. */
42763     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
42764
42765     return MA_SUCCESS;
42766 }
42767
42768 MA_API ma_result ma_lpf1_get_heap_size(const ma_lpf1_config* pConfig, size_t* pHeapSizeInBytes)
42769 {
42770     ma_result result;
42771     ma_lpf1_heap_layout heapLayout;
42772
42773     if (pHeapSizeInBytes == NULL) {
42774         return MA_INVALID_ARGS;
42775     }
42776
42777     result = ma_lpf1_get_heap_layout(pConfig, &heapLayout);
42778     if (result != MA_SUCCESS) {
42779         return result;
42780     }
42781
42782     *pHeapSizeInBytes = heapLayout.sizeInBytes;
42783
42784     return MA_SUCCESS;
42785 }
42786
42787 MA_API ma_result ma_lpf1_init_preallocated(const ma_lpf1_config* pConfig, void* pHeap, ma_lpf1* pLPF)
42788 {
42789     ma_result result;
42790     ma_lpf1_heap_layout heapLayout;
42791
42792     if (pLPF == NULL) {
42793         return MA_INVALID_ARGS;
42794     }
42795
42796     MA_ZERO_OBJECT(pLPF);
42797
42798     result = ma_lpf1_get_heap_layout(pConfig, &heapLayout);
42799     if (result != MA_SUCCESS) {
42800         return result;
42801     }
42802
42803     pLPF->_pHeap = pHeap;
42804     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
42805
42806     pLPF->pR1 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r1Offset);
42807
42808     return ma_lpf1_reinit(pConfig, pLPF);
42809 }
42810
42811 MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf1* pLPF)
42812 {
42813     ma_result result;
42814     size_t heapSizeInBytes;
42815     void* pHeap;
42816
42817     result = ma_lpf1_get_heap_size(pConfig, &heapSizeInBytes);
42818     if (result != MA_SUCCESS) {
42819         return result;
42820     }
42821
42822     if (heapSizeInBytes > 0) {
42823         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
42824         if (pHeap == NULL) {
42825             return MA_OUT_OF_MEMORY;
42826         }
42827     } else {
42828         pHeap = NULL;
42829     }
42830
42831     result = ma_lpf1_init_preallocated(pConfig, pHeap, pLPF);
42832     if (result != MA_SUCCESS) {
42833         ma_free(pHeap, pAllocationCallbacks);
42834         return result;
42835     }
42836
42837     pLPF->_ownsHeap = MA_TRUE;
42838     return MA_SUCCESS;
42839 }
42840
42841 MA_API void ma_lpf1_uninit(ma_lpf1* pLPF, const ma_allocation_callbacks* pAllocationCallbacks)
42842 {
42843     if (pLPF == NULL) {
42844         return;
42845     }
42846
42847     if (pLPF->_ownsHeap) {
42848         ma_free(pLPF->_pHeap, pAllocationCallbacks);
42849     }
42850 }
42851
42852 MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF)
42853 {
42854     double a;
42855
42856     if (pLPF == NULL || pConfig == NULL) {
42857         return MA_INVALID_ARGS;
42858     }
42859
42860     /* Only supporting f32 and s16. */
42861     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
42862         return MA_INVALID_ARGS;
42863     }
42864
42865     /* The format cannot be changed after initialization. */
42866     if (pLPF->format != ma_format_unknown && pLPF->format != pConfig->format) {
42867         return MA_INVALID_OPERATION;
42868     }
42869
42870     /* The channel count cannot be changed after initialization. */
42871     if (pLPF->channels != 0 && pLPF->channels != pConfig->channels) {
42872         return MA_INVALID_OPERATION;
42873     }
42874
42875     pLPF->format   = pConfig->format;
42876     pLPF->channels = pConfig->channels;
42877
42878     a = ma_expd(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate);
42879     if (pConfig->format == ma_format_f32) {
42880         pLPF->a.f32 = (float)a;
42881     } else {
42882         pLPF->a.s32 = ma_biquad_float_to_fp(a);
42883     }
42884
42885     return MA_SUCCESS;
42886 }
42887
42888 static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, const float* pX)
42889 {
42890     ma_uint32 c;
42891     const ma_uint32 channels = pLPF->channels;
42892     const float a = pLPF->a.f32;
42893     const float b = 1 - a;
42894
42895     MA_ASSUME(channels > 0);
42896     for (c = 0; c < channels; c += 1) {
42897         float r1 = pLPF->pR1[c].f32;
42898         float x  = pX[c];
42899         float y;
42900
42901         y = b*x + a*r1;
42902
42903         pY[c]           = y;
42904         pLPF->pR1[c].f32 = y;
42905     }
42906 }
42907
42908 static MA_INLINE void ma_lpf1_process_pcm_frame_s16(ma_lpf1* pLPF, ma_int16* pY, const ma_int16* pX)
42909 {
42910     ma_uint32 c;
42911     const ma_uint32 channels = pLPF->channels;
42912     const ma_int32 a = pLPF->a.s32;
42913     const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a);
42914
42915     MA_ASSUME(channels > 0);
42916     for (c = 0; c < channels; c += 1) {
42917         ma_int32 r1 = pLPF->pR1[c].s32;
42918         ma_int32 x  = pX[c];
42919         ma_int32 y;
42920
42921         y = (b*x + a*r1) >> MA_BIQUAD_FIXED_POINT_SHIFT;
42922
42923         pY[c]            = (ma_int16)y;
42924         pLPF->pR1[c].s32 = (ma_int32)y;
42925     }
42926 }
42927
42928 MA_API ma_result ma_lpf1_process_pcm_frames(ma_lpf1* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
42929 {
42930     ma_uint32 n;
42931
42932     if (pLPF == NULL || pFramesOut == NULL || pFramesIn == NULL) {
42933         return MA_INVALID_ARGS;
42934     }
42935
42936     /* 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. */
42937
42938     if (pLPF->format == ma_format_f32) {
42939         /* */ float* pY = (      float*)pFramesOut;
42940         const float* pX = (const float*)pFramesIn;
42941
42942         for (n = 0; n < frameCount; n += 1) {
42943             ma_lpf1_process_pcm_frame_f32(pLPF, pY, pX);
42944             pY += pLPF->channels;
42945             pX += pLPF->channels;
42946         }
42947     } else if (pLPF->format == ma_format_s16) {
42948         /* */ ma_int16* pY = (      ma_int16*)pFramesOut;
42949         const ma_int16* pX = (const ma_int16*)pFramesIn;
42950
42951         for (n = 0; n < frameCount; n += 1) {
42952             ma_lpf1_process_pcm_frame_s16(pLPF, pY, pX);
42953             pY += pLPF->channels;
42954             pX += pLPF->channels;
42955         }
42956     } else {
42957         MA_ASSERT(MA_FALSE);
42958         return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */
42959     }
42960
42961     return MA_SUCCESS;
42962 }
42963
42964 MA_API ma_uint32 ma_lpf1_get_latency(const ma_lpf1* pLPF)
42965 {
42966     if (pLPF == NULL) {
42967         return 0;
42968     }
42969
42970     return 1;
42971 }
42972
42973
42974 static MA_INLINE ma_biquad_config ma_lpf2__get_biquad_config(const ma_lpf2_config* pConfig)
42975 {
42976     ma_biquad_config bqConfig;
42977     double q;
42978     double w;
42979     double s;
42980     double c;
42981     double a;
42982
42983     MA_ASSERT(pConfig != NULL);
42984
42985     q = pConfig->q;
42986     w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
42987     s = ma_sind(w);
42988     c = ma_cosd(w);
42989     a = s / (2*q);
42990
42991     bqConfig.b0 = (1 - c) / 2;
42992     bqConfig.b1 =  1 - c;
42993     bqConfig.b2 = (1 - c) / 2;
42994     bqConfig.a0 =  1 + a;
42995     bqConfig.a1 = -2 * c;
42996     bqConfig.a2 =  1 - a;
42997
42998     bqConfig.format   = pConfig->format;
42999     bqConfig.channels = pConfig->channels;
43000
43001     return bqConfig;
43002 }
43003
43004 MA_API ma_result ma_lpf2_get_heap_size(const ma_lpf2_config* pConfig, size_t* pHeapSizeInBytes)
43005 {
43006     ma_biquad_config bqConfig;
43007     bqConfig = ma_lpf2__get_biquad_config(pConfig);
43008
43009     return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes);
43010 }
43011
43012 MA_API ma_result ma_lpf2_init_preallocated(const ma_lpf2_config* pConfig, void* pHeap, ma_lpf2* pLPF)
43013 {
43014     ma_result result;
43015     ma_biquad_config bqConfig;
43016
43017     if (pLPF == NULL) {
43018         return MA_INVALID_ARGS;
43019     }
43020
43021     MA_ZERO_OBJECT(pLPF);
43022
43023     if (pConfig == NULL) {
43024         return MA_INVALID_ARGS;
43025     }
43026
43027     bqConfig = ma_lpf2__get_biquad_config(pConfig);
43028     result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pLPF->bq);
43029     if (result != MA_SUCCESS) {
43030         return result;
43031     }
43032
43033     return MA_SUCCESS;
43034 }
43035
43036 MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf2* pLPF)
43037 {
43038     ma_result result;
43039     size_t heapSizeInBytes;
43040     void* pHeap;
43041
43042     result = ma_lpf2_get_heap_size(pConfig, &heapSizeInBytes);
43043     if (result != MA_SUCCESS) {
43044         return result;
43045     }
43046
43047     if (heapSizeInBytes > 0) {
43048         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
43049         if (pHeap == NULL) {
43050             return MA_OUT_OF_MEMORY;
43051         }
43052     } else {
43053         pHeap = NULL;
43054     }
43055
43056     result = ma_lpf2_init_preallocated(pConfig, pHeap, pLPF);
43057     if (result != MA_SUCCESS) {
43058         ma_free(pHeap, pAllocationCallbacks);
43059         return result;
43060     }
43061
43062     pLPF->bq._ownsHeap = MA_TRUE;    /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */
43063     return MA_SUCCESS;
43064 }
43065
43066 MA_API void ma_lpf2_uninit(ma_lpf2* pLPF, const ma_allocation_callbacks* pAllocationCallbacks)
43067 {
43068     if (pLPF == NULL) {
43069         return;
43070     }
43071
43072     ma_biquad_uninit(&pLPF->bq, pAllocationCallbacks);   /* <-- This will free the heap allocation. */
43073 }
43074
43075 MA_API ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF)
43076 {
43077     ma_result result;
43078     ma_biquad_config bqConfig;
43079
43080     if (pLPF == NULL || pConfig == NULL) {
43081         return MA_INVALID_ARGS;
43082     }
43083
43084     bqConfig = ma_lpf2__get_biquad_config(pConfig);
43085     result = ma_biquad_reinit(&bqConfig, &pLPF->bq);
43086     if (result != MA_SUCCESS) {
43087         return result;
43088     }
43089
43090     return MA_SUCCESS;
43091 }
43092
43093 static MA_INLINE void ma_lpf2_process_pcm_frame_s16(ma_lpf2* pLPF, ma_int16* pFrameOut, const ma_int16* pFrameIn)
43094 {
43095     ma_biquad_process_pcm_frame_s16(&pLPF->bq, pFrameOut, pFrameIn);
43096 }
43097
43098 static MA_INLINE void ma_lpf2_process_pcm_frame_f32(ma_lpf2* pLPF, float* pFrameOut, const float* pFrameIn)
43099 {
43100     ma_biquad_process_pcm_frame_f32(&pLPF->bq, pFrameOut, pFrameIn);
43101 }
43102
43103 MA_API ma_result ma_lpf2_process_pcm_frames(ma_lpf2* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
43104 {
43105     if (pLPF == NULL) {
43106         return MA_INVALID_ARGS;
43107     }
43108
43109     return ma_biquad_process_pcm_frames(&pLPF->bq, pFramesOut, pFramesIn, frameCount);
43110 }
43111
43112 MA_API ma_uint32 ma_lpf2_get_latency(const ma_lpf2* pLPF)
43113 {
43114     if (pLPF == NULL) {
43115         return 0;
43116     }
43117
43118     return ma_biquad_get_latency(&pLPF->bq);
43119 }
43120
43121
43122 MA_API ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
43123 {
43124     ma_lpf_config config;
43125
43126     MA_ZERO_OBJECT(&config);
43127     config.format          = format;
43128     config.channels        = channels;
43129     config.sampleRate      = sampleRate;
43130     config.cutoffFrequency = cutoffFrequency;
43131     config.order           = ma_min(order, MA_MAX_FILTER_ORDER);
43132
43133     return config;
43134 }
43135
43136
43137 typedef struct
43138 {
43139     size_t sizeInBytes;
43140     size_t lpf1Offset;
43141     size_t lpf2Offset;  /* Offset of the first second order filter. Subsequent filters will come straight after, and will each have the same heap size. */
43142 } ma_lpf_heap_layout;
43143
43144 static void ma_lpf_calculate_sub_lpf_counts(ma_uint32 order, ma_uint32* pLPF1Count, ma_uint32* pLPF2Count)
43145 {
43146     MA_ASSERT(pLPF1Count != NULL);
43147     MA_ASSERT(pLPF2Count != NULL);
43148
43149     *pLPF1Count = order % 2;
43150     *pLPF2Count = order / 2;
43151 }
43152
43153 static ma_result ma_lpf_get_heap_layout(const ma_lpf_config* pConfig, ma_lpf_heap_layout* pHeapLayout)
43154 {
43155     ma_result result;
43156     ma_uint32 lpf1Count;
43157     ma_uint32 lpf2Count;
43158     ma_uint32 ilpf1;
43159     ma_uint32 ilpf2;
43160
43161     MA_ASSERT(pHeapLayout != NULL);
43162
43163     MA_ZERO_OBJECT(pHeapLayout);
43164
43165     if (pConfig == NULL) {
43166         return MA_INVALID_ARGS;
43167     }
43168
43169     if (pConfig->channels == 0) {
43170         return MA_INVALID_ARGS;
43171     }
43172
43173     if (pConfig->order > MA_MAX_FILTER_ORDER) {
43174         return MA_INVALID_ARGS;
43175     }
43176
43177     ma_lpf_calculate_sub_lpf_counts(pConfig->order, &lpf1Count, &lpf2Count);
43178
43179     pHeapLayout->sizeInBytes = 0;
43180
43181     /* LPF 1 */
43182     pHeapLayout->lpf1Offset = pHeapLayout->sizeInBytes;
43183     for (ilpf1 = 0; ilpf1 < lpf1Count; ilpf1 += 1) {
43184         size_t lpf1HeapSizeInBytes;
43185         ma_lpf1_config lpf1Config = ma_lpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency);
43186
43187         result = ma_lpf1_get_heap_size(&lpf1Config, &lpf1HeapSizeInBytes);
43188         if (result != MA_SUCCESS) {
43189             return result;
43190         }
43191
43192         pHeapLayout->sizeInBytes += sizeof(ma_lpf1) + lpf1HeapSizeInBytes;
43193     }
43194
43195     /* LPF 2*/
43196     pHeapLayout->lpf2Offset = pHeapLayout->sizeInBytes;
43197     for (ilpf2 = 0; ilpf2 < lpf2Count; ilpf2 += 1) {
43198         size_t lpf2HeapSizeInBytes;
43199         ma_lpf2_config lpf2Config = ma_lpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, 0.707107);   /* <-- The "q" parameter does not matter for the purpose of calculating the heap size. */
43200
43201         result = ma_lpf2_get_heap_size(&lpf2Config, &lpf2HeapSizeInBytes);
43202         if (result != MA_SUCCESS) {
43203             return result;
43204         }
43205
43206         pHeapLayout->sizeInBytes += sizeof(ma_lpf2) + lpf2HeapSizeInBytes;
43207     }
43208
43209     /* Make sure allocation size is aligned. */
43210     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
43211
43212     return MA_SUCCESS;
43213 }
43214
43215 static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, void* pHeap, ma_lpf* pLPF, ma_bool32 isNew)
43216 {
43217     ma_result result;
43218     ma_uint32 lpf1Count;
43219     ma_uint32 lpf2Count;
43220     ma_uint32 ilpf1;
43221     ma_uint32 ilpf2;
43222     ma_lpf_heap_layout heapLayout;  /* Only used if isNew is true. */
43223
43224     if (pLPF == NULL || pConfig == NULL) {
43225         return MA_INVALID_ARGS;
43226     }
43227
43228     /* Only supporting f32 and s16. */
43229     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
43230         return MA_INVALID_ARGS;
43231     }
43232
43233     /* The format cannot be changed after initialization. */
43234     if (pLPF->format != ma_format_unknown && pLPF->format != pConfig->format) {
43235         return MA_INVALID_OPERATION;
43236     }
43237
43238     /* The channel count cannot be changed after initialization. */
43239     if (pLPF->channels != 0 && pLPF->channels != pConfig->channels) {
43240         return MA_INVALID_OPERATION;
43241     }
43242
43243     if (pConfig->order > MA_MAX_FILTER_ORDER) {
43244         return MA_INVALID_ARGS;
43245     }
43246
43247     ma_lpf_calculate_sub_lpf_counts(pConfig->order, &lpf1Count, &lpf2Count);
43248
43249     /* The filter order can't change between reinits. */
43250     if (!isNew) {
43251         if (pLPF->lpf1Count != lpf1Count || pLPF->lpf2Count != lpf2Count) {
43252             return MA_INVALID_OPERATION;
43253         }
43254     }
43255
43256     if (isNew) {
43257         result = ma_lpf_get_heap_layout(pConfig, &heapLayout);
43258         if (result != MA_SUCCESS) {
43259             return result;
43260         }
43261
43262         pLPF->_pHeap = pHeap;
43263         MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
43264
43265         pLPF->pLPF1 = (ma_lpf1*)ma_offset_ptr(pHeap, heapLayout.lpf1Offset);
43266         pLPF->pLPF2 = (ma_lpf2*)ma_offset_ptr(pHeap, heapLayout.lpf2Offset);
43267     } else {
43268         MA_ZERO_OBJECT(&heapLayout);    /* To silence a compiler warning. */
43269     }
43270
43271     for (ilpf1 = 0; ilpf1 < lpf1Count; ilpf1 += 1) {
43272         ma_lpf1_config lpf1Config = ma_lpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency);
43273
43274         if (isNew) {
43275             size_t lpf1HeapSizeInBytes;
43276
43277             result = ma_lpf1_get_heap_size(&lpf1Config, &lpf1HeapSizeInBytes);
43278             if (result == MA_SUCCESS) {
43279                 result = ma_lpf1_init_preallocated(&lpf1Config, ma_offset_ptr(pHeap, heapLayout.lpf1Offset + (sizeof(ma_lpf1) * lpf1Count) + (ilpf1 * lpf1HeapSizeInBytes)), &pLPF->pLPF1[ilpf1]);
43280             }
43281         } else {
43282             result = ma_lpf1_reinit(&lpf1Config, &pLPF->pLPF1[ilpf1]);
43283         }
43284
43285         if (result != MA_SUCCESS) {
43286             ma_uint32 jlpf1;
43287
43288             for (jlpf1 = 0; jlpf1 < ilpf1; jlpf1 += 1) {
43289                 ma_lpf1_uninit(&pLPF->pLPF1[jlpf1], NULL);  /* No need for allocation callbacks here since we used a preallocated heap allocation. */
43290             }
43291
43292             return result;
43293         }
43294     }
43295
43296     for (ilpf2 = 0; ilpf2 < lpf2Count; ilpf2 += 1) {
43297         ma_lpf2_config lpf2Config;
43298         double q;
43299         double a;
43300
43301         /* Tempting to use 0.707107, but won't result in a Butterworth filter if the order is > 2. */
43302         if (lpf1Count == 1) {
43303             a = (1 + ilpf2*1) * (MA_PI_D/(pConfig->order*1));   /* Odd order. */
43304         } else {
43305             a = (1 + ilpf2*2) * (MA_PI_D/(pConfig->order*2));   /* Even order. */
43306         }
43307         q = 1 / (2*ma_cosd(a));
43308
43309         lpf2Config = ma_lpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q);
43310
43311         if (isNew) {
43312             size_t lpf2HeapSizeInBytes;
43313
43314             result = ma_lpf2_get_heap_size(&lpf2Config, &lpf2HeapSizeInBytes);
43315             if (result == MA_SUCCESS) {
43316                 result = ma_lpf2_init_preallocated(&lpf2Config, ma_offset_ptr(pHeap, heapLayout.lpf2Offset + (sizeof(ma_lpf2) * lpf2Count) + (ilpf2 * lpf2HeapSizeInBytes)), &pLPF->pLPF2[ilpf2]);
43317             }
43318         } else {
43319             result = ma_lpf2_reinit(&lpf2Config, &pLPF->pLPF2[ilpf2]);
43320         }
43321
43322         if (result != MA_SUCCESS) {
43323             ma_uint32 jlpf1;
43324             ma_uint32 jlpf2;
43325
43326             for (jlpf1 = 0; jlpf1 < lpf1Count; jlpf1 += 1) {
43327                 ma_lpf1_uninit(&pLPF->pLPF1[jlpf1], NULL);  /* No need for allocation callbacks here since we used a preallocated heap allocation. */
43328             }
43329
43330             for (jlpf2 = 0; jlpf2 < ilpf2; jlpf2 += 1) {
43331                 ma_lpf2_uninit(&pLPF->pLPF2[jlpf2], NULL);  /* No need for allocation callbacks here since we used a preallocated heap allocation. */
43332             }
43333
43334             return result;
43335         }
43336     }
43337
43338     pLPF->lpf1Count  = lpf1Count;
43339     pLPF->lpf2Count  = lpf2Count;
43340     pLPF->format     = pConfig->format;
43341     pLPF->channels   = pConfig->channels;
43342     pLPF->sampleRate = pConfig->sampleRate;
43343
43344     return MA_SUCCESS;
43345 }
43346
43347 MA_API ma_result ma_lpf_get_heap_size(const ma_lpf_config* pConfig, size_t* pHeapSizeInBytes)
43348 {
43349     ma_result result;
43350     ma_lpf_heap_layout heapLayout;
43351
43352     if (pHeapSizeInBytes == NULL) {
43353         return MA_INVALID_ARGS;
43354     }
43355
43356     *pHeapSizeInBytes = 0;
43357
43358     result = ma_lpf_get_heap_layout(pConfig, &heapLayout);
43359     if (result != MA_SUCCESS) {
43360         return result;
43361     }
43362
43363     *pHeapSizeInBytes = heapLayout.sizeInBytes;
43364
43365     return result;
43366 }
43367
43368 MA_API ma_result ma_lpf_init_preallocated(const ma_lpf_config* pConfig, void* pHeap, ma_lpf* pLPF)
43369 {
43370     if (pLPF == NULL) {
43371         return MA_INVALID_ARGS;
43372     }
43373
43374     MA_ZERO_OBJECT(pLPF);
43375
43376     return ma_lpf_reinit__internal(pConfig, pHeap, pLPF, /*isNew*/MA_TRUE);
43377 }
43378
43379 MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf* pLPF)
43380 {
43381     ma_result result;
43382     size_t heapSizeInBytes;
43383     void* pHeap;
43384
43385     result = ma_lpf_get_heap_size(pConfig, &heapSizeInBytes);
43386     if (result != MA_SUCCESS) {
43387         return result;
43388     }
43389
43390     if (heapSizeInBytes > 0) {
43391         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
43392         if (pHeap == NULL) {
43393             return MA_OUT_OF_MEMORY;
43394         }
43395     } else {
43396         pHeap = NULL;
43397     }
43398
43399     result = ma_lpf_init_preallocated(pConfig, pHeap, pLPF);
43400     if (result != MA_SUCCESS) {
43401         ma_free(pHeap, pAllocationCallbacks);
43402         return result;
43403     }
43404
43405     pLPF->_ownsHeap = MA_TRUE;
43406     return MA_SUCCESS;
43407 }
43408
43409 MA_API void ma_lpf_uninit(ma_lpf* pLPF, const ma_allocation_callbacks* pAllocationCallbacks)
43410 {
43411     ma_uint32 ilpf1;
43412     ma_uint32 ilpf2;
43413
43414     if (pLPF == NULL) {
43415         return;
43416     }
43417
43418     for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) {
43419         ma_lpf1_uninit(&pLPF->pLPF1[ilpf1], pAllocationCallbacks);
43420     }
43421
43422     for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) {
43423         ma_lpf2_uninit(&pLPF->pLPF2[ilpf2], pAllocationCallbacks);
43424     }
43425 }
43426
43427 MA_API ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF)
43428 {
43429     return ma_lpf_reinit__internal(pConfig, NULL, pLPF, /*isNew*/MA_FALSE);
43430 }
43431
43432 static MA_INLINE void ma_lpf_process_pcm_frame_f32(ma_lpf* pLPF, float* pY, const void* pX)
43433 {
43434     ma_uint32 ilpf1;
43435     ma_uint32 ilpf2;
43436
43437     MA_ASSERT(pLPF->format == ma_format_f32);
43438
43439     MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels));
43440
43441     for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) {
43442         ma_lpf1_process_pcm_frame_f32(&pLPF->pLPF1[ilpf1], pY, pY);
43443     }
43444
43445     for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) {
43446         ma_lpf2_process_pcm_frame_f32(&pLPF->pLPF2[ilpf2], pY, pY);
43447     }
43448 }
43449
43450 static MA_INLINE void ma_lpf_process_pcm_frame_s16(ma_lpf* pLPF, ma_int16* pY, const ma_int16* pX)
43451 {
43452     ma_uint32 ilpf1;
43453     ma_uint32 ilpf2;
43454
43455     MA_ASSERT(pLPF->format == ma_format_s16);
43456
43457     MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels));
43458
43459     for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) {
43460         ma_lpf1_process_pcm_frame_s16(&pLPF->pLPF1[ilpf1], pY, pY);
43461     }
43462
43463     for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) {
43464         ma_lpf2_process_pcm_frame_s16(&pLPF->pLPF2[ilpf2], pY, pY);
43465     }
43466 }
43467
43468 MA_API ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
43469 {
43470     ma_result result;
43471     ma_uint32 ilpf1;
43472     ma_uint32 ilpf2;
43473
43474     if (pLPF == NULL) {
43475         return MA_INVALID_ARGS;
43476     }
43477
43478     /* Faster path for in-place. */
43479     if (pFramesOut == pFramesIn) {
43480         for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) {
43481             result = ma_lpf1_process_pcm_frames(&pLPF->pLPF1[ilpf1], pFramesOut, pFramesOut, frameCount);
43482             if (result != MA_SUCCESS) {
43483                 return result;
43484             }
43485         }
43486
43487         for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) {
43488             result = ma_lpf2_process_pcm_frames(&pLPF->pLPF2[ilpf2], pFramesOut, pFramesOut, frameCount);
43489             if (result != MA_SUCCESS) {
43490                 return result;
43491             }
43492         }
43493     }
43494
43495     /* Slightly slower path for copying. */
43496     if (pFramesOut != pFramesIn) {
43497         ma_uint32 iFrame;
43498
43499         /*  */ if (pLPF->format == ma_format_f32) {
43500             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
43501             const float* pFramesInF32  = (const float*)pFramesIn;
43502
43503             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
43504                 ma_lpf_process_pcm_frame_f32(pLPF, pFramesOutF32, pFramesInF32);
43505                 pFramesOutF32 += pLPF->channels;
43506                 pFramesInF32  += pLPF->channels;
43507             }
43508         } else if (pLPF->format == ma_format_s16) {
43509             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
43510             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
43511
43512             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
43513                 ma_lpf_process_pcm_frame_s16(pLPF, pFramesOutS16, pFramesInS16);
43514                 pFramesOutS16 += pLPF->channels;
43515                 pFramesInS16  += pLPF->channels;
43516             }
43517         } else {
43518             MA_ASSERT(MA_FALSE);
43519             return MA_INVALID_OPERATION;    /* Should never hit this. */
43520         }
43521     }
43522
43523     return MA_SUCCESS;
43524 }
43525
43526 MA_API ma_uint32 ma_lpf_get_latency(const ma_lpf* pLPF)
43527 {
43528     if (pLPF == NULL) {
43529         return 0;
43530     }
43531
43532     return pLPF->lpf2Count*2 + pLPF->lpf1Count;
43533 }
43534
43535
43536 /**************************************************************************************************************************************************************
43537
43538 High-Pass Filtering
43539
43540 **************************************************************************************************************************************************************/
43541 MA_API ma_hpf1_config ma_hpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency)
43542 {
43543     ma_hpf1_config config;
43544
43545     MA_ZERO_OBJECT(&config);
43546     config.format = format;
43547     config.channels = channels;
43548     config.sampleRate = sampleRate;
43549     config.cutoffFrequency = cutoffFrequency;
43550
43551     return config;
43552 }
43553
43554 MA_API ma_hpf2_config ma_hpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
43555 {
43556     ma_hpf2_config config;
43557
43558     MA_ZERO_OBJECT(&config);
43559     config.format = format;
43560     config.channels = channels;
43561     config.sampleRate = sampleRate;
43562     config.cutoffFrequency = cutoffFrequency;
43563     config.q = q;
43564
43565     /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */
43566     if (config.q == 0) {
43567         config.q = 0.707107;
43568     }
43569
43570     return config;
43571 }
43572
43573
43574 typedef struct
43575 {
43576     size_t sizeInBytes;
43577     size_t r1Offset;
43578 } ma_hpf1_heap_layout;
43579
43580 static ma_result ma_hpf1_get_heap_layout(const ma_hpf1_config* pConfig, ma_hpf1_heap_layout* pHeapLayout)
43581 {
43582     MA_ASSERT(pHeapLayout != NULL);
43583
43584     MA_ZERO_OBJECT(pHeapLayout);
43585
43586     if (pConfig == NULL) {
43587         return MA_INVALID_ARGS;
43588     }
43589
43590     if (pConfig->channels == 0) {
43591         return MA_INVALID_ARGS;
43592     }
43593
43594     pHeapLayout->sizeInBytes = 0;
43595
43596     /* R1 */
43597     pHeapLayout->r1Offset = pHeapLayout->sizeInBytes;
43598     pHeapLayout->sizeInBytes += sizeof(ma_biquad_coefficient) * pConfig->channels;
43599
43600     /* Make sure allocation size is aligned. */
43601     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
43602
43603     return MA_SUCCESS;
43604 }
43605
43606 MA_API ma_result ma_hpf1_get_heap_size(const ma_hpf1_config* pConfig, size_t* pHeapSizeInBytes)
43607 {
43608     ma_result result;
43609     ma_hpf1_heap_layout heapLayout;
43610
43611     if (pHeapSizeInBytes == NULL) {
43612         return MA_INVALID_ARGS;
43613     }
43614
43615     result = ma_hpf1_get_heap_layout(pConfig, &heapLayout);
43616     if (result != MA_SUCCESS) {
43617         return result;
43618     }
43619
43620     *pHeapSizeInBytes = heapLayout.sizeInBytes;
43621
43622     return MA_SUCCESS;
43623 }
43624
43625 MA_API ma_result ma_hpf1_init_preallocated(const ma_hpf1_config* pConfig, void* pHeap, ma_hpf1* pLPF)
43626 {
43627     ma_result result;
43628     ma_hpf1_heap_layout heapLayout;
43629
43630     if (pLPF == NULL) {
43631         return MA_INVALID_ARGS;
43632     }
43633
43634     MA_ZERO_OBJECT(pLPF);
43635
43636     result = ma_hpf1_get_heap_layout(pConfig, &heapLayout);
43637     if (result != MA_SUCCESS) {
43638         return result;
43639     }
43640
43641     pLPF->_pHeap = pHeap;
43642     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
43643
43644     pLPF->pR1 = (ma_biquad_coefficient*)ma_offset_ptr(pHeap, heapLayout.r1Offset);
43645
43646     return ma_hpf1_reinit(pConfig, pLPF);
43647 }
43648
43649 MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf1* pLPF)
43650 {
43651     ma_result result;
43652     size_t heapSizeInBytes;
43653     void* pHeap;
43654
43655     result = ma_hpf1_get_heap_size(pConfig, &heapSizeInBytes);
43656     if (result != MA_SUCCESS) {
43657         return result;
43658     }
43659
43660     if (heapSizeInBytes > 0) {
43661         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
43662         if (pHeap == NULL) {
43663             return MA_OUT_OF_MEMORY;
43664         }
43665     } else {
43666         pHeap = NULL;
43667     }
43668
43669     result = ma_hpf1_init_preallocated(pConfig, pHeap, pLPF);
43670     if (result != MA_SUCCESS) {
43671         ma_free(pHeap, pAllocationCallbacks);
43672         return result;
43673     }
43674
43675     pLPF->_ownsHeap = MA_TRUE;
43676     return MA_SUCCESS;
43677 }
43678
43679 MA_API void ma_hpf1_uninit(ma_hpf1* pHPF, const ma_allocation_callbacks* pAllocationCallbacks)
43680 {
43681     if (pHPF == NULL) {
43682         return;
43683     }
43684
43685     if (pHPF->_ownsHeap) {
43686         ma_free(pHPF->_pHeap, pAllocationCallbacks);
43687     }
43688 }
43689
43690 MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF)
43691 {
43692     double a;
43693
43694     if (pHPF == NULL || pConfig == NULL) {
43695         return MA_INVALID_ARGS;
43696     }
43697
43698     /* Only supporting f32 and s16. */
43699     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
43700         return MA_INVALID_ARGS;
43701     }
43702
43703     /* The format cannot be changed after initialization. */
43704     if (pHPF->format != ma_format_unknown && pHPF->format != pConfig->format) {
43705         return MA_INVALID_OPERATION;
43706     }
43707
43708     /* The channel count cannot be changed after initialization. */
43709     if (pHPF->channels != 0 && pHPF->channels != pConfig->channels) {
43710         return MA_INVALID_OPERATION;
43711     }
43712
43713     pHPF->format   = pConfig->format;
43714     pHPF->channels = pConfig->channels;
43715
43716     a = ma_expd(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate);
43717     if (pConfig->format == ma_format_f32) {
43718         pHPF->a.f32 = (float)a;
43719     } else {
43720         pHPF->a.s32 = ma_biquad_float_to_fp(a);
43721     }
43722
43723     return MA_SUCCESS;
43724 }
43725
43726 static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1* pHPF, float* pY, const float* pX)
43727 {
43728     ma_uint32 c;
43729     const ma_uint32 channels = pHPF->channels;
43730     const float a = 1 - pHPF->a.f32;
43731     const float b = 1 - a;
43732
43733     MA_ASSUME(channels > 0);
43734     for (c = 0; c < channels; c += 1) {
43735         float r1 = pHPF->pR1[c].f32;
43736         float x  = pX[c];
43737         float y;
43738
43739         y = b*x - a*r1;
43740
43741         pY[c]            = y;
43742         pHPF->pR1[c].f32 = y;
43743     }
43744 }
43745
43746 static MA_INLINE void ma_hpf1_process_pcm_frame_s16(ma_hpf1* pHPF, ma_int16* pY, const ma_int16* pX)
43747 {
43748     ma_uint32 c;
43749     const ma_uint32 channels = pHPF->channels;
43750     const ma_int32 a = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - pHPF->a.s32);
43751     const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a);
43752
43753     MA_ASSUME(channels > 0);
43754     for (c = 0; c < channels; c += 1) {
43755         ma_int32 r1 = pHPF->pR1[c].s32;
43756         ma_int32 x  = pX[c];
43757         ma_int32 y;
43758
43759         y = (b*x - a*r1) >> MA_BIQUAD_FIXED_POINT_SHIFT;
43760
43761         pY[c]            = (ma_int16)y;
43762         pHPF->pR1[c].s32 = (ma_int32)y;
43763     }
43764 }
43765
43766 MA_API ma_result ma_hpf1_process_pcm_frames(ma_hpf1* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
43767 {
43768     ma_uint32 n;
43769
43770     if (pHPF == NULL || pFramesOut == NULL || pFramesIn == NULL) {
43771         return MA_INVALID_ARGS;
43772     }
43773
43774     /* 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. */
43775
43776     if (pHPF->format == ma_format_f32) {
43777         /* */ float* pY = (      float*)pFramesOut;
43778         const float* pX = (const float*)pFramesIn;
43779
43780         for (n = 0; n < frameCount; n += 1) {
43781             ma_hpf1_process_pcm_frame_f32(pHPF, pY, pX);
43782             pY += pHPF->channels;
43783             pX += pHPF->channels;
43784         }
43785     } else if (pHPF->format == ma_format_s16) {
43786         /* */ ma_int16* pY = (      ma_int16*)pFramesOut;
43787         const ma_int16* pX = (const ma_int16*)pFramesIn;
43788
43789         for (n = 0; n < frameCount; n += 1) {
43790             ma_hpf1_process_pcm_frame_s16(pHPF, pY, pX);
43791             pY += pHPF->channels;
43792             pX += pHPF->channels;
43793         }
43794     } else {
43795         MA_ASSERT(MA_FALSE);
43796         return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */
43797     }
43798
43799     return MA_SUCCESS;
43800 }
43801
43802 MA_API ma_uint32 ma_hpf1_get_latency(const ma_hpf1* pHPF)
43803 {
43804     if (pHPF == NULL) {
43805         return 0;
43806     }
43807
43808     return 1;
43809 }
43810
43811
43812 static MA_INLINE ma_biquad_config ma_hpf2__get_biquad_config(const ma_hpf2_config* pConfig)
43813 {
43814     ma_biquad_config bqConfig;
43815     double q;
43816     double w;
43817     double s;
43818     double c;
43819     double a;
43820
43821     MA_ASSERT(pConfig != NULL);
43822
43823     q = pConfig->q;
43824     w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
43825     s = ma_sind(w);
43826     c = ma_cosd(w);
43827     a = s / (2*q);
43828
43829     bqConfig.b0 =  (1 + c) / 2;
43830     bqConfig.b1 = -(1 + c);
43831     bqConfig.b2 =  (1 + c) / 2;
43832     bqConfig.a0 =   1 + a;
43833     bqConfig.a1 =  -2 * c;
43834     bqConfig.a2 =   1 - a;
43835
43836     bqConfig.format   = pConfig->format;
43837     bqConfig.channels = pConfig->channels;
43838
43839     return bqConfig;
43840 }
43841
43842 MA_API ma_result ma_hpf2_get_heap_size(const ma_hpf2_config* pConfig, size_t* pHeapSizeInBytes)
43843 {
43844     ma_biquad_config bqConfig;
43845     bqConfig = ma_hpf2__get_biquad_config(pConfig);
43846
43847     return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes);
43848 }
43849
43850 MA_API ma_result ma_hpf2_init_preallocated(const ma_hpf2_config* pConfig, void* pHeap, ma_hpf2* pHPF)
43851 {
43852     ma_result result;
43853     ma_biquad_config bqConfig;
43854
43855     if (pHPF == NULL) {
43856         return MA_INVALID_ARGS;
43857     }
43858
43859     MA_ZERO_OBJECT(pHPF);
43860
43861     if (pConfig == NULL) {
43862         return MA_INVALID_ARGS;
43863     }
43864
43865     bqConfig = ma_hpf2__get_biquad_config(pConfig);
43866     result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pHPF->bq);
43867     if (result != MA_SUCCESS) {
43868         return result;
43869     }
43870
43871     return MA_SUCCESS;
43872 }
43873
43874 MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf2* pHPF)
43875 {
43876     ma_result result;
43877     size_t heapSizeInBytes;
43878     void* pHeap;
43879
43880     result = ma_hpf2_get_heap_size(pConfig, &heapSizeInBytes);
43881     if (result != MA_SUCCESS) {
43882         return result;
43883     }
43884
43885     if (heapSizeInBytes > 0) {
43886         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
43887         if (pHeap == NULL) {
43888             return MA_OUT_OF_MEMORY;
43889         }
43890     } else {
43891         pHeap = NULL;
43892     }
43893
43894     result = ma_hpf2_init_preallocated(pConfig, pHeap, pHPF);
43895     if (result != MA_SUCCESS) {
43896         ma_free(pHeap, pAllocationCallbacks);
43897         return result;
43898     }
43899
43900     pHPF->bq._ownsHeap = MA_TRUE;    /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */
43901     return MA_SUCCESS;
43902 }
43903
43904 MA_API void ma_hpf2_uninit(ma_hpf2* pHPF, const ma_allocation_callbacks* pAllocationCallbacks)
43905 {
43906     if (pHPF == NULL) {
43907         return;
43908     }
43909
43910     ma_biquad_uninit(&pHPF->bq, pAllocationCallbacks);   /* <-- This will free the heap allocation. */
43911 }
43912
43913 MA_API ma_result ma_hpf2_reinit(const ma_hpf2_config* pConfig, ma_hpf2* pHPF)
43914 {
43915     ma_result result;
43916     ma_biquad_config bqConfig;
43917
43918     if (pHPF == NULL || pConfig == NULL) {
43919         return MA_INVALID_ARGS;
43920     }
43921
43922     bqConfig = ma_hpf2__get_biquad_config(pConfig);
43923     result = ma_biquad_reinit(&bqConfig, &pHPF->bq);
43924     if (result != MA_SUCCESS) {
43925         return result;
43926     }
43927
43928     return MA_SUCCESS;
43929 }
43930
43931 static MA_INLINE void ma_hpf2_process_pcm_frame_s16(ma_hpf2* pHPF, ma_int16* pFrameOut, const ma_int16* pFrameIn)
43932 {
43933     ma_biquad_process_pcm_frame_s16(&pHPF->bq, pFrameOut, pFrameIn);
43934 }
43935
43936 static MA_INLINE void ma_hpf2_process_pcm_frame_f32(ma_hpf2* pHPF, float* pFrameOut, const float* pFrameIn)
43937 {
43938     ma_biquad_process_pcm_frame_f32(&pHPF->bq, pFrameOut, pFrameIn);
43939 }
43940
43941 MA_API ma_result ma_hpf2_process_pcm_frames(ma_hpf2* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
43942 {
43943     if (pHPF == NULL) {
43944         return MA_INVALID_ARGS;
43945     }
43946
43947     return ma_biquad_process_pcm_frames(&pHPF->bq, pFramesOut, pFramesIn, frameCount);
43948 }
43949
43950 MA_API ma_uint32 ma_hpf2_get_latency(const ma_hpf2* pHPF)
43951 {
43952     if (pHPF == NULL) {
43953         return 0;
43954     }
43955
43956     return ma_biquad_get_latency(&pHPF->bq);
43957 }
43958
43959
43960 MA_API ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
43961 {
43962     ma_hpf_config config;
43963
43964     MA_ZERO_OBJECT(&config);
43965     config.format          = format;
43966     config.channels        = channels;
43967     config.sampleRate      = sampleRate;
43968     config.cutoffFrequency = cutoffFrequency;
43969     config.order           = ma_min(order, MA_MAX_FILTER_ORDER);
43970
43971     return config;
43972 }
43973
43974
43975 typedef struct
43976 {
43977     size_t sizeInBytes;
43978     size_t hpf1Offset;
43979     size_t hpf2Offset;  /* Offset of the first second order filter. Subsequent filters will come straight after, and will each have the same heap size. */
43980 } ma_hpf_heap_layout;
43981
43982 static void ma_hpf_calculate_sub_hpf_counts(ma_uint32 order, ma_uint32* pHPF1Count, ma_uint32* pHPF2Count)
43983 {
43984     MA_ASSERT(pHPF1Count != NULL);
43985     MA_ASSERT(pHPF2Count != NULL);
43986
43987     *pHPF1Count = order % 2;
43988     *pHPF2Count = order / 2;
43989 }
43990
43991 static ma_result ma_hpf_get_heap_layout(const ma_hpf_config* pConfig, ma_hpf_heap_layout* pHeapLayout)
43992 {
43993     ma_result result;
43994     ma_uint32 hpf1Count;
43995     ma_uint32 hpf2Count;
43996     ma_uint32 ihpf1;
43997     ma_uint32 ihpf2;
43998
43999     MA_ASSERT(pHeapLayout != NULL);
44000
44001     MA_ZERO_OBJECT(pHeapLayout);
44002
44003     if (pConfig == NULL) {
44004         return MA_INVALID_ARGS;
44005     }
44006
44007     if (pConfig->channels == 0) {
44008         return MA_INVALID_ARGS;
44009     }
44010
44011     if (pConfig->order > MA_MAX_FILTER_ORDER) {
44012         return MA_INVALID_ARGS;
44013     }
44014
44015     ma_hpf_calculate_sub_hpf_counts(pConfig->order, &hpf1Count, &hpf2Count);
44016
44017     pHeapLayout->sizeInBytes = 0;
44018
44019     /* LPF 1 */
44020     pHeapLayout->hpf1Offset = pHeapLayout->sizeInBytes;
44021     for (ihpf1 = 0; ihpf1 < hpf1Count; ihpf1 += 1) {
44022         size_t hpf1HeapSizeInBytes;
44023         ma_hpf1_config hpf1Config = ma_hpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency);
44024
44025         result = ma_hpf1_get_heap_size(&hpf1Config, &hpf1HeapSizeInBytes);
44026         if (result != MA_SUCCESS) {
44027             return result;
44028         }
44029
44030         pHeapLayout->sizeInBytes += sizeof(ma_hpf1) + hpf1HeapSizeInBytes;
44031     }
44032
44033     /* LPF 2*/
44034     pHeapLayout->hpf2Offset = pHeapLayout->sizeInBytes;
44035     for (ihpf2 = 0; ihpf2 < hpf2Count; ihpf2 += 1) {
44036         size_t hpf2HeapSizeInBytes;
44037         ma_hpf2_config hpf2Config = ma_hpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, 0.707107);   /* <-- The "q" parameter does not matter for the purpose of calculating the heap size. */
44038
44039         result = ma_hpf2_get_heap_size(&hpf2Config, &hpf2HeapSizeInBytes);
44040         if (result != MA_SUCCESS) {
44041             return result;
44042         }
44043
44044         pHeapLayout->sizeInBytes += sizeof(ma_hpf2) + hpf2HeapSizeInBytes;
44045     }
44046
44047     /* Make sure allocation size is aligned. */
44048     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
44049
44050     return MA_SUCCESS;
44051 }
44052
44053 static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, void* pHeap, ma_hpf* pHPF, ma_bool32 isNew)
44054 {
44055     ma_result result;
44056     ma_uint32 hpf1Count;
44057     ma_uint32 hpf2Count;
44058     ma_uint32 ihpf1;
44059     ma_uint32 ihpf2;
44060     ma_hpf_heap_layout heapLayout;  /* Only used if isNew is true. */
44061
44062     if (pHPF == NULL || pConfig == NULL) {
44063         return MA_INVALID_ARGS;
44064     }
44065
44066     /* Only supporting f32 and s16. */
44067     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
44068         return MA_INVALID_ARGS;
44069     }
44070
44071     /* The format cannot be changed after initialization. */
44072     if (pHPF->format != ma_format_unknown && pHPF->format != pConfig->format) {
44073         return MA_INVALID_OPERATION;
44074     }
44075
44076     /* The channel count cannot be changed after initialization. */
44077     if (pHPF->channels != 0 && pHPF->channels != pConfig->channels) {
44078         return MA_INVALID_OPERATION;
44079     }
44080
44081     if (pConfig->order > MA_MAX_FILTER_ORDER) {
44082         return MA_INVALID_ARGS;
44083     }
44084
44085     ma_hpf_calculate_sub_hpf_counts(pConfig->order, &hpf1Count, &hpf2Count);
44086
44087     /* The filter order can't change between reinits. */
44088     if (!isNew) {
44089         if (pHPF->hpf1Count != hpf1Count || pHPF->hpf2Count != hpf2Count) {
44090             return MA_INVALID_OPERATION;
44091         }
44092     }
44093
44094     if (isNew) {
44095         result = ma_hpf_get_heap_layout(pConfig, &heapLayout);
44096         if (result != MA_SUCCESS) {
44097             return result;
44098         }
44099
44100         pHPF->_pHeap = pHeap;
44101         MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
44102
44103         pHPF->pHPF1 = (ma_hpf1*)ma_offset_ptr(pHeap, heapLayout.hpf1Offset);
44104         pHPF->pHPF2 = (ma_hpf2*)ma_offset_ptr(pHeap, heapLayout.hpf2Offset);
44105     } else {
44106         MA_ZERO_OBJECT(&heapLayout);    /* To silence a compiler warning. */
44107     }
44108
44109     for (ihpf1 = 0; ihpf1 < hpf1Count; ihpf1 += 1) {
44110         ma_hpf1_config hpf1Config = ma_hpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency);
44111
44112         if (isNew) {
44113             size_t hpf1HeapSizeInBytes;
44114
44115             result = ma_hpf1_get_heap_size(&hpf1Config, &hpf1HeapSizeInBytes);
44116             if (result == MA_SUCCESS) {
44117                 result = ma_hpf1_init_preallocated(&hpf1Config, ma_offset_ptr(pHeap, heapLayout.hpf1Offset + (ihpf1 * (sizeof(ma_hpf1) + hpf1HeapSizeInBytes)) + sizeof(ma_hpf1)), &pHPF->pHPF1[ihpf1]);
44118             }
44119         } else {
44120             result = ma_hpf1_reinit(&hpf1Config, &pHPF->pHPF1[ihpf1]);
44121         }
44122
44123         if (result != MA_SUCCESS) {
44124             ma_uint32 jhpf1;
44125
44126             for (jhpf1 = 0; jhpf1 < ihpf1; jhpf1 += 1) {
44127                 ma_hpf1_uninit(&pHPF->pHPF1[jhpf1], NULL);  /* No need for allocation callbacks here since we used a preallocated heap allocation. */
44128             }
44129
44130             return result;
44131         }
44132     }
44133
44134     for (ihpf2 = 0; ihpf2 < hpf2Count; ihpf2 += 1) {
44135         ma_hpf2_config hpf2Config;
44136         double q;
44137         double a;
44138
44139         /* Tempting to use 0.707107, but won't result in a Butterworth filter if the order is > 2. */
44140         if (hpf1Count == 1) {
44141             a = (1 + ihpf2*1) * (MA_PI_D/(pConfig->order*1));   /* Odd order. */
44142         } else {
44143             a = (1 + ihpf2*2) * (MA_PI_D/(pConfig->order*2));   /* Even order. */
44144         }
44145         q = 1 / (2*ma_cosd(a));
44146
44147         hpf2Config = ma_hpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q);
44148
44149         if (isNew) {
44150             size_t hpf2HeapSizeInBytes;
44151
44152             result = ma_hpf2_get_heap_size(&hpf2Config, &hpf2HeapSizeInBytes);
44153             if (result == MA_SUCCESS) {
44154                 result = ma_hpf2_init_preallocated(&hpf2Config, ma_offset_ptr(pHeap, heapLayout.hpf2Offset + (ihpf2 * (sizeof(ma_hpf2) + hpf2HeapSizeInBytes)) + sizeof(ma_hpf2)), &pHPF->pHPF2[ihpf2]);
44155             }
44156         } else {
44157             result = ma_hpf2_reinit(&hpf2Config, &pHPF->pHPF2[ihpf2]);
44158         }
44159
44160         if (result != MA_SUCCESS) {
44161             ma_uint32 jhpf1;
44162             ma_uint32 jhpf2;
44163
44164             for (jhpf1 = 0; jhpf1 < hpf1Count; jhpf1 += 1) {
44165                 ma_hpf1_uninit(&pHPF->pHPF1[jhpf1], NULL);  /* No need for allocation callbacks here since we used a preallocated heap allocation. */
44166             }
44167
44168             for (jhpf2 = 0; jhpf2 < ihpf2; jhpf2 += 1) {
44169                 ma_hpf2_uninit(&pHPF->pHPF2[jhpf2], NULL);  /* No need for allocation callbacks here since we used a preallocated heap allocation. */
44170             }
44171
44172             return result;
44173         }
44174     }
44175
44176     pHPF->hpf1Count  = hpf1Count;
44177     pHPF->hpf2Count  = hpf2Count;
44178     pHPF->format     = pConfig->format;
44179     pHPF->channels   = pConfig->channels;
44180     pHPF->sampleRate = pConfig->sampleRate;
44181
44182     return MA_SUCCESS;
44183 }
44184
44185 MA_API ma_result ma_hpf_get_heap_size(const ma_hpf_config* pConfig, size_t* pHeapSizeInBytes)
44186 {
44187     ma_result result;
44188     ma_hpf_heap_layout heapLayout;
44189
44190     if (pHeapSizeInBytes == NULL) {
44191         return MA_INVALID_ARGS;
44192     }
44193
44194     *pHeapSizeInBytes = 0;
44195
44196     result = ma_hpf_get_heap_layout(pConfig, &heapLayout);
44197     if (result != MA_SUCCESS) {
44198         return result;
44199     }
44200
44201     *pHeapSizeInBytes = heapLayout.sizeInBytes;
44202
44203     return result;
44204 }
44205
44206 MA_API ma_result ma_hpf_init_preallocated(const ma_hpf_config* pConfig, void* pHeap, ma_hpf* pLPF)
44207 {
44208     if (pLPF == NULL) {
44209         return MA_INVALID_ARGS;
44210     }
44211
44212     MA_ZERO_OBJECT(pLPF);
44213
44214     return ma_hpf_reinit__internal(pConfig, pHeap, pLPF, /*isNew*/MA_TRUE);
44215 }
44216
44217 MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf* pHPF)
44218 {
44219     ma_result result;
44220     size_t heapSizeInBytes;
44221     void* pHeap;
44222
44223     result = ma_hpf_get_heap_size(pConfig, &heapSizeInBytes);
44224     if (result != MA_SUCCESS) {
44225         return result;
44226     }
44227
44228     if (heapSizeInBytes > 0) {
44229         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
44230         if (pHeap == NULL) {
44231             return MA_OUT_OF_MEMORY;
44232         }
44233     } else {
44234         pHeap = NULL;
44235     }
44236
44237     result = ma_hpf_init_preallocated(pConfig, pHeap, pHPF);
44238     if (result != MA_SUCCESS) {
44239         ma_free(pHeap, pAllocationCallbacks);
44240         return result;
44241     }
44242
44243     pHPF->_ownsHeap = MA_TRUE;
44244     return MA_SUCCESS;
44245 }
44246
44247 MA_API void ma_hpf_uninit(ma_hpf* pHPF, const ma_allocation_callbacks* pAllocationCallbacks)
44248 {
44249     ma_uint32 ihpf1;
44250     ma_uint32 ihpf2;
44251
44252     if (pHPF == NULL) {
44253         return;
44254     }
44255
44256     for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) {
44257         ma_hpf1_uninit(&pHPF->pHPF1[ihpf1], pAllocationCallbacks);
44258     }
44259
44260     for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) {
44261         ma_hpf2_uninit(&pHPF->pHPF2[ihpf2], pAllocationCallbacks);
44262     }
44263 }
44264
44265 MA_API ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF)
44266 {
44267     return ma_hpf_reinit__internal(pConfig, NULL, pHPF, /*isNew*/MA_FALSE);
44268 }
44269
44270 MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
44271 {
44272     ma_result result;
44273     ma_uint32 ihpf1;
44274     ma_uint32 ihpf2;
44275
44276     if (pHPF == NULL) {
44277         return MA_INVALID_ARGS;
44278     }
44279
44280     /* Faster path for in-place. */
44281     if (pFramesOut == pFramesIn) {
44282         for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) {
44283             result = ma_hpf1_process_pcm_frames(&pHPF->pHPF1[ihpf1], pFramesOut, pFramesOut, frameCount);
44284             if (result != MA_SUCCESS) {
44285                 return result;
44286             }
44287         }
44288
44289         for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) {
44290             result = ma_hpf2_process_pcm_frames(&pHPF->pHPF2[ihpf2], pFramesOut, pFramesOut, frameCount);
44291             if (result != MA_SUCCESS) {
44292                 return result;
44293             }
44294         }
44295     }
44296
44297     /* Slightly slower path for copying. */
44298     if (pFramesOut != pFramesIn) {
44299         ma_uint32 iFrame;
44300
44301         /*  */ if (pHPF->format == ma_format_f32) {
44302             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
44303             const float* pFramesInF32  = (const float*)pFramesIn;
44304
44305             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
44306                 MA_COPY_MEMORY(pFramesOutF32, pFramesInF32, ma_get_bytes_per_frame(pHPF->format, pHPF->channels));
44307
44308                 for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) {
44309                     ma_hpf1_process_pcm_frame_f32(&pHPF->pHPF1[ihpf1], pFramesOutF32, pFramesOutF32);
44310                 }
44311
44312                 for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) {
44313                     ma_hpf2_process_pcm_frame_f32(&pHPF->pHPF2[ihpf2], pFramesOutF32, pFramesOutF32);
44314                 }
44315
44316                 pFramesOutF32 += pHPF->channels;
44317                 pFramesInF32  += pHPF->channels;
44318             }
44319         } else if (pHPF->format == ma_format_s16) {
44320             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
44321             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
44322
44323             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
44324                 MA_COPY_MEMORY(pFramesOutS16, pFramesInS16, ma_get_bytes_per_frame(pHPF->format, pHPF->channels));
44325
44326                 for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) {
44327                     ma_hpf1_process_pcm_frame_s16(&pHPF->pHPF1[ihpf1], pFramesOutS16, pFramesOutS16);
44328                 }
44329
44330                 for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) {
44331                     ma_hpf2_process_pcm_frame_s16(&pHPF->pHPF2[ihpf2], pFramesOutS16, pFramesOutS16);
44332                 }
44333
44334                 pFramesOutS16 += pHPF->channels;
44335                 pFramesInS16  += pHPF->channels;
44336             }
44337         } else {
44338             MA_ASSERT(MA_FALSE);
44339             return MA_INVALID_OPERATION;    /* Should never hit this. */
44340         }
44341     }
44342
44343     return MA_SUCCESS;
44344 }
44345
44346 MA_API ma_uint32 ma_hpf_get_latency(const ma_hpf* pHPF)
44347 {
44348     if (pHPF == NULL) {
44349         return 0;
44350     }
44351
44352     return pHPF->hpf2Count*2 + pHPF->hpf1Count;
44353 }
44354
44355
44356 /**************************************************************************************************************************************************************
44357
44358 Band-Pass Filtering
44359
44360 **************************************************************************************************************************************************************/
44361 MA_API ma_bpf2_config ma_bpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
44362 {
44363     ma_bpf2_config config;
44364
44365     MA_ZERO_OBJECT(&config);
44366     config.format = format;
44367     config.channels = channels;
44368     config.sampleRate = sampleRate;
44369     config.cutoffFrequency = cutoffFrequency;
44370     config.q = q;
44371
44372     /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */
44373     if (config.q == 0) {
44374         config.q = 0.707107;
44375     }
44376
44377     return config;
44378 }
44379
44380
44381 static MA_INLINE ma_biquad_config ma_bpf2__get_biquad_config(const ma_bpf2_config* pConfig)
44382 {
44383     ma_biquad_config bqConfig;
44384     double q;
44385     double w;
44386     double s;
44387     double c;
44388     double a;
44389
44390     MA_ASSERT(pConfig != NULL);
44391
44392     q = pConfig->q;
44393     w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
44394     s = ma_sind(w);
44395     c = ma_cosd(w);
44396     a = s / (2*q);
44397
44398     bqConfig.b0 =  q * a;
44399     bqConfig.b1 =  0;
44400     bqConfig.b2 = -q * a;
44401     bqConfig.a0 =  1 + a;
44402     bqConfig.a1 = -2 * c;
44403     bqConfig.a2 =  1 - a;
44404
44405     bqConfig.format   = pConfig->format;
44406     bqConfig.channels = pConfig->channels;
44407
44408     return bqConfig;
44409 }
44410
44411 MA_API ma_result ma_bpf2_get_heap_size(const ma_bpf2_config* pConfig, size_t* pHeapSizeInBytes)
44412 {
44413     ma_biquad_config bqConfig;
44414     bqConfig = ma_bpf2__get_biquad_config(pConfig);
44415
44416     return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes);
44417 }
44418
44419 MA_API ma_result ma_bpf2_init_preallocated(const ma_bpf2_config* pConfig, void* pHeap, ma_bpf2* pBPF)
44420 {
44421     ma_result result;
44422     ma_biquad_config bqConfig;
44423
44424     if (pBPF == NULL) {
44425         return MA_INVALID_ARGS;
44426     }
44427
44428     MA_ZERO_OBJECT(pBPF);
44429
44430     if (pConfig == NULL) {
44431         return MA_INVALID_ARGS;
44432     }
44433
44434     bqConfig = ma_bpf2__get_biquad_config(pConfig);
44435     result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pBPF->bq);
44436     if (result != MA_SUCCESS) {
44437         return result;
44438     }
44439
44440     return MA_SUCCESS;
44441 }
44442
44443 MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf2* pBPF)
44444 {
44445     ma_result result;
44446     size_t heapSizeInBytes;
44447     void* pHeap;
44448
44449     result = ma_bpf2_get_heap_size(pConfig, &heapSizeInBytes);
44450     if (result != MA_SUCCESS) {
44451         return result;
44452     }
44453
44454     if (heapSizeInBytes > 0) {
44455         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
44456         if (pHeap == NULL) {
44457             return MA_OUT_OF_MEMORY;
44458         }
44459     } else {
44460         pHeap = NULL;
44461     }
44462
44463     result = ma_bpf2_init_preallocated(pConfig, pHeap, pBPF);
44464     if (result != MA_SUCCESS) {
44465         ma_free(pHeap, pAllocationCallbacks);
44466         return result;
44467     }
44468
44469     pBPF->bq._ownsHeap = MA_TRUE;    /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */
44470     return MA_SUCCESS;
44471 }
44472
44473 MA_API void ma_bpf2_uninit(ma_bpf2* pBPF, const ma_allocation_callbacks* pAllocationCallbacks)
44474 {
44475     if (pBPF == NULL) {
44476         return;
44477     }
44478
44479     ma_biquad_uninit(&pBPF->bq, pAllocationCallbacks);   /* <-- This will free the heap allocation. */
44480 }
44481
44482 MA_API ma_result ma_bpf2_reinit(const ma_bpf2_config* pConfig, ma_bpf2* pBPF)
44483 {
44484     ma_result result;
44485     ma_biquad_config bqConfig;
44486
44487     if (pBPF == NULL || pConfig == NULL) {
44488         return MA_INVALID_ARGS;
44489     }
44490
44491     bqConfig = ma_bpf2__get_biquad_config(pConfig);
44492     result = ma_biquad_reinit(&bqConfig, &pBPF->bq);
44493     if (result != MA_SUCCESS) {
44494         return result;
44495     }
44496
44497     return MA_SUCCESS;
44498 }
44499
44500 static MA_INLINE void ma_bpf2_process_pcm_frame_s16(ma_bpf2* pBPF, ma_int16* pFrameOut, const ma_int16* pFrameIn)
44501 {
44502     ma_biquad_process_pcm_frame_s16(&pBPF->bq, pFrameOut, pFrameIn);
44503 }
44504
44505 static MA_INLINE void ma_bpf2_process_pcm_frame_f32(ma_bpf2* pBPF, float* pFrameOut, const float* pFrameIn)
44506 {
44507     ma_biquad_process_pcm_frame_f32(&pBPF->bq, pFrameOut, pFrameIn);
44508 }
44509
44510 MA_API ma_result ma_bpf2_process_pcm_frames(ma_bpf2* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
44511 {
44512     if (pBPF == NULL) {
44513         return MA_INVALID_ARGS;
44514     }
44515
44516     return ma_biquad_process_pcm_frames(&pBPF->bq, pFramesOut, pFramesIn, frameCount);
44517 }
44518
44519 MA_API ma_uint32 ma_bpf2_get_latency(const ma_bpf2* pBPF)
44520 {
44521     if (pBPF == NULL) {
44522         return 0;
44523     }
44524
44525     return ma_biquad_get_latency(&pBPF->bq);
44526 }
44527
44528
44529 MA_API ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
44530 {
44531     ma_bpf_config config;
44532
44533     MA_ZERO_OBJECT(&config);
44534     config.format          = format;
44535     config.channels        = channels;
44536     config.sampleRate      = sampleRate;
44537     config.cutoffFrequency = cutoffFrequency;
44538     config.order           = ma_min(order, MA_MAX_FILTER_ORDER);
44539
44540     return config;
44541 }
44542
44543
44544 typedef struct
44545 {
44546     size_t sizeInBytes;
44547     size_t bpf2Offset;
44548 } ma_bpf_heap_layout;
44549
44550 static ma_result ma_bpf_get_heap_layout(const ma_bpf_config* pConfig, ma_bpf_heap_layout* pHeapLayout)
44551 {
44552     ma_result result;
44553     ma_uint32 bpf2Count;
44554     ma_uint32 ibpf2;
44555
44556     MA_ASSERT(pHeapLayout != NULL);
44557
44558     MA_ZERO_OBJECT(pHeapLayout);
44559
44560     if (pConfig == NULL) {
44561         return MA_INVALID_ARGS;
44562     }
44563
44564     if (pConfig->order > MA_MAX_FILTER_ORDER) {
44565         return MA_INVALID_ARGS;
44566     }
44567
44568     /* We must have an even number of order. */
44569     if ((pConfig->order & 0x1) != 0) {
44570         return MA_INVALID_ARGS;
44571     }
44572
44573     bpf2Count = pConfig->channels / 2;
44574
44575     pHeapLayout->sizeInBytes = 0;
44576
44577     /* BPF 2 */
44578     pHeapLayout->bpf2Offset = pHeapLayout->sizeInBytes;
44579     for (ibpf2 = 0; ibpf2 < bpf2Count; ibpf2 += 1) {
44580         size_t bpf2HeapSizeInBytes;
44581         ma_bpf2_config bpf2Config = ma_bpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, 0.707107);   /* <-- The "q" parameter does not matter for the purpose of calculating the heap size. */
44582
44583         result = ma_bpf2_get_heap_size(&bpf2Config, &bpf2HeapSizeInBytes);
44584         if (result != MA_SUCCESS) {
44585             return result;
44586         }
44587
44588         pHeapLayout->sizeInBytes += sizeof(ma_bpf2) + bpf2HeapSizeInBytes;
44589     }
44590
44591     /* Make sure allocation size is aligned. */
44592     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
44593
44594     return MA_SUCCESS;
44595 }
44596
44597 static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, void* pHeap, ma_bpf* pBPF, ma_bool32 isNew)
44598 {
44599     ma_result result;
44600     ma_uint32 bpf2Count;
44601     ma_uint32 ibpf2;
44602     ma_bpf_heap_layout heapLayout;  /* Only used if isNew is true. */
44603
44604     if (pBPF == NULL || pConfig == NULL) {
44605         return MA_INVALID_ARGS;
44606     }
44607
44608     /* Only supporting f32 and s16. */
44609     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
44610         return MA_INVALID_ARGS;
44611     }
44612
44613     /* The format cannot be changed after initialization. */
44614     if (pBPF->format != ma_format_unknown && pBPF->format != pConfig->format) {
44615         return MA_INVALID_OPERATION;
44616     }
44617
44618     /* The channel count cannot be changed after initialization. */
44619     if (pBPF->channels != 0 && pBPF->channels != pConfig->channels) {
44620         return MA_INVALID_OPERATION;
44621     }
44622
44623     if (pConfig->order > MA_MAX_FILTER_ORDER) {
44624         return MA_INVALID_ARGS;
44625     }
44626
44627     /* We must have an even number of order. */
44628     if ((pConfig->order & 0x1) != 0) {
44629         return MA_INVALID_ARGS;
44630     }
44631
44632     bpf2Count = pConfig->order / 2;
44633
44634     /* The filter order can't change between reinits. */
44635     if (!isNew) {
44636         if (pBPF->bpf2Count != bpf2Count) {
44637             return MA_INVALID_OPERATION;
44638         }
44639     }
44640
44641     if (isNew) {
44642         result = ma_bpf_get_heap_layout(pConfig, &heapLayout);
44643         if (result != MA_SUCCESS) {
44644             return result;
44645         }
44646
44647         pBPF->_pHeap = pHeap;
44648         MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
44649
44650         pBPF->pBPF2 = (ma_bpf2*)ma_offset_ptr(pHeap, heapLayout.bpf2Offset);
44651     } else {
44652         MA_ZERO_OBJECT(&heapLayout);
44653     }
44654
44655     for (ibpf2 = 0; ibpf2 < bpf2Count; ibpf2 += 1) {
44656         ma_bpf2_config bpf2Config;
44657         double q;
44658
44659         /* TODO: Calculate Q to make this a proper Butterworth filter. */
44660         q = 0.707107;
44661
44662         bpf2Config = ma_bpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q);
44663
44664         if (isNew) {
44665             size_t bpf2HeapSizeInBytes;
44666
44667             result = ma_bpf2_get_heap_size(&bpf2Config, &bpf2HeapSizeInBytes);
44668             if (result == MA_SUCCESS) {
44669                 result = ma_bpf2_init_preallocated(&bpf2Config, ma_offset_ptr(pHeap, heapLayout.bpf2Offset + (ibpf2 * (sizeof(ma_bpf2) + bpf2HeapSizeInBytes)) + sizeof(ma_bpf2)), &pBPF->pBPF2[ibpf2]);
44670             }
44671         } else {
44672             result = ma_bpf2_reinit(&bpf2Config, &pBPF->pBPF2[ibpf2]);
44673         }
44674
44675         if (result != MA_SUCCESS) {
44676             return result;
44677         }
44678     }
44679
44680     pBPF->bpf2Count = bpf2Count;
44681     pBPF->format    = pConfig->format;
44682     pBPF->channels  = pConfig->channels;
44683
44684     return MA_SUCCESS;
44685 }
44686
44687
44688 MA_API ma_result ma_bpf_get_heap_size(const ma_bpf_config* pConfig, size_t* pHeapSizeInBytes)
44689 {
44690     ma_result result;
44691     ma_bpf_heap_layout heapLayout;
44692
44693     if (pHeapSizeInBytes == NULL) {
44694         return MA_INVALID_ARGS;
44695     }
44696
44697     *pHeapSizeInBytes = 0;
44698
44699     result = ma_bpf_get_heap_layout(pConfig, &heapLayout);
44700     if (result != MA_SUCCESS) {
44701         return result;
44702     }
44703
44704     *pHeapSizeInBytes = heapLayout.sizeInBytes;
44705
44706     return MA_SUCCESS;
44707 }
44708
44709 MA_API ma_result ma_bpf_init_preallocated(const ma_bpf_config* pConfig, void* pHeap, ma_bpf* pBPF)
44710 {
44711     if (pBPF == NULL) {
44712         return MA_INVALID_ARGS;
44713     }
44714
44715     MA_ZERO_OBJECT(pBPF);
44716
44717     return ma_bpf_reinit__internal(pConfig, pHeap, pBPF, /*isNew*/MA_TRUE);
44718 }
44719
44720 MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf* pBPF)
44721 {
44722     ma_result result;
44723     size_t heapSizeInBytes;
44724     void* pHeap;
44725
44726     result = ma_bpf_get_heap_size(pConfig, &heapSizeInBytes);
44727     if (result != MA_SUCCESS) {
44728         return result;
44729     }
44730
44731     if (heapSizeInBytes > 0) {
44732         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
44733         if (pHeap == NULL) {
44734             return MA_OUT_OF_MEMORY;
44735         }
44736     } else {
44737         pHeap = NULL;
44738     }
44739
44740     result = ma_bpf_init_preallocated(pConfig, pHeap, pBPF);
44741     if (result != MA_SUCCESS) {
44742         ma_free(pHeap, pAllocationCallbacks);
44743         return result;
44744     }
44745
44746     pBPF->_ownsHeap = MA_TRUE;
44747     return MA_SUCCESS;
44748 }
44749
44750 MA_API void ma_bpf_uninit(ma_bpf* pBPF, const ma_allocation_callbacks* pAllocationCallbacks)
44751 {
44752     ma_uint32 ibpf2;
44753
44754     if (pBPF == NULL) {
44755         return;
44756     }
44757
44758     for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) {
44759         ma_bpf2_uninit(&pBPF->pBPF2[ibpf2], pAllocationCallbacks);
44760     }
44761 }
44762
44763 MA_API ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF)
44764 {
44765     return ma_bpf_reinit__internal(pConfig, NULL, pBPF, /*isNew*/MA_FALSE);
44766 }
44767
44768 MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
44769 {
44770     ma_result result;
44771     ma_uint32 ibpf2;
44772
44773     if (pBPF == NULL) {
44774         return MA_INVALID_ARGS;
44775     }
44776
44777     /* Faster path for in-place. */
44778     if (pFramesOut == pFramesIn) {
44779         for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) {
44780             result = ma_bpf2_process_pcm_frames(&pBPF->pBPF2[ibpf2], pFramesOut, pFramesOut, frameCount);
44781             if (result != MA_SUCCESS) {
44782                 return result;
44783             }
44784         }
44785     }
44786
44787     /* Slightly slower path for copying. */
44788     if (pFramesOut != pFramesIn) {
44789         ma_uint32 iFrame;
44790
44791         /*  */ if (pBPF->format == ma_format_f32) {
44792             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
44793             const float* pFramesInF32  = (const float*)pFramesIn;
44794
44795             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
44796                 MA_COPY_MEMORY(pFramesOutF32, pFramesInF32, ma_get_bytes_per_frame(pBPF->format, pBPF->channels));
44797
44798                 for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) {
44799                     ma_bpf2_process_pcm_frame_f32(&pBPF->pBPF2[ibpf2], pFramesOutF32, pFramesOutF32);
44800                 }
44801
44802                 pFramesOutF32 += pBPF->channels;
44803                 pFramesInF32  += pBPF->channels;
44804             }
44805         } else if (pBPF->format == ma_format_s16) {
44806             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
44807             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
44808
44809             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
44810                 MA_COPY_MEMORY(pFramesOutS16, pFramesInS16, ma_get_bytes_per_frame(pBPF->format, pBPF->channels));
44811
44812                 for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) {
44813                     ma_bpf2_process_pcm_frame_s16(&pBPF->pBPF2[ibpf2], pFramesOutS16, pFramesOutS16);
44814                 }
44815
44816                 pFramesOutS16 += pBPF->channels;
44817                 pFramesInS16  += pBPF->channels;
44818             }
44819         } else {
44820             MA_ASSERT(MA_FALSE);
44821             return MA_INVALID_OPERATION;    /* Should never hit this. */
44822         }
44823     }
44824
44825     return MA_SUCCESS;
44826 }
44827
44828 MA_API ma_uint32 ma_bpf_get_latency(const ma_bpf* pBPF)
44829 {
44830     if (pBPF == NULL) {
44831         return 0;
44832     }
44833
44834     return pBPF->bpf2Count*2;
44835 }
44836
44837
44838 /**************************************************************************************************************************************************************
44839
44840 Notching Filter
44841
44842 **************************************************************************************************************************************************************/
44843 MA_API ma_notch2_config ma_notch2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency)
44844 {
44845     ma_notch2_config config;
44846
44847     MA_ZERO_OBJECT(&config);
44848     config.format     = format;
44849     config.channels   = channels;
44850     config.sampleRate = sampleRate;
44851     config.q          = q;
44852     config.frequency  = frequency;
44853
44854     if (config.q == 0) {
44855         config.q = 0.707107;
44856     }
44857
44858     return config;
44859 }
44860
44861
44862 static MA_INLINE ma_biquad_config ma_notch2__get_biquad_config(const ma_notch2_config* pConfig)
44863 {
44864     ma_biquad_config bqConfig;
44865     double q;
44866     double w;
44867     double s;
44868     double c;
44869     double a;
44870
44871     MA_ASSERT(pConfig != NULL);
44872
44873     q = pConfig->q;
44874     w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
44875     s = ma_sind(w);
44876     c = ma_cosd(w);
44877     a = s / (2*q);
44878
44879     bqConfig.b0 =  1;
44880     bqConfig.b1 = -2 * c;
44881     bqConfig.b2 =  1;
44882     bqConfig.a0 =  1 + a;
44883     bqConfig.a1 = -2 * c;
44884     bqConfig.a2 =  1 - a;
44885
44886     bqConfig.format   = pConfig->format;
44887     bqConfig.channels = pConfig->channels;
44888
44889     return bqConfig;
44890 }
44891
44892 MA_API ma_result ma_notch2_get_heap_size(const ma_notch2_config* pConfig, size_t* pHeapSizeInBytes)
44893 {
44894     ma_biquad_config bqConfig;
44895     bqConfig = ma_notch2__get_biquad_config(pConfig);
44896
44897     return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes);
44898 }
44899
44900 MA_API ma_result ma_notch2_init_preallocated(const ma_notch2_config* pConfig, void* pHeap, ma_notch2* pFilter)
44901 {
44902     ma_result result;
44903     ma_biquad_config bqConfig;
44904
44905     if (pFilter == NULL) {
44906         return MA_INVALID_ARGS;
44907     }
44908
44909     MA_ZERO_OBJECT(pFilter);
44910
44911     if (pConfig == NULL) {
44912         return MA_INVALID_ARGS;
44913     }
44914
44915     bqConfig = ma_notch2__get_biquad_config(pConfig);
44916     result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq);
44917     if (result != MA_SUCCESS) {
44918         return result;
44919     }
44920
44921     return MA_SUCCESS;
44922 }
44923
44924 MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch2* pFilter)
44925 {
44926     ma_result result;
44927     size_t heapSizeInBytes;
44928     void* pHeap;
44929
44930     result = ma_notch2_get_heap_size(pConfig, &heapSizeInBytes);
44931     if (result != MA_SUCCESS) {
44932         return result;
44933     }
44934
44935     if (heapSizeInBytes > 0) {
44936         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
44937         if (pHeap == NULL) {
44938             return MA_OUT_OF_MEMORY;
44939         }
44940     } else {
44941         pHeap = NULL;
44942     }
44943
44944     result = ma_notch2_init_preallocated(pConfig, pHeap, pFilter);
44945     if (result != MA_SUCCESS) {
44946         ma_free(pHeap, pAllocationCallbacks);
44947         return result;
44948     }
44949
44950     pFilter->bq._ownsHeap = MA_TRUE;    /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */
44951     return MA_SUCCESS;
44952 }
44953
44954 MA_API void ma_notch2_uninit(ma_notch2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks)
44955 {
44956     if (pFilter == NULL) {
44957         return;
44958     }
44959
44960     ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks);   /* <-- This will free the heap allocation. */
44961 }
44962
44963 MA_API ma_result ma_notch2_reinit(const ma_notch2_config* pConfig, ma_notch2* pFilter)
44964 {
44965     ma_result result;
44966     ma_biquad_config bqConfig;
44967
44968     if (pFilter == NULL || pConfig == NULL) {
44969         return MA_INVALID_ARGS;
44970     }
44971
44972     bqConfig = ma_notch2__get_biquad_config(pConfig);
44973     result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
44974     if (result != MA_SUCCESS) {
44975         return result;
44976     }
44977
44978     return MA_SUCCESS;
44979 }
44980
44981 static MA_INLINE void ma_notch2_process_pcm_frame_s16(ma_notch2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
44982 {
44983     ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
44984 }
44985
44986 static MA_INLINE void ma_notch2_process_pcm_frame_f32(ma_notch2* pFilter, float* pFrameOut, const float* pFrameIn)
44987 {
44988     ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
44989 }
44990
44991 MA_API ma_result ma_notch2_process_pcm_frames(ma_notch2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
44992 {
44993     if (pFilter == NULL) {
44994         return MA_INVALID_ARGS;
44995     }
44996
44997     return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
44998 }
44999
45000 MA_API ma_uint32 ma_notch2_get_latency(const ma_notch2* pFilter)
45001 {
45002     if (pFilter == NULL) {
45003         return 0;
45004     }
45005
45006     return ma_biquad_get_latency(&pFilter->bq);
45007 }
45008
45009
45010
45011 /**************************************************************************************************************************************************************
45012
45013 Peaking EQ Filter
45014
45015 **************************************************************************************************************************************************************/
45016 MA_API ma_peak2_config ma_peak2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency)
45017 {
45018     ma_peak2_config config;
45019
45020     MA_ZERO_OBJECT(&config);
45021     config.format     = format;
45022     config.channels   = channels;
45023     config.sampleRate = sampleRate;
45024     config.gainDB     = gainDB;
45025     config.q          = q;
45026     config.frequency  = frequency;
45027
45028     if (config.q == 0) {
45029         config.q = 0.707107;
45030     }
45031
45032     return config;
45033 }
45034
45035
45036 static MA_INLINE ma_biquad_config ma_peak2__get_biquad_config(const ma_peak2_config* pConfig)
45037 {
45038     ma_biquad_config bqConfig;
45039     double q;
45040     double w;
45041     double s;
45042     double c;
45043     double a;
45044     double A;
45045
45046     MA_ASSERT(pConfig != NULL);
45047
45048     q = pConfig->q;
45049     w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
45050     s = ma_sind(w);
45051     c = ma_cosd(w);
45052     a = s / (2*q);
45053     A = ma_powd(10, (pConfig->gainDB / 40));
45054
45055     bqConfig.b0 =  1 + (a * A);
45056     bqConfig.b1 = -2 * c;
45057     bqConfig.b2 =  1 - (a * A);
45058     bqConfig.a0 =  1 + (a / A);
45059     bqConfig.a1 = -2 * c;
45060     bqConfig.a2 =  1 - (a / A);
45061
45062     bqConfig.format   = pConfig->format;
45063     bqConfig.channels = pConfig->channels;
45064
45065     return bqConfig;
45066 }
45067
45068 MA_API ma_result ma_peak2_get_heap_size(const ma_peak2_config* pConfig, size_t* pHeapSizeInBytes)
45069 {
45070     ma_biquad_config bqConfig;
45071     bqConfig = ma_peak2__get_biquad_config(pConfig);
45072
45073     return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes);
45074 }
45075
45076 MA_API ma_result ma_peak2_init_preallocated(const ma_peak2_config* pConfig, void* pHeap, ma_peak2* pFilter)
45077 {
45078     ma_result result;
45079     ma_biquad_config bqConfig;
45080
45081     if (pFilter == NULL) {
45082         return MA_INVALID_ARGS;
45083     }
45084
45085     MA_ZERO_OBJECT(pFilter);
45086
45087     if (pConfig == NULL) {
45088         return MA_INVALID_ARGS;
45089     }
45090
45091     bqConfig = ma_peak2__get_biquad_config(pConfig);
45092     result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq);
45093     if (result != MA_SUCCESS) {
45094         return result;
45095     }
45096
45097     return MA_SUCCESS;
45098 }
45099
45100 MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak2* pFilter)
45101 {
45102     ma_result result;
45103     size_t heapSizeInBytes;
45104     void* pHeap;
45105
45106     result = ma_peak2_get_heap_size(pConfig, &heapSizeInBytes);
45107     if (result != MA_SUCCESS) {
45108         return result;
45109     }
45110
45111     if (heapSizeInBytes > 0) {
45112         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
45113         if (pHeap == NULL) {
45114             return MA_OUT_OF_MEMORY;
45115         }
45116     } else {
45117         pHeap = NULL;
45118     }
45119
45120     result = ma_peak2_init_preallocated(pConfig, pHeap, pFilter);
45121     if (result != MA_SUCCESS) {
45122         ma_free(pHeap, pAllocationCallbacks);
45123         return result;
45124     }
45125
45126     pFilter->bq._ownsHeap = MA_TRUE;    /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */
45127     return MA_SUCCESS;
45128 }
45129
45130 MA_API void ma_peak2_uninit(ma_peak2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks)
45131 {
45132     if (pFilter == NULL) {
45133         return;
45134     }
45135
45136     ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks);   /* <-- This will free the heap allocation. */
45137 }
45138
45139 MA_API ma_result ma_peak2_reinit(const ma_peak2_config* pConfig, ma_peak2* pFilter)
45140 {
45141     ma_result result;
45142     ma_biquad_config bqConfig;
45143
45144     if (pFilter == NULL || pConfig == NULL) {
45145         return MA_INVALID_ARGS;
45146     }
45147
45148     bqConfig = ma_peak2__get_biquad_config(pConfig);
45149     result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
45150     if (result != MA_SUCCESS) {
45151         return result;
45152     }
45153
45154     return MA_SUCCESS;
45155 }
45156
45157 static MA_INLINE void ma_peak2_process_pcm_frame_s16(ma_peak2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
45158 {
45159     ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
45160 }
45161
45162 static MA_INLINE void ma_peak2_process_pcm_frame_f32(ma_peak2* pFilter, float* pFrameOut, const float* pFrameIn)
45163 {
45164     ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
45165 }
45166
45167 MA_API ma_result ma_peak2_process_pcm_frames(ma_peak2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
45168 {
45169     if (pFilter == NULL) {
45170         return MA_INVALID_ARGS;
45171     }
45172
45173     return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
45174 }
45175
45176 MA_API ma_uint32 ma_peak2_get_latency(const ma_peak2* pFilter)
45177 {
45178     if (pFilter == NULL) {
45179         return 0;
45180     }
45181
45182     return ma_biquad_get_latency(&pFilter->bq);
45183 }
45184
45185
45186 /**************************************************************************************************************************************************************
45187
45188 Low Shelf Filter
45189
45190 **************************************************************************************************************************************************************/
45191 MA_API ma_loshelf2_config ma_loshelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency)
45192 {
45193     ma_loshelf2_config config;
45194
45195     MA_ZERO_OBJECT(&config);
45196     config.format     = format;
45197     config.channels   = channels;
45198     config.sampleRate = sampleRate;
45199     config.gainDB     = gainDB;
45200     config.shelfSlope = shelfSlope;
45201     config.frequency  = frequency;
45202
45203     return config;
45204 }
45205
45206
45207 static MA_INLINE ma_biquad_config ma_loshelf2__get_biquad_config(const ma_loshelf2_config* pConfig)
45208 {
45209     ma_biquad_config bqConfig;
45210     double w;
45211     double s;
45212     double c;
45213     double A;
45214     double S;
45215     double a;
45216     double sqrtA;
45217
45218     MA_ASSERT(pConfig != NULL);
45219
45220     w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
45221     s = ma_sind(w);
45222     c = ma_cosd(w);
45223     A = ma_powd(10, (pConfig->gainDB / 40));
45224     S = pConfig->shelfSlope;
45225     a = s/2 * ma_sqrtd((A + 1/A) * (1/S - 1) + 2);
45226     sqrtA = 2*ma_sqrtd(A)*a;
45227
45228     bqConfig.b0 =  A * ((A + 1) - (A - 1)*c + sqrtA);
45229     bqConfig.b1 =  2 * A * ((A - 1) - (A + 1)*c);
45230     bqConfig.b2 =  A * ((A + 1) - (A - 1)*c - sqrtA);
45231     bqConfig.a0 =  (A + 1) + (A - 1)*c + sqrtA;
45232     bqConfig.a1 = -2 * ((A - 1) + (A + 1)*c);
45233     bqConfig.a2 =  (A + 1) + (A - 1)*c - sqrtA;
45234
45235     bqConfig.format   = pConfig->format;
45236     bqConfig.channels = pConfig->channels;
45237
45238     return bqConfig;
45239 }
45240
45241 MA_API ma_result ma_loshelf2_get_heap_size(const ma_loshelf2_config* pConfig, size_t* pHeapSizeInBytes)
45242 {
45243     ma_biquad_config bqConfig;
45244     bqConfig = ma_loshelf2__get_biquad_config(pConfig);
45245
45246     return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes);
45247 }
45248
45249 MA_API ma_result ma_loshelf2_init_preallocated(const ma_loshelf2_config* pConfig, void* pHeap, ma_loshelf2* pFilter)
45250 {
45251     ma_result result;
45252     ma_biquad_config bqConfig;
45253
45254     if (pFilter == NULL) {
45255         return MA_INVALID_ARGS;
45256     }
45257
45258     MA_ZERO_OBJECT(pFilter);
45259
45260     if (pConfig == NULL) {
45261         return MA_INVALID_ARGS;
45262     }
45263
45264     bqConfig = ma_loshelf2__get_biquad_config(pConfig);
45265     result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq);
45266     if (result != MA_SUCCESS) {
45267         return result;
45268     }
45269
45270     return MA_SUCCESS;
45271 }
45272
45273 MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf2* pFilter)
45274 {
45275     ma_result result;
45276     size_t heapSizeInBytes;
45277     void* pHeap;
45278
45279     result = ma_loshelf2_get_heap_size(pConfig, &heapSizeInBytes);
45280     if (result != MA_SUCCESS) {
45281         return result;
45282     }
45283
45284     if (heapSizeInBytes > 0) {
45285         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
45286         if (pHeap == NULL) {
45287             return MA_OUT_OF_MEMORY;
45288         }
45289     } else {
45290         pHeap = NULL;
45291     }
45292
45293     result = ma_loshelf2_init_preallocated(pConfig, pHeap, pFilter);
45294     if (result != MA_SUCCESS) {
45295         ma_free(pHeap, pAllocationCallbacks);
45296         return result;
45297     }
45298
45299     pFilter->bq._ownsHeap = MA_TRUE;    /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */
45300     return MA_SUCCESS;
45301 }
45302
45303 MA_API void ma_loshelf2_uninit(ma_loshelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks)
45304 {
45305     if (pFilter == NULL) {
45306         return;
45307     }
45308
45309     ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks);   /* <-- This will free the heap allocation. */
45310 }
45311
45312 MA_API ma_result ma_loshelf2_reinit(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter)
45313 {
45314     ma_result result;
45315     ma_biquad_config bqConfig;
45316
45317     if (pFilter == NULL || pConfig == NULL) {
45318         return MA_INVALID_ARGS;
45319     }
45320
45321     bqConfig = ma_loshelf2__get_biquad_config(pConfig);
45322     result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
45323     if (result != MA_SUCCESS) {
45324         return result;
45325     }
45326
45327     return MA_SUCCESS;
45328 }
45329
45330 static MA_INLINE void ma_loshelf2_process_pcm_frame_s16(ma_loshelf2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
45331 {
45332     ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
45333 }
45334
45335 static MA_INLINE void ma_loshelf2_process_pcm_frame_f32(ma_loshelf2* pFilter, float* pFrameOut, const float* pFrameIn)
45336 {
45337     ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
45338 }
45339
45340 MA_API ma_result ma_loshelf2_process_pcm_frames(ma_loshelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
45341 {
45342     if (pFilter == NULL) {
45343         return MA_INVALID_ARGS;
45344     }
45345
45346     return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
45347 }
45348
45349 MA_API ma_uint32 ma_loshelf2_get_latency(const ma_loshelf2* pFilter)
45350 {
45351     if (pFilter == NULL) {
45352         return 0;
45353     }
45354
45355     return ma_biquad_get_latency(&pFilter->bq);
45356 }
45357
45358
45359 /**************************************************************************************************************************************************************
45360
45361 High Shelf Filter
45362
45363 **************************************************************************************************************************************************************/
45364 MA_API ma_hishelf2_config ma_hishelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency)
45365 {
45366     ma_hishelf2_config config;
45367
45368     MA_ZERO_OBJECT(&config);
45369     config.format     = format;
45370     config.channels   = channels;
45371     config.sampleRate = sampleRate;
45372     config.gainDB     = gainDB;
45373     config.shelfSlope = shelfSlope;
45374     config.frequency  = frequency;
45375
45376     return config;
45377 }
45378
45379
45380 static MA_INLINE ma_biquad_config ma_hishelf2__get_biquad_config(const ma_hishelf2_config* pConfig)
45381 {
45382     ma_biquad_config bqConfig;
45383     double w;
45384     double s;
45385     double c;
45386     double A;
45387     double S;
45388     double a;
45389     double sqrtA;
45390
45391     MA_ASSERT(pConfig != NULL);
45392
45393     w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
45394     s = ma_sind(w);
45395     c = ma_cosd(w);
45396     A = ma_powd(10, (pConfig->gainDB / 40));
45397     S = pConfig->shelfSlope;
45398     a = s/2 * ma_sqrtd((A + 1/A) * (1/S - 1) + 2);
45399     sqrtA = 2*ma_sqrtd(A)*a;
45400
45401     bqConfig.b0 =  A * ((A + 1) + (A - 1)*c + sqrtA);
45402     bqConfig.b1 = -2 * A * ((A - 1) + (A + 1)*c);
45403     bqConfig.b2 =  A * ((A + 1) + (A - 1)*c - sqrtA);
45404     bqConfig.a0 =  (A + 1) - (A - 1)*c + sqrtA;
45405     bqConfig.a1 =  2 * ((A - 1) - (A + 1)*c);
45406     bqConfig.a2 =  (A + 1) - (A - 1)*c - sqrtA;
45407
45408     bqConfig.format   = pConfig->format;
45409     bqConfig.channels = pConfig->channels;
45410
45411     return bqConfig;
45412 }
45413
45414 MA_API ma_result ma_hishelf2_get_heap_size(const ma_hishelf2_config* pConfig, size_t* pHeapSizeInBytes)
45415 {
45416     ma_biquad_config bqConfig;
45417     bqConfig = ma_hishelf2__get_biquad_config(pConfig);
45418
45419     return ma_biquad_get_heap_size(&bqConfig, pHeapSizeInBytes);
45420 }
45421
45422 MA_API ma_result ma_hishelf2_init_preallocated(const ma_hishelf2_config* pConfig, void* pHeap, ma_hishelf2* pFilter)
45423 {
45424     ma_result result;
45425     ma_biquad_config bqConfig;
45426
45427     if (pFilter == NULL) {
45428         return MA_INVALID_ARGS;
45429     }
45430
45431     MA_ZERO_OBJECT(pFilter);
45432
45433     if (pConfig == NULL) {
45434         return MA_INVALID_ARGS;
45435     }
45436
45437     bqConfig = ma_hishelf2__get_biquad_config(pConfig);
45438     result = ma_biquad_init_preallocated(&bqConfig, pHeap, &pFilter->bq);
45439     if (result != MA_SUCCESS) {
45440         return result;
45441     }
45442
45443     return MA_SUCCESS;
45444 }
45445
45446 MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf2* pFilter)
45447 {
45448     ma_result result;
45449     size_t heapSizeInBytes;
45450     void* pHeap;
45451
45452     result = ma_hishelf2_get_heap_size(pConfig, &heapSizeInBytes);
45453     if (result != MA_SUCCESS) {
45454         return result;
45455     }
45456
45457     if (heapSizeInBytes > 0) {
45458         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
45459         if (pHeap == NULL) {
45460             return MA_OUT_OF_MEMORY;
45461         }
45462     } else {
45463         pHeap = NULL;
45464     }
45465
45466     result = ma_hishelf2_init_preallocated(pConfig, pHeap, pFilter);
45467     if (result != MA_SUCCESS) {
45468         ma_free(pHeap, pAllocationCallbacks);
45469         return result;
45470     }
45471
45472     pFilter->bq._ownsHeap = MA_TRUE;    /* <-- This will cause the biquad to take ownership of the heap and free it when it's uninitialized. */
45473     return MA_SUCCESS;
45474 }
45475
45476 MA_API void ma_hishelf2_uninit(ma_hishelf2* pFilter, const ma_allocation_callbacks* pAllocationCallbacks)
45477 {
45478     if (pFilter == NULL) {
45479         return;
45480     }
45481
45482     ma_biquad_uninit(&pFilter->bq, pAllocationCallbacks);   /* <-- This will free the heap allocation. */
45483 }
45484
45485 MA_API ma_result ma_hishelf2_reinit(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter)
45486 {
45487     ma_result result;
45488     ma_biquad_config bqConfig;
45489
45490     if (pFilter == NULL || pConfig == NULL) {
45491         return MA_INVALID_ARGS;
45492     }
45493
45494     bqConfig = ma_hishelf2__get_biquad_config(pConfig);
45495     result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
45496     if (result != MA_SUCCESS) {
45497         return result;
45498     }
45499
45500     return MA_SUCCESS;
45501 }
45502
45503 static MA_INLINE void ma_hishelf2_process_pcm_frame_s16(ma_hishelf2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
45504 {
45505     ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
45506 }
45507
45508 static MA_INLINE void ma_hishelf2_process_pcm_frame_f32(ma_hishelf2* pFilter, float* pFrameOut, const float* pFrameIn)
45509 {
45510     ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
45511 }
45512
45513 MA_API ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
45514 {
45515     if (pFilter == NULL) {
45516         return MA_INVALID_ARGS;
45517     }
45518
45519     return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
45520 }
45521
45522 MA_API ma_uint32 ma_hishelf2_get_latency(const ma_hishelf2* pFilter)
45523 {
45524     if (pFilter == NULL) {
45525         return 0;
45526     }
45527
45528     return ma_biquad_get_latency(&pFilter->bq);
45529 }
45530
45531
45532
45533 /*
45534 Delay
45535 */
45536 MA_API ma_delay_config ma_delay_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay)
45537 {
45538     ma_delay_config config;
45539
45540     MA_ZERO_OBJECT(&config);
45541     config.channels      = channels;
45542     config.sampleRate    = sampleRate;
45543     config.delayInFrames = delayInFrames;
45544     config.delayStart    = (decay == 0) ? MA_TRUE : MA_FALSE;   /* Delay the start if it looks like we're not configuring an echo. */
45545     config.wet           = 1;
45546     config.dry           = 1;
45547     config.decay         = decay;
45548
45549     return config;
45550 }
45551
45552
45553 MA_API ma_result ma_delay_init(const ma_delay_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay* pDelay)
45554 {
45555     if (pDelay == NULL) {
45556         return MA_INVALID_ARGS;
45557     }
45558
45559     MA_ZERO_OBJECT(pDelay);
45560
45561     if (pConfig == NULL) {
45562         return MA_INVALID_ARGS;
45563     }
45564
45565     if (pConfig->decay < 0 || pConfig->decay > 1) {
45566         return MA_INVALID_ARGS;
45567     }
45568
45569     pDelay->config             = *pConfig;
45570     pDelay->bufferSizeInFrames = pConfig->delayInFrames;
45571     pDelay->cursor             = 0;
45572
45573     pDelay->pBuffer = (float*)ma_malloc((size_t)(pDelay->bufferSizeInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->channels)), pAllocationCallbacks);
45574     if (pDelay->pBuffer == NULL) {
45575         return MA_OUT_OF_MEMORY;
45576     }
45577
45578     ma_silence_pcm_frames(pDelay->pBuffer, pDelay->bufferSizeInFrames, ma_format_f32, pConfig->channels);
45579
45580     return MA_SUCCESS;
45581 }
45582
45583 MA_API void ma_delay_uninit(ma_delay* pDelay, const ma_allocation_callbacks* pAllocationCallbacks)
45584 {
45585     if (pDelay == NULL) {
45586         return;
45587     }
45588
45589     ma_free(pDelay->pBuffer, pAllocationCallbacks);
45590 }
45591
45592 MA_API ma_result ma_delay_process_pcm_frames(ma_delay* pDelay, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
45593 {
45594     ma_uint32 iFrame;
45595     ma_uint32 iChannel;
45596     float* pFramesOutF32 = (float*)pFramesOut;
45597     const float* pFramesInF32 = (const float*)pFramesIn;
45598
45599     if (pDelay == NULL || pFramesOut == NULL || pFramesIn == NULL) {
45600         return MA_INVALID_ARGS;
45601     }
45602
45603     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
45604         for (iChannel = 0; iChannel < pDelay->config.channels; iChannel += 1) {
45605             ma_uint32 iBuffer = (pDelay->cursor * pDelay->config.channels) + iChannel;
45606
45607             if (pDelay->config.delayStart) {
45608                 /* Delayed start. */
45609
45610                 /* Read */
45611                 pFramesOutF32[iChannel] = pDelay->pBuffer[iBuffer] * pDelay->config.wet;
45612
45613                 /* Feedback */
45614                 pDelay->pBuffer[iBuffer] = (pDelay->pBuffer[iBuffer] * pDelay->config.decay) + (pFramesInF32[iChannel] * pDelay->config.dry);
45615             } else {
45616                 /* Immediate start */
45617
45618                 /* Feedback */
45619                 pDelay->pBuffer[iBuffer] = (pDelay->pBuffer[iBuffer] * pDelay->config.decay) + (pFramesInF32[iChannel] * pDelay->config.dry);
45620
45621                 /* Read */
45622                 pFramesOutF32[iChannel] = pDelay->pBuffer[iBuffer] * pDelay->config.wet;
45623             }
45624         }
45625
45626         pDelay->cursor = (pDelay->cursor + 1) % pDelay->bufferSizeInFrames;
45627
45628         pFramesOutF32 += pDelay->config.channels;
45629         pFramesInF32  += pDelay->config.channels;
45630     }
45631
45632     return MA_SUCCESS;
45633 }
45634
45635 MA_API void ma_delay_set_wet(ma_delay* pDelay, float value)
45636 {
45637     if (pDelay == NULL) {
45638         return;
45639     }
45640
45641     pDelay->config.wet = value;
45642 }
45643
45644 MA_API float ma_delay_get_wet(const ma_delay* pDelay)
45645 {
45646     if (pDelay == NULL) {
45647         return 0;
45648     }
45649
45650     return pDelay->config.wet;
45651 }
45652
45653 MA_API void ma_delay_set_dry(ma_delay* pDelay, float value)
45654 {
45655     if (pDelay == NULL) {
45656         return;
45657     }
45658
45659     pDelay->config.dry = value;
45660 }
45661
45662 MA_API float ma_delay_get_dry(const ma_delay* pDelay)
45663 {
45664     if (pDelay == NULL) {
45665         return 0;
45666     }
45667
45668     return pDelay->config.dry;
45669 }
45670
45671 MA_API void ma_delay_set_decay(ma_delay* pDelay, float value)
45672 {
45673     if (pDelay == NULL) {
45674         return;
45675     }
45676
45677     pDelay->config.decay = value;
45678 }
45679
45680 MA_API float ma_delay_get_decay(const ma_delay* pDelay)
45681 {
45682     if (pDelay == NULL) {
45683         return 0;
45684     }
45685
45686     return pDelay->config.decay;
45687 }
45688
45689
45690 MA_API ma_gainer_config ma_gainer_config_init(ma_uint32 channels, ma_uint32 smoothTimeInFrames)
45691 {
45692     ma_gainer_config config;
45693
45694     MA_ZERO_OBJECT(&config);
45695     config.channels           = channels;
45696     config.smoothTimeInFrames = smoothTimeInFrames;
45697
45698     return config;
45699 }
45700
45701
45702 typedef struct
45703 {
45704     size_t sizeInBytes;
45705     size_t oldGainsOffset;
45706     size_t newGainsOffset;
45707 } ma_gainer_heap_layout;
45708
45709 static ma_result ma_gainer_get_heap_layout(const ma_gainer_config* pConfig, ma_gainer_heap_layout* pHeapLayout)
45710 {
45711     MA_ASSERT(pHeapLayout != NULL);
45712
45713     MA_ZERO_OBJECT(pHeapLayout);
45714
45715     if (pConfig == NULL) {
45716         return MA_INVALID_ARGS;
45717     }
45718
45719     if (pConfig->channels == 0) {
45720         return MA_INVALID_ARGS;
45721     }
45722
45723     pHeapLayout->sizeInBytes = 0;
45724
45725     /* Old gains. */
45726     pHeapLayout->oldGainsOffset = pHeapLayout->sizeInBytes;
45727     pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels;
45728
45729     /* New gains. */
45730     pHeapLayout->newGainsOffset = pHeapLayout->sizeInBytes;
45731     pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels;
45732
45733     /* Alignment. */
45734     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
45735
45736     return MA_SUCCESS;
45737 }
45738
45739
45740 MA_API ma_result ma_gainer_get_heap_size(const ma_gainer_config* pConfig, size_t* pHeapSizeInBytes)
45741 {
45742     ma_result result;
45743     ma_gainer_heap_layout heapLayout;
45744
45745     if (pHeapSizeInBytes == NULL) {
45746         return MA_INVALID_ARGS;
45747     }
45748
45749     *pHeapSizeInBytes = 0;
45750
45751     result = ma_gainer_get_heap_layout(pConfig, &heapLayout);
45752     if (result != MA_SUCCESS) {
45753         return MA_INVALID_ARGS;
45754     }
45755
45756     *pHeapSizeInBytes = heapLayout.sizeInBytes;
45757
45758     return MA_SUCCESS;
45759 }
45760
45761
45762 MA_API ma_result ma_gainer_init_preallocated(const ma_gainer_config* pConfig, void* pHeap, ma_gainer* pGainer)
45763 {
45764     ma_result result;
45765     ma_gainer_heap_layout heapLayout;
45766     ma_uint32 iChannel;
45767
45768     if (pGainer == NULL) {
45769         return MA_INVALID_ARGS;
45770     }
45771
45772     MA_ZERO_OBJECT(pGainer);
45773
45774     if (pConfig == NULL || pHeap == NULL) {
45775         return MA_INVALID_ARGS;
45776     }
45777
45778     result = ma_gainer_get_heap_layout(pConfig, &heapLayout);
45779     if (result != MA_SUCCESS) {
45780         return result;
45781     }
45782
45783     pGainer->_pHeap = pHeap;
45784     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
45785
45786     pGainer->pOldGains = (float*)ma_offset_ptr(pHeap, heapLayout.oldGainsOffset);
45787     pGainer->pNewGains = (float*)ma_offset_ptr(pHeap, heapLayout.newGainsOffset);
45788
45789     pGainer->config = *pConfig;
45790     pGainer->t      = (ma_uint32)-1;  /* No interpolation by default. */
45791
45792     for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) {
45793         pGainer->pOldGains[iChannel] = 1;
45794         pGainer->pNewGains[iChannel] = 1;
45795     }
45796
45797     return MA_SUCCESS;
45798 }
45799
45800 MA_API ma_result ma_gainer_init(const ma_gainer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_gainer* pGainer)
45801 {
45802     ma_result result;
45803     size_t heapSizeInBytes;
45804     void* pHeap;
45805
45806     result = ma_gainer_get_heap_size(pConfig, &heapSizeInBytes);
45807     if (result != MA_SUCCESS) {
45808         return result;  /* Failed to retrieve the size of the heap allocation. */
45809     }
45810
45811     if (heapSizeInBytes > 0) {
45812         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
45813         if (pHeap == NULL) {
45814             return MA_OUT_OF_MEMORY;
45815         }
45816     } else {
45817         pHeap = NULL;
45818     }
45819
45820     result = ma_gainer_init_preallocated(pConfig, pHeap, pGainer);
45821     if (result != MA_SUCCESS) {
45822         ma_free(pHeap, pAllocationCallbacks);
45823         return result;
45824     }
45825
45826     pGainer->_ownsHeap = MA_TRUE;
45827     return MA_SUCCESS;
45828 }
45829
45830 MA_API void ma_gainer_uninit(ma_gainer* pGainer, const ma_allocation_callbacks* pAllocationCallbacks)
45831 {
45832     if (pGainer == NULL) {
45833         return;
45834     }
45835
45836     if (pGainer->_ownsHeap) {
45837         ma_free(pGainer->_pHeap, pAllocationCallbacks);
45838     }
45839 }
45840
45841 static float ma_gainer_calculate_current_gain(const ma_gainer* pGainer, ma_uint32 channel)
45842 {
45843     float a = (float)pGainer->t / pGainer->config.smoothTimeInFrames;
45844     return ma_mix_f32_fast(pGainer->pOldGains[channel], pGainer->pNewGains[channel], a);
45845 }
45846
45847 MA_API ma_result ma_gainer_process_pcm_frames(ma_gainer* pGainer, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
45848 {
45849     ma_uint64 iFrame;
45850     ma_uint32 iChannel;
45851     float* pFramesOutF32 = (float*)pFramesOut;
45852     const float* pFramesInF32 = (const float*)pFramesIn;
45853
45854     if (pGainer == NULL) {
45855         return MA_INVALID_ARGS;
45856     }
45857
45858     if (pGainer->t >= pGainer->config.smoothTimeInFrames) {
45859         /* Fast path. No gain calculation required. */
45860         ma_copy_and_apply_volume_factor_per_channel_f32(pFramesOutF32, pFramesInF32, frameCount, pGainer->config.channels, pGainer->pNewGains);
45861
45862         /* Now that some frames have been processed we need to make sure future changes to the gain are interpolated. */
45863         if (pGainer->t == (ma_uint32)-1) {
45864             pGainer->t = pGainer->config.smoothTimeInFrames;
45865         }
45866     } else {
45867         /* Slow path. Need to interpolate the gain for each channel individually. */
45868
45869         /* We can allow the input and output buffers to be null in which case we'll just update the internal timer. */
45870         if (pFramesOut != NULL && pFramesIn != NULL) {
45871             float a = (float)pGainer->t / pGainer->config.smoothTimeInFrames;
45872             float d = 1.0f / pGainer->config.smoothTimeInFrames;
45873             ma_uint32 channelCount = pGainer->config.channels;
45874
45875             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
45876                 for (iChannel = 0; iChannel < channelCount; iChannel += 1) {
45877                     pFramesOutF32[iChannel] = pFramesInF32[iChannel] * ma_mix_f32_fast(pGainer->pOldGains[iChannel], pGainer->pNewGains[iChannel], a);
45878                 }
45879
45880                 pFramesOutF32 += channelCount;
45881                 pFramesInF32  += channelCount;
45882
45883                 a += d;
45884                 if (a > 1) {
45885                     a = 1;
45886                 }
45887             }
45888         }
45889
45890         pGainer->t = (ma_uint32)ma_min(pGainer->t + frameCount, pGainer->config.smoothTimeInFrames);
45891
45892     #if 0   /* Reference implementation. */
45893         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
45894             /* We can allow the input and output buffers to be null in which case we'll just update the internal timer. */
45895             if (pFramesOut != NULL && pFramesIn != NULL) {
45896                 for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) {
45897                     pFramesOutF32[iFrame*pGainer->config.channels + iChannel] = pFramesInF32[iFrame*pGainer->config.channels + iChannel] * ma_gainer_calculate_current_gain(pGainer, iChannel);
45898                 }
45899             }
45900
45901             /* Move interpolation time forward, but don't go beyond our smoothing time. */
45902             pGainer->t = ma_min(pGainer->t + 1, pGainer->config.smoothTimeInFrames);
45903         }
45904     #endif
45905     }
45906
45907     return MA_SUCCESS;
45908 }
45909
45910 static void ma_gainer_set_gain_by_index(ma_gainer* pGainer, float newGain, ma_uint32 iChannel)
45911 {
45912     pGainer->pOldGains[iChannel] = ma_gainer_calculate_current_gain(pGainer, iChannel);
45913     pGainer->pNewGains[iChannel] = newGain;
45914 }
45915
45916 static void ma_gainer_reset_smoothing_time(ma_gainer* pGainer)
45917 {
45918     if (pGainer->t == (ma_uint32)-1) {
45919         pGainer->t = pGainer->config.smoothTimeInFrames;    /* No smoothing required for initial gains setting. */
45920     } else {
45921         pGainer->t = 0;
45922     }
45923 }
45924
45925 MA_API ma_result ma_gainer_set_gain(ma_gainer* pGainer, float newGain)
45926 {
45927     ma_uint32 iChannel;
45928
45929     if (pGainer == NULL) {
45930         return MA_INVALID_ARGS;
45931     }
45932
45933     for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) {
45934         ma_gainer_set_gain_by_index(pGainer, newGain, iChannel);
45935     }
45936
45937     /* The smoothing time needs to be reset to ensure we always interpolate by the configured smoothing time, but only if it's not the first setting. */
45938     ma_gainer_reset_smoothing_time(pGainer);
45939
45940     return MA_SUCCESS;
45941 }
45942
45943 MA_API ma_result ma_gainer_set_gains(ma_gainer* pGainer, float* pNewGains)
45944 {
45945     ma_uint32 iChannel;
45946
45947     if (pGainer == NULL || pNewGains == NULL) {
45948         return MA_INVALID_ARGS;
45949     }
45950
45951     for (iChannel = 0; iChannel < pGainer->config.channels; iChannel += 1) {
45952         ma_gainer_set_gain_by_index(pGainer, pNewGains[iChannel], iChannel);
45953     }
45954
45955     /* The smoothing time needs to be reset to ensure we always interpolate by the configured smoothing time, but only if it's not the first setting. */
45956     ma_gainer_reset_smoothing_time(pGainer);
45957
45958     return MA_SUCCESS;
45959 }
45960
45961
45962 MA_API ma_panner_config ma_panner_config_init(ma_format format, ma_uint32 channels)
45963 {
45964     ma_panner_config config;
45965
45966     MA_ZERO_OBJECT(&config);
45967     config.format   = format;
45968     config.channels = channels;
45969     config.mode     = ma_pan_mode_balance;  /* Set to balancing mode by default because it's consistent with other audio engines and most likely what the caller is expecting. */
45970     config.pan      = 0;
45971
45972     return config;
45973 }
45974
45975
45976 MA_API ma_result ma_panner_init(const ma_panner_config* pConfig, ma_panner* pPanner)
45977 {
45978     if (pPanner == NULL) {
45979         return MA_INVALID_ARGS;
45980     }
45981
45982     MA_ZERO_OBJECT(pPanner);
45983
45984     if (pConfig == NULL) {
45985         return MA_INVALID_ARGS;
45986     }
45987
45988     pPanner->format   = pConfig->format;
45989     pPanner->channels = pConfig->channels;
45990     pPanner->mode     = pConfig->mode;
45991     pPanner->pan      = pConfig->pan;
45992
45993     return MA_SUCCESS;
45994 }
45995
45996 static void ma_stereo_balance_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, float pan)
45997 {
45998     ma_uint64 iFrame;
45999
46000     if (pan > 0) {
46001         float factor = 1.0f - pan;
46002         if (pFramesOut == pFramesIn) {
46003             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
46004                 pFramesOut[iFrame*2 + 0] = pFramesIn[iFrame*2 + 0] * factor;
46005             }
46006         } else {
46007             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
46008                 pFramesOut[iFrame*2 + 0] = pFramesIn[iFrame*2 + 0] * factor;
46009                 pFramesOut[iFrame*2 + 1] = pFramesIn[iFrame*2 + 1];
46010             }
46011         }
46012     } else {
46013         float factor = 1.0f + pan;
46014         if (pFramesOut == pFramesIn) {
46015             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
46016                 pFramesOut[iFrame*2 + 1] = pFramesIn[iFrame*2 + 1] * factor;
46017             }
46018         } else {
46019             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
46020                 pFramesOut[iFrame*2 + 0] = pFramesIn[iFrame*2 + 0];
46021                 pFramesOut[iFrame*2 + 1] = pFramesIn[iFrame*2 + 1] * factor;
46022             }
46023         }
46024     }
46025 }
46026
46027 static void ma_stereo_balance_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, float pan)
46028 {
46029     if (pan == 0) {
46030         /* Fast path. No panning required. */
46031         if (pFramesOut == pFramesIn) {
46032             /* No-op */
46033         } else {
46034             ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2);
46035         }
46036
46037         return;
46038     }
46039
46040     switch (format) {
46041         case ma_format_f32: ma_stereo_balance_pcm_frames_f32((float*)pFramesOut, (float*)pFramesIn, frameCount, pan); break;
46042
46043         /* Unknown format. Just copy. */
46044         default:
46045         {
46046             ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2);
46047         } break;
46048     }
46049 }
46050
46051
46052 static void ma_stereo_pan_pcm_frames_f32(float* pFramesOut, const float* pFramesIn, ma_uint64 frameCount, float pan)
46053 {
46054     ma_uint64 iFrame;
46055
46056     if (pan > 0) {
46057         float factorL0 = 1.0f - pan;
46058         float factorL1 = 0.0f + pan;
46059
46060         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
46061             float sample0 = (pFramesIn[iFrame*2 + 0] * factorL0);
46062             float sample1 = (pFramesIn[iFrame*2 + 0] * factorL1) + pFramesIn[iFrame*2 + 1];
46063
46064             pFramesOut[iFrame*2 + 0] = sample0;
46065             pFramesOut[iFrame*2 + 1] = sample1;
46066         }
46067     } else {
46068         float factorR0 = 0.0f - pan;
46069         float factorR1 = 1.0f + pan;
46070
46071         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
46072             float sample0 = pFramesIn[iFrame*2 + 0] + (pFramesIn[iFrame*2 + 1] * factorR0);
46073             float sample1 =                           (pFramesIn[iFrame*2 + 1] * factorR1);
46074
46075             pFramesOut[iFrame*2 + 0] = sample0;
46076             pFramesOut[iFrame*2 + 1] = sample1;
46077         }
46078     }
46079 }
46080
46081 static void ma_stereo_pan_pcm_frames(void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount, ma_format format, float pan)
46082 {
46083     if (pan == 0) {
46084         /* Fast path. No panning required. */
46085         if (pFramesOut == pFramesIn) {
46086             /* No-op */
46087         } else {
46088             ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2);
46089         }
46090
46091         return;
46092     }
46093
46094     switch (format) {
46095         case ma_format_f32: ma_stereo_pan_pcm_frames_f32((float*)pFramesOut, (float*)pFramesIn, frameCount, pan); break;
46096
46097         /* Unknown format. Just copy. */
46098         default:
46099         {
46100             ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, format, 2);
46101         } break;
46102     }
46103 }
46104
46105 MA_API ma_result ma_panner_process_pcm_frames(ma_panner* pPanner, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
46106 {
46107     if (pPanner == NULL || pFramesOut == NULL || pFramesIn == NULL) {
46108         return MA_INVALID_ARGS;
46109     }
46110
46111     if (pPanner->channels == 2) {
46112         /* Stereo case. For now assume channel 0 is left and channel right is 1, but should probably add support for a channel map. */
46113         if (pPanner->mode == ma_pan_mode_balance) {
46114             ma_stereo_balance_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->pan);
46115         } else {
46116             ma_stereo_pan_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->pan);
46117         }
46118     } else {
46119         if (pPanner->channels == 1) {
46120             /* Panning has no effect on mono streams. */
46121             ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->channels);
46122         } else {
46123             /* For now we're not going to support non-stereo set ups. Not sure how I want to handle this case just yet. */
46124             ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, pPanner->format, pPanner->channels);
46125         }
46126     }
46127
46128     return MA_SUCCESS;
46129 }
46130
46131 MA_API void ma_panner_set_mode(ma_panner* pPanner, ma_pan_mode mode)
46132 {
46133     if (pPanner == NULL) {
46134         return;
46135     }
46136
46137     pPanner->mode = mode;
46138 }
46139
46140 MA_API ma_pan_mode ma_panner_get_mode(const ma_panner* pPanner)
46141 {
46142     if (pPanner == NULL) {
46143         return ma_pan_mode_balance;
46144     }
46145
46146     return pPanner->mode;
46147 }
46148
46149 MA_API void ma_panner_set_pan(ma_panner* pPanner, float pan)
46150 {
46151     if (pPanner == NULL) {
46152         return;
46153     }
46154
46155     pPanner->pan = ma_clamp(pan, -1.0f, 1.0f);
46156 }
46157
46158 MA_API float ma_panner_get_pan(const ma_panner* pPanner)
46159 {
46160     if (pPanner == NULL) {
46161         return 0;
46162     }
46163
46164     return pPanner->pan;
46165 }
46166
46167
46168
46169
46170 MA_API ma_fader_config ma_fader_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
46171 {
46172     ma_fader_config config;
46173
46174     MA_ZERO_OBJECT(&config);
46175     config.format     = format;
46176     config.channels   = channels;
46177     config.sampleRate = sampleRate;
46178
46179     return config;
46180 }
46181
46182
46183 MA_API ma_result ma_fader_init(const ma_fader_config* pConfig, ma_fader* pFader)
46184 {
46185     if (pFader == NULL) {
46186         return MA_INVALID_ARGS;
46187     }
46188
46189     MA_ZERO_OBJECT(pFader);
46190
46191     if (pConfig == NULL) {
46192         return MA_INVALID_ARGS;
46193     }
46194
46195     /* Only f32 is supported for now. */
46196     if (pConfig->format != ma_format_f32) {
46197         return MA_INVALID_ARGS;
46198     }
46199
46200     pFader->config         = *pConfig;
46201     pFader->volumeBeg      = 1;
46202     pFader->volumeEnd      = 1;
46203     pFader->lengthInFrames = 0;
46204     pFader->cursorInFrames = 0;
46205
46206     return MA_SUCCESS;
46207 }
46208
46209 MA_API ma_result ma_fader_process_pcm_frames(ma_fader* pFader, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
46210 {
46211     if (pFader == NULL) {
46212         return MA_INVALID_ARGS;
46213     }
46214
46215     /*
46216     For now we need to clamp frameCount so that the cursor never overflows 32-bits. This is required for
46217     the conversion to a float which we use for the linear interpolation. This might be changed later.
46218     */
46219     if (frameCount + pFader->cursorInFrames > UINT_MAX) {
46220         frameCount = UINT_MAX - pFader->cursorInFrames;
46221     }
46222
46223     /* Optimized path if volumeBeg and volumeEnd are equal. */
46224     if (pFader->volumeBeg == pFader->volumeEnd) {
46225         if (pFader->volumeBeg == 1) {
46226             /* Straight copy. */
46227             ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, pFader->config.format, pFader->config.channels);
46228         } else {
46229             /* Copy with volume. */
46230             ma_copy_and_apply_volume_and_clip_pcm_frames(pFramesOut, pFramesIn, frameCount, pFader->config.format, pFader->config.channels, pFader->volumeEnd);
46231         }
46232     } else {
46233         /* Slower path. Volumes are different, so may need to do an interpolation. */
46234         if (pFader->cursorInFrames >= pFader->lengthInFrames) {
46235             /* Fast path. We've gone past the end of the fade period so just apply the end volume to all samples. */
46236             ma_copy_and_apply_volume_and_clip_pcm_frames(pFramesOut, pFramesIn, frameCount, pFader->config.format, pFader->config.channels, pFader->volumeEnd);
46237         } else {
46238             /* Slow path. This is where we do the actual fading. */
46239             ma_uint64 iFrame;
46240             ma_uint32 iChannel;
46241
46242             /* For now we only support f32. Support for other formats will be added later. */
46243             if (pFader->config.format == ma_format_f32) {
46244                 const float* pFramesInF32  = (const float*)pFramesIn;
46245                 /* */ float* pFramesOutF32 = (      float*)pFramesOut;
46246
46247                 for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
46248                     float a = (ma_uint32)ma_min(pFader->cursorInFrames + iFrame, pFader->lengthInFrames) / (float)((ma_uint32)pFader->lengthInFrames);   /* Safe cast due to the frameCount clamp at the top of this function. */
46249                     float volume = ma_mix_f32_fast(pFader->volumeBeg, pFader->volumeEnd, a);
46250
46251                     for (iChannel = 0; iChannel < pFader->config.channels; iChannel += 1) {
46252                         pFramesOutF32[iFrame*pFader->config.channels + iChannel] = pFramesInF32[iFrame*pFader->config.channels + iChannel] * volume;
46253                     }
46254                 }
46255             } else {
46256                 return MA_NOT_IMPLEMENTED;
46257             }
46258         }
46259     }
46260
46261     pFader->cursorInFrames += frameCount;
46262
46263     return MA_SUCCESS;
46264 }
46265
46266 MA_API void ma_fader_get_data_format(const ma_fader* pFader, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate)
46267 {
46268     if (pFader == NULL) {
46269         return;
46270     }
46271
46272     if (pFormat != NULL) {
46273         *pFormat = pFader->config.format;
46274     }
46275
46276     if (pChannels != NULL) {
46277         *pChannels = pFader->config.channels;
46278     }
46279
46280     if (pSampleRate != NULL) {
46281         *pSampleRate = pFader->config.sampleRate;
46282     }
46283 }
46284
46285 MA_API void ma_fader_set_fade(ma_fader* pFader, float volumeBeg, float volumeEnd, ma_uint64 lengthInFrames)
46286 {
46287     if (pFader == NULL) {
46288         return;
46289     }
46290
46291     /* If the volume is negative, use current volume. */
46292     if (volumeBeg < 0) {
46293         volumeBeg = ma_fader_get_current_volume(pFader);
46294     }
46295
46296     /*
46297     The length needs to be clamped to 32-bits due to how we convert it to a float for linear
46298     interpolation reasons. I might change this requirement later, but for now it's not important.
46299     */
46300     if (lengthInFrames > UINT_MAX) {
46301         lengthInFrames = UINT_MAX;
46302     }
46303
46304     pFader->volumeBeg      = volumeBeg;
46305     pFader->volumeEnd      = volumeEnd;
46306     pFader->lengthInFrames = lengthInFrames;
46307     pFader->cursorInFrames = 0; /* Reset cursor. */
46308 }
46309
46310 MA_API float ma_fader_get_current_volume(ma_fader* pFader)
46311 {
46312     if (pFader == NULL) {
46313         return 0.0f;
46314     }
46315
46316     /* The current volume depends on the position of the cursor. */
46317     if (pFader->cursorInFrames == 0) {
46318         return pFader->volumeBeg;
46319     } else if (pFader->cursorInFrames >= pFader->lengthInFrames) {
46320         return pFader->volumeEnd;
46321     } else {
46322         /* The cursor is somewhere inside the fading period. We can figure this out with a simple linear interpoluation between volumeBeg and volumeEnd based on our cursor position. */
46323         return ma_mix_f32_fast(pFader->volumeBeg, pFader->volumeEnd, (ma_uint32)pFader->cursorInFrames / (float)((ma_uint32)pFader->lengthInFrames));    /* Safe cast to uint32 because we clamp it in ma_fader_process_pcm_frames(). */
46324     }
46325 }
46326
46327
46328
46329
46330
46331 MA_API ma_vec3f ma_vec3f_init_3f(float x, float y, float z)
46332 {
46333     ma_vec3f v;
46334
46335     v.x = x;
46336     v.y = y;
46337     v.z = z;
46338
46339     return v;
46340 }
46341
46342 MA_API ma_vec3f ma_vec3f_sub(ma_vec3f a, ma_vec3f b)
46343 {
46344     return ma_vec3f_init_3f(
46345         a.x - b.x,
46346         a.y - b.y,
46347         a.z - b.z
46348     );
46349 }
46350
46351 MA_API ma_vec3f ma_vec3f_neg(ma_vec3f a)
46352 {
46353     return ma_vec3f_init_3f(
46354         -a.x,
46355         -a.y,
46356         -a.z
46357     );
46358 }
46359
46360 MA_API float ma_vec3f_dot(ma_vec3f a, ma_vec3f b)
46361 {
46362     return a.x*b.x + a.y*b.y + a.z*b.z;
46363 }
46364
46365 MA_API float ma_vec3f_len2(ma_vec3f v)
46366 {
46367     return ma_vec3f_dot(v, v);
46368 }
46369
46370 MA_API float ma_vec3f_len(ma_vec3f v)
46371 {
46372     return (float)ma_sqrtd(ma_vec3f_len2(v));
46373 }
46374
46375 MA_API float ma_vec3f_dist(ma_vec3f a, ma_vec3f b)
46376 {
46377     return ma_vec3f_len(ma_vec3f_sub(a, b));
46378 }
46379
46380 MA_API ma_vec3f ma_vec3f_normalize(ma_vec3f v)
46381 {
46382     float f;
46383     float l = ma_vec3f_len(v);
46384     if (l == 0) {
46385         return ma_vec3f_init_3f(0, 0, 0);
46386     }
46387
46388     f = 1 / l;
46389     v.x *= f;
46390     v.y *= f;
46391     v.z *= f;
46392
46393     return v;
46394 }
46395
46396 MA_API ma_vec3f ma_vec3f_cross(ma_vec3f a, ma_vec3f b)
46397 {
46398     return ma_vec3f_init_3f(
46399         a.y*b.z - a.z*b.y,
46400         a.z*b.x - a.x*b.z,
46401         a.x*b.y - a.y*b.x
46402     );
46403 }
46404
46405
46406
46407 static void ma_channel_map_apply_f32(float* pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* pFramesIn, const ma_channel* pChannelMapIn, ma_uint32 channelsIn, ma_uint64 frameCount, ma_channel_mix_mode mode, ma_mono_expansion_mode monoExpansionMode);
46408 static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition);
46409
46410
46411 #ifndef MA_DEFAULT_SPEED_OF_SOUND
46412 #define MA_DEFAULT_SPEED_OF_SOUND   343.3f
46413 #endif
46414
46415 /*
46416 These vectors represent the direction that speakers are facing from the center point. They're used
46417 for panning in the spatializer. Must be normalized.
46418 */
46419 static ma_vec3f g_maChannelDirections[MA_CHANNEL_POSITION_COUNT] = {
46420     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_NONE */
46421     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_MONO */
46422     {-0.7071f,  0.0f,    -0.7071f },  /* MA_CHANNEL_FRONT_LEFT */
46423     {+0.7071f,  0.0f,    -0.7071f },  /* MA_CHANNEL_FRONT_RIGHT */
46424     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_FRONT_CENTER */
46425     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_LFE */
46426     {-0.7071f,  0.0f,    +0.7071f },  /* MA_CHANNEL_BACK_LEFT */
46427     {+0.7071f,  0.0f,    +0.7071f },  /* MA_CHANNEL_BACK_RIGHT */
46428     {-0.3162f,  0.0f,    -0.9487f },  /* MA_CHANNEL_FRONT_LEFT_CENTER */
46429     {+0.3162f,  0.0f,    -0.9487f },  /* MA_CHANNEL_FRONT_RIGHT_CENTER */
46430     { 0.0f,     0.0f,    +1.0f    },  /* MA_CHANNEL_BACK_CENTER */
46431     {-1.0f,     0.0f,     0.0f    },  /* MA_CHANNEL_SIDE_LEFT */
46432     {+1.0f,     0.0f,     0.0f    },  /* MA_CHANNEL_SIDE_RIGHT */
46433     { 0.0f,    +1.0f,     0.0f    },  /* MA_CHANNEL_TOP_CENTER */
46434     {-0.5774f, +0.5774f, -0.5774f },  /* MA_CHANNEL_TOP_FRONT_LEFT */
46435     { 0.0f,    +0.7071f, -0.7071f },  /* MA_CHANNEL_TOP_FRONT_CENTER */
46436     {+0.5774f, +0.5774f, -0.5774f },  /* MA_CHANNEL_TOP_FRONT_RIGHT */
46437     {-0.5774f, +0.5774f, +0.5774f },  /* MA_CHANNEL_TOP_BACK_LEFT */
46438     { 0.0f,    +0.7071f, +0.7071f },  /* MA_CHANNEL_TOP_BACK_CENTER */
46439     {+0.5774f, +0.5774f, +0.5774f },  /* MA_CHANNEL_TOP_BACK_RIGHT */
46440     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_0 */
46441     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_1 */
46442     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_2 */
46443     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_3 */
46444     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_4 */
46445     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_5 */
46446     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_6 */
46447     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_7 */
46448     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_8 */
46449     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_9 */
46450     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_10 */
46451     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_11 */
46452     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_12 */
46453     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_13 */
46454     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_14 */
46455     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_15 */
46456     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_16 */
46457     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_17 */
46458     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_18 */
46459     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_19 */
46460     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_20 */
46461     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_21 */
46462     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_22 */
46463     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_23 */
46464     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_24 */
46465     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_25 */
46466     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_26 */
46467     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_27 */
46468     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_28 */
46469     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_29 */
46470     { 0.0f,     0.0f,    -1.0f    },  /* MA_CHANNEL_AUX_30 */
46471     { 0.0f,     0.0f,    -1.0f    }   /* MA_CHANNEL_AUX_31 */
46472 };
46473
46474 static ma_vec3f ma_get_channel_direction(ma_channel channel)
46475 {
46476     if (channel >= MA_CHANNEL_POSITION_COUNT) {
46477         return ma_vec3f_init_3f(0, 0, -1);
46478     } else {
46479         return g_maChannelDirections[channel];
46480     }
46481 }
46482
46483
46484
46485 static float ma_attenuation_inverse(float distance, float minDistance, float maxDistance, float rolloff)
46486 {
46487     if (minDistance >= maxDistance) {
46488         return 1;   /* To avoid division by zero. Do not attenuate. */
46489     }
46490
46491     return minDistance / (minDistance + rolloff * (ma_clamp(distance, minDistance, maxDistance) - minDistance));
46492 }
46493
46494 static float ma_attenuation_linear(float distance, float minDistance, float maxDistance, float rolloff)
46495 {
46496     if (minDistance >= maxDistance) {
46497         return 1;   /* To avoid division by zero. Do not attenuate. */
46498     }
46499
46500     return 1 - rolloff * (ma_clamp(distance, minDistance, maxDistance) - minDistance) / (maxDistance - minDistance);
46501 }
46502
46503 static float ma_attenuation_exponential(float distance, float minDistance, float maxDistance, float rolloff)
46504 {
46505     if (minDistance >= maxDistance) {
46506         return 1;   /* To avoid division by zero. Do not attenuate. */
46507     }
46508
46509     return (float)ma_powd(ma_clamp(distance, minDistance, maxDistance) / minDistance, -rolloff);
46510 }
46511
46512
46513 /*
46514 Dopper Effect calculation taken from the OpenAL spec, with two main differences:
46515
46516   1) The source to listener vector will have already been calcualted at an earlier step so we can
46517      just use that directly. We need only the position of the source relative to the origin.
46518
46519   2) We don't scale by a frequency because we actually just want the ratio which we'll plug straight
46520      into the resampler directly.
46521 */
46522 static float ma_doppler_pitch(ma_vec3f relativePosition, ma_vec3f sourceVelocity, ma_vec3f listenVelocity, float speedOfSound, float dopplerFactor)
46523 {
46524     float len;
46525     float vls;
46526     float vss;
46527
46528     len = ma_vec3f_len(relativePosition);
46529
46530     /*
46531     There's a case where the position of the source will be right on top of the listener in which
46532     case the length will be 0 and we'll end up with a division by zero. We can just return a ratio
46533     of 1.0 in this case. This is not considered in the OpenAL spec, but is necessary.
46534     */
46535     if (len == 0) {
46536         return 1.0;
46537     }
46538
46539     vls = ma_vec3f_dot(relativePosition, listenVelocity) / len;
46540     vss = ma_vec3f_dot(relativePosition, sourceVelocity) / len;
46541
46542     vls = ma_min(vls, speedOfSound / dopplerFactor);
46543     vss = ma_min(vss, speedOfSound / dopplerFactor);
46544
46545     return (speedOfSound - dopplerFactor*vls) / (speedOfSound - dopplerFactor*vss);
46546 }
46547
46548
46549 static void ma_get_default_channel_map_for_spatializer(ma_channel* pChannelMap, size_t channelMapCap, ma_uint32 channelCount)
46550 {
46551     /*
46552     Special case for stereo. Want to default the left and right speakers to side left and side
46553     right so that they're facing directly down the X axis rather than slightly forward. Not
46554     doing this will result in sounds being quieter when behind the listener. This might
46555     actually be good for some scenerios, but I don't think it's an appropriate default because
46556     it can be a bit unexpected.
46557     */
46558     if (channelCount == 2) {
46559         pChannelMap[0] = MA_CHANNEL_SIDE_LEFT;
46560         pChannelMap[1] = MA_CHANNEL_SIDE_RIGHT;
46561     } else {
46562         ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channelCount);
46563     }
46564 }
46565
46566
46567 MA_API ma_spatializer_listener_config ma_spatializer_listener_config_init(ma_uint32 channelsOut)
46568 {
46569     ma_spatializer_listener_config config;
46570
46571     MA_ZERO_OBJECT(&config);
46572     config.channelsOut             = channelsOut;
46573     config.pChannelMapOut          = NULL;
46574     config.handedness              = ma_handedness_right;
46575     config.worldUp                 = ma_vec3f_init_3f(0, 1,  0);
46576     config.coneInnerAngleInRadians = 6.283185f; /* 360 degrees. */
46577     config.coneOuterAngleInRadians = 6.283185f; /* 360 degrees. */
46578     config.coneOuterGain           = 0;
46579     config.speedOfSound            = 343.3f;    /* Same as OpenAL. Used for doppler effect. */
46580
46581     return config;
46582 }
46583
46584
46585 typedef struct
46586 {
46587     size_t sizeInBytes;
46588     size_t channelMapOutOffset;
46589 } ma_spatializer_listener_heap_layout;
46590
46591 static ma_result ma_spatializer_listener_get_heap_layout(const ma_spatializer_listener_config* pConfig, ma_spatializer_listener_heap_layout* pHeapLayout)
46592 {
46593     MA_ASSERT(pHeapLayout != NULL);
46594
46595     MA_ZERO_OBJECT(pHeapLayout);
46596
46597     if (pConfig == NULL) {
46598         return MA_INVALID_ARGS;
46599     }
46600
46601     if (pConfig->channelsOut == 0) {
46602         return MA_INVALID_ARGS;
46603     }
46604
46605     pHeapLayout->sizeInBytes = 0;
46606
46607     /* Channel map. We always need this, even for passthroughs. */
46608     pHeapLayout->channelMapOutOffset = pHeapLayout->sizeInBytes;
46609     pHeapLayout->sizeInBytes += ma_align_64(sizeof(*pConfig->pChannelMapOut) * pConfig->channelsOut);
46610
46611     return MA_SUCCESS;
46612 }
46613
46614
46615 MA_API ma_result ma_spatializer_listener_get_heap_size(const ma_spatializer_listener_config* pConfig, size_t* pHeapSizeInBytes)
46616 {
46617     ma_result result;
46618     ma_spatializer_listener_heap_layout heapLayout;
46619
46620     if (pHeapSizeInBytes == NULL) {
46621         return MA_INVALID_ARGS;
46622     }
46623
46624     *pHeapSizeInBytes = 0;
46625
46626     result = ma_spatializer_listener_get_heap_layout(pConfig, &heapLayout);
46627     if (result != MA_SUCCESS) {
46628         return result;
46629     }
46630
46631     *pHeapSizeInBytes = heapLayout.sizeInBytes;
46632
46633     return MA_SUCCESS;
46634 }
46635
46636 MA_API ma_result ma_spatializer_listener_init_preallocated(const ma_spatializer_listener_config* pConfig, void* pHeap, ma_spatializer_listener* pListener)
46637 {
46638     ma_result result;
46639     ma_spatializer_listener_heap_layout heapLayout;
46640
46641     if (pListener == NULL) {
46642         return MA_INVALID_ARGS;
46643     }
46644
46645     MA_ZERO_OBJECT(pListener);
46646
46647     result = ma_spatializer_listener_get_heap_layout(pConfig, &heapLayout);
46648     if (result != MA_SUCCESS) {
46649         return result;
46650     }
46651
46652     pListener->_pHeap = pHeap;
46653     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
46654
46655     pListener->config    = *pConfig;
46656     pListener->position  = ma_vec3f_init_3f(0, 0,  0);
46657     pListener->direction = ma_vec3f_init_3f(0, 0, -1);
46658     pListener->velocity  = ma_vec3f_init_3f(0, 0,  0);
46659     pListener->isEnabled = MA_TRUE;
46660
46661     /* Swap the forward direction if we're left handed (it was initialized based on right handed). */
46662     if (pListener->config.handedness == ma_handedness_left) {
46663         pListener->direction = ma_vec3f_neg(pListener->direction);
46664     }
46665
46666
46667     /* We must always have a valid channel map. */
46668     pListener->config.pChannelMapOut = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapOutOffset);
46669
46670     /* Use a slightly different default channel map for stereo. */
46671     if (pConfig->pChannelMapOut == NULL) {
46672         ma_get_default_channel_map_for_spatializer(pListener->config.pChannelMapOut, pConfig->channelsOut, pConfig->channelsOut);
46673     } else {
46674         ma_channel_map_copy_or_default(pListener->config.pChannelMapOut, pConfig->channelsOut, pConfig->pChannelMapOut, pConfig->channelsOut);
46675     }
46676
46677     return MA_SUCCESS;
46678 }
46679
46680 MA_API ma_result ma_spatializer_listener_init(const ma_spatializer_listener_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer_listener* pListener)
46681 {
46682     ma_result result;
46683     size_t heapSizeInBytes;
46684     void* pHeap;
46685
46686     result = ma_spatializer_listener_get_heap_size(pConfig, &heapSizeInBytes);
46687     if (result != MA_SUCCESS) {
46688         return result;
46689     }
46690
46691     if (heapSizeInBytes > 0) {
46692         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
46693         if (pHeap == NULL) {
46694             return MA_OUT_OF_MEMORY;
46695         }
46696     } else {
46697         pHeap = NULL;
46698     }
46699
46700     result = ma_spatializer_listener_init_preallocated(pConfig, pHeap, pListener);
46701     if (result != MA_SUCCESS) {
46702         ma_free(pHeap, pAllocationCallbacks);
46703         return result;
46704     }
46705
46706     pListener->_ownsHeap = MA_TRUE;
46707     return MA_SUCCESS;
46708 }
46709
46710 MA_API void ma_spatializer_listener_uninit(ma_spatializer_listener* pListener, const ma_allocation_callbacks* pAllocationCallbacks)
46711 {
46712     if (pListener == NULL) {
46713         return;
46714     }
46715
46716     if (pListener->_ownsHeap) {
46717         ma_free(pListener->_pHeap, pAllocationCallbacks);
46718     }
46719 }
46720
46721 MA_API ma_channel* ma_spatializer_listener_get_channel_map(ma_spatializer_listener* pListener)
46722 {
46723     if (pListener == NULL) {
46724         return NULL;
46725     }
46726
46727     return pListener->config.pChannelMapOut;
46728 }
46729
46730 MA_API void ma_spatializer_listener_set_cone(ma_spatializer_listener* pListener, float innerAngleInRadians, float outerAngleInRadians, float outerGain)
46731 {
46732     if (pListener == NULL) {
46733         return;
46734     }
46735
46736     pListener->config.coneInnerAngleInRadians = innerAngleInRadians;
46737     pListener->config.coneOuterAngleInRadians = outerAngleInRadians;
46738     pListener->config.coneOuterGain           = outerGain;
46739 }
46740
46741 MA_API void ma_spatializer_listener_get_cone(const ma_spatializer_listener* pListener, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain)
46742 {
46743     if (pListener == NULL) {
46744         return;
46745     }
46746
46747     if (pInnerAngleInRadians != NULL) {
46748         *pInnerAngleInRadians = pListener->config.coneInnerAngleInRadians;
46749     }
46750
46751     if (pOuterAngleInRadians != NULL) {
46752         *pOuterAngleInRadians = pListener->config.coneOuterAngleInRadians;
46753     }
46754
46755     if (pOuterGain != NULL) {
46756         *pOuterGain = pListener->config.coneOuterGain;
46757     }
46758 }
46759
46760 MA_API void ma_spatializer_listener_set_position(ma_spatializer_listener* pListener, float x, float y, float z)
46761 {
46762     if (pListener == NULL) {
46763         return;
46764     }
46765
46766     pListener->position = ma_vec3f_init_3f(x, y, z);
46767 }
46768
46769 MA_API ma_vec3f ma_spatializer_listener_get_position(const ma_spatializer_listener* pListener)
46770 {
46771     if (pListener == NULL) {
46772         return ma_vec3f_init_3f(0, 0, 0);
46773     }
46774
46775     return pListener->position;
46776 }
46777
46778 MA_API void ma_spatializer_listener_set_direction(ma_spatializer_listener* pListener, float x, float y, float z)
46779 {
46780     if (pListener == NULL) {
46781         return;
46782     }
46783
46784     pListener->direction = ma_vec3f_init_3f(x, y, z);
46785 }
46786
46787 MA_API ma_vec3f ma_spatializer_listener_get_direction(const ma_spatializer_listener* pListener)
46788 {
46789     if (pListener == NULL) {
46790         return ma_vec3f_init_3f(0, 0, -1);
46791     }
46792
46793     return pListener->direction;
46794 }
46795
46796 MA_API void ma_spatializer_listener_set_velocity(ma_spatializer_listener* pListener, float x, float y, float z)
46797 {
46798     if (pListener == NULL) {
46799         return;
46800     }
46801
46802     pListener->velocity = ma_vec3f_init_3f(x, y, z);
46803 }
46804
46805 MA_API ma_vec3f ma_spatializer_listener_get_velocity(const ma_spatializer_listener* pListener)
46806 {
46807     if (pListener == NULL) {
46808         return ma_vec3f_init_3f(0, 0, 0);
46809     }
46810
46811     return pListener->velocity;
46812 }
46813
46814 MA_API void ma_spatializer_listener_set_speed_of_sound(ma_spatializer_listener* pListener, float speedOfSound)
46815 {
46816     if (pListener == NULL) {
46817         return;
46818     }
46819
46820     pListener->config.speedOfSound = speedOfSound;
46821 }
46822
46823 MA_API float ma_spatializer_listener_get_speed_of_sound(const ma_spatializer_listener* pListener)
46824 {
46825     if (pListener == NULL) {
46826         return 0;
46827     }
46828
46829     return pListener->config.speedOfSound;
46830 }
46831
46832 MA_API void ma_spatializer_listener_set_world_up(ma_spatializer_listener* pListener, float x, float y, float z)
46833 {
46834     if (pListener == NULL) {
46835         return;
46836     }
46837
46838     pListener->config.worldUp = ma_vec3f_init_3f(x, y, z);
46839 }
46840
46841 MA_API ma_vec3f ma_spatializer_listener_get_world_up(const ma_spatializer_listener* pListener)
46842 {
46843     if (pListener == NULL) {
46844         return ma_vec3f_init_3f(0, 1, 0);
46845     }
46846
46847     return pListener->config.worldUp;
46848 }
46849
46850 MA_API void ma_spatializer_listener_set_enabled(ma_spatializer_listener* pListener, ma_bool32 isEnabled)
46851 {
46852     if (pListener == NULL) {
46853         return;
46854     }
46855
46856     pListener->isEnabled = isEnabled;
46857 }
46858
46859 MA_API ma_bool32 ma_spatializer_listener_is_enabled(const ma_spatializer_listener* pListener)
46860 {
46861     if (pListener == NULL) {
46862         return MA_FALSE;
46863     }
46864
46865     return pListener->isEnabled;
46866 }
46867
46868
46869
46870
46871 MA_API ma_spatializer_config ma_spatializer_config_init(ma_uint32 channelsIn, ma_uint32 channelsOut)
46872 {
46873     ma_spatializer_config config;
46874
46875     MA_ZERO_OBJECT(&config);
46876     config.channelsIn                   = channelsIn;
46877     config.channelsOut                  = channelsOut;
46878     config.pChannelMapIn                = NULL;
46879     config.attenuationModel             = ma_attenuation_model_inverse;
46880     config.positioning                  = ma_positioning_absolute;
46881     config.handedness                   = ma_handedness_right;
46882     config.minGain                      = 0;
46883     config.maxGain                      = 1;
46884     config.minDistance                  = 1;
46885     config.maxDistance                  = MA_FLT_MAX;
46886     config.rolloff                      = 1;
46887     config.coneInnerAngleInRadians      = 6.283185f; /* 360 degrees. */
46888     config.coneOuterAngleInRadians      = 6.283185f; /* 360 degress. */
46889     config.coneOuterGain                = 0.0f;
46890     config.dopplerFactor                = 1;
46891     config.directionalAttenuationFactor = 1;
46892     config.gainSmoothTimeInFrames       = 360;       /* 7.5ms @ 48K. */
46893
46894     return config;
46895 }
46896
46897
46898 static ma_gainer_config ma_spatializer_gainer_config_init(const ma_spatializer_config* pConfig)
46899 {
46900     MA_ASSERT(pConfig != NULL);
46901     return ma_gainer_config_init(pConfig->channelsOut, pConfig->gainSmoothTimeInFrames);
46902 }
46903
46904 static ma_result ma_spatializer_validate_config(const ma_spatializer_config* pConfig)
46905 {
46906     MA_ASSERT(pConfig != NULL);
46907
46908     if (pConfig->channelsIn == 0 || pConfig->channelsOut == 0) {
46909         return MA_INVALID_ARGS;
46910     }
46911
46912     return MA_SUCCESS;
46913 }
46914
46915 typedef struct
46916 {
46917     size_t sizeInBytes;
46918     size_t channelMapInOffset;
46919     size_t newChannelGainsOffset;
46920     size_t gainerOffset;
46921 } ma_spatializer_heap_layout;
46922
46923 static ma_result ma_spatializer_get_heap_layout(const ma_spatializer_config* pConfig, ma_spatializer_heap_layout* pHeapLayout)
46924 {
46925     ma_result result;
46926
46927     MA_ASSERT(pHeapLayout != NULL);
46928
46929     MA_ZERO_OBJECT(pHeapLayout);
46930
46931     if (pConfig == NULL) {
46932         return MA_INVALID_ARGS;
46933     }
46934
46935     result = ma_spatializer_validate_config(pConfig);
46936     if (result != MA_SUCCESS) {
46937         return result;
46938     }
46939
46940     pHeapLayout->sizeInBytes = 0;
46941
46942     /* Channel map. */
46943     pHeapLayout->channelMapInOffset = MA_SIZE_MAX;  /* <-- MA_SIZE_MAX indicates no allocation necessary. */
46944     if (pConfig->pChannelMapIn != NULL) {
46945         pHeapLayout->channelMapInOffset = pHeapLayout->sizeInBytes;
46946         pHeapLayout->sizeInBytes += ma_align_64(sizeof(*pConfig->pChannelMapIn) * pConfig->channelsIn);
46947     }
46948
46949     /* New channel gains for output. */
46950     pHeapLayout->newChannelGainsOffset = pHeapLayout->sizeInBytes;
46951     pHeapLayout->sizeInBytes += ma_align_64(sizeof(float) * pConfig->channelsOut);
46952
46953     /* Gainer. */
46954     {
46955         size_t gainerHeapSizeInBytes;
46956         ma_gainer_config gainerConfig;
46957
46958         gainerConfig = ma_spatializer_gainer_config_init(pConfig);
46959
46960         result = ma_gainer_get_heap_size(&gainerConfig, &gainerHeapSizeInBytes);
46961         if (result != MA_SUCCESS) {
46962             return result;
46963         }
46964
46965         pHeapLayout->gainerOffset = pHeapLayout->sizeInBytes;
46966         pHeapLayout->sizeInBytes += ma_align_64(gainerHeapSizeInBytes);
46967     }
46968
46969     return MA_SUCCESS;
46970 }
46971
46972 MA_API ma_result ma_spatializer_get_heap_size(const ma_spatializer_config* pConfig, size_t* pHeapSizeInBytes)
46973 {
46974     ma_result result;
46975     ma_spatializer_heap_layout heapLayout;
46976
46977     if (pHeapSizeInBytes == NULL) {
46978         return MA_INVALID_ARGS;
46979     }
46980
46981     *pHeapSizeInBytes = 0;  /* Safety. */
46982
46983     result = ma_spatializer_get_heap_layout(pConfig, &heapLayout);
46984     if (result != MA_SUCCESS) {
46985         return result;
46986     }
46987
46988     *pHeapSizeInBytes = heapLayout.sizeInBytes;
46989
46990     return MA_SUCCESS;
46991 }
46992
46993
46994 MA_API ma_result ma_spatializer_init_preallocated(const ma_spatializer_config* pConfig, void* pHeap, ma_spatializer* pSpatializer)
46995 {
46996     ma_result result;
46997     ma_spatializer_heap_layout heapLayout;
46998     ma_gainer_config gainerConfig;
46999
47000     if (pSpatializer == NULL) {
47001         return MA_INVALID_ARGS;
47002     }
47003
47004     MA_ZERO_OBJECT(pSpatializer);
47005
47006     if (pConfig == NULL || pHeap == NULL) {
47007         return MA_INVALID_ARGS;
47008     }
47009
47010     result = ma_spatializer_get_heap_layout(pConfig, &heapLayout);
47011     if (result != MA_SUCCESS) {
47012         return result;
47013     }
47014
47015     pSpatializer->_pHeap = pHeap;
47016     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
47017
47018     pSpatializer->config       = *pConfig;
47019     pSpatializer->position     = ma_vec3f_init_3f(0, 0,  0);
47020     pSpatializer->direction    = ma_vec3f_init_3f(0, 0, -1);
47021     pSpatializer->velocity     = ma_vec3f_init_3f(0, 0,  0);
47022     pSpatializer->dopplerPitch = 1;
47023
47024     /* Swap the forward direction if we're left handed (it was initialized based on right handed). */
47025     if (pSpatializer->config.handedness == ma_handedness_left) {
47026         pSpatializer->direction = ma_vec3f_neg(pSpatializer->direction);
47027     }
47028
47029     /* Channel map. This will be on the heap. */
47030     if (pConfig->pChannelMapIn != NULL) {
47031         pSpatializer->config.pChannelMapIn = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapInOffset);
47032         ma_channel_map_copy_or_default(pSpatializer->config.pChannelMapIn, pSpatializer->config.channelsIn, pConfig->pChannelMapIn, pSpatializer->config.channelsIn);
47033     }
47034
47035     /* New channel gains for output channels. */
47036     pSpatializer->pNewChannelGainsOut = (float*)ma_offset_ptr(pHeap, heapLayout.newChannelGainsOffset);
47037
47038     /* Gainer. */
47039     gainerConfig = ma_spatializer_gainer_config_init(pConfig);
47040
47041     result = ma_gainer_init_preallocated(&gainerConfig, ma_offset_ptr(pHeap, heapLayout.gainerOffset), &pSpatializer->gainer);
47042     if (result != MA_SUCCESS) {
47043         return result;  /* Failed to initialize the gainer. */
47044     }
47045
47046     return MA_SUCCESS;
47047 }
47048
47049 MA_API ma_result ma_spatializer_init(const ma_spatializer_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_spatializer* pSpatializer)
47050 {
47051     ma_result result;
47052     size_t heapSizeInBytes;
47053     void* pHeap;
47054
47055     /* We'll need a heap allocation to retrieve the size. */
47056     result = ma_spatializer_get_heap_size(pConfig, &heapSizeInBytes);
47057     if (result != MA_SUCCESS) {
47058         return result;
47059     }
47060
47061     if (heapSizeInBytes > 0) {
47062         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
47063         if (pHeap == NULL) {
47064             return MA_OUT_OF_MEMORY;
47065         }
47066     } else {
47067         pHeap = NULL;
47068     }
47069
47070     result = ma_spatializer_init_preallocated(pConfig, pHeap, pSpatializer);
47071     if (result != MA_SUCCESS) {
47072         ma_free(pHeap, pAllocationCallbacks);
47073         return result;
47074     }
47075
47076     pSpatializer->_ownsHeap = MA_TRUE;
47077     return MA_SUCCESS;
47078 }
47079
47080 MA_API void ma_spatializer_uninit(ma_spatializer* pSpatializer, const ma_allocation_callbacks* pAllocationCallbacks)
47081 {
47082     if (pSpatializer == NULL) {
47083         return;
47084     }
47085
47086     ma_gainer_uninit(&pSpatializer->gainer, pAllocationCallbacks);
47087
47088     if (pSpatializer->_ownsHeap) {
47089         ma_free(pSpatializer->_pHeap, pAllocationCallbacks);
47090     }
47091 }
47092
47093 static float ma_calculate_angular_gain(ma_vec3f dirA, ma_vec3f dirB, float coneInnerAngleInRadians, float coneOuterAngleInRadians, float coneOuterGain)
47094 {
47095     /*
47096     Angular attenuation.
47097
47098     Unlike distance gain, the math for this is not specified by the OpenAL spec so we'll just go ahead and figure
47099     this out for ourselves at the expense of possibly being inconsistent with other implementations.
47100
47101     To do cone attenuation, I'm just using the same math that we'd use to implement a basic spotlight in OpenGL. We
47102     just need to get the direction from the source to the listener and then do a dot product against that and the
47103     direction of the spotlight. Then we just compare that dot product against the cosine of the inner and outer
47104     angles. If the dot product is greater than the the outer angle, we just use coneOuterGain. If it's less than
47105     the inner angle, we just use a gain of 1. Otherwise we linearly interpolate between 1 and coneOuterGain.
47106     */
47107     if (coneInnerAngleInRadians < 6.283185f) {
47108         float angularGain = 1;
47109         float cutoffInner = (float)ma_cosd(coneInnerAngleInRadians*0.5f);
47110         float cutoffOuter = (float)ma_cosd(coneOuterAngleInRadians*0.5f);
47111         float d;
47112
47113         d = ma_vec3f_dot(dirA, dirB);
47114
47115         if (d > cutoffInner) {
47116             /* It's inside the inner angle. */
47117             angularGain = 1;
47118         } else {
47119             /* It's outside the inner angle. */
47120             if (d > cutoffOuter) {
47121                 /* It's between the inner and outer angle. We need to linearly interpolate between 1 and coneOuterGain. */
47122                 angularGain = ma_mix_f32(coneOuterGain, 1, (d - cutoffOuter) / (cutoffInner - cutoffOuter));
47123             } else {
47124                 /* It's outside the outer angle. */
47125                 angularGain = coneOuterGain;
47126             }
47127         }
47128
47129         /*printf("d = %f; cutoffInner = %f; cutoffOuter = %f; angularGain = %f\n", d, cutoffInner, cutoffOuter, angularGain);*/
47130         return angularGain;
47131     } else {
47132         /* Inner angle is 360 degrees so no need to do any attenuation. */
47133         return 1;
47134     }
47135 }
47136
47137 MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ma_spatializer_listener* pListener, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
47138 {
47139     ma_channel* pChannelMapIn  = pSpatializer->config.pChannelMapIn;
47140     ma_channel* pChannelMapOut = pListener->config.pChannelMapOut;
47141
47142     if (pSpatializer == NULL) {
47143         return MA_INVALID_ARGS;
47144     }
47145
47146     /* If we're not spatializing we need to run an optimized path. */
47147     if (pSpatializer->config.attenuationModel == ma_attenuation_model_none) {
47148         if (ma_spatializer_listener_is_enabled(pListener)) {
47149             /* No attenuation is required, but we'll need to do some channel conversion. */
47150             if (pSpatializer->config.channelsIn == pSpatializer->config.channelsOut) {
47151                 ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, ma_format_f32, pSpatializer->config.channelsIn);
47152             } else {
47153                 ma_channel_map_apply_f32((float*)pFramesOut, pChannelMapOut, pSpatializer->config.channelsOut, (const float*)pFramesIn, pChannelMapIn, pSpatializer->config.channelsIn, frameCount, ma_channel_mix_mode_rectangular, ma_mono_expansion_mode_default);   /* Safe casts to float* because f32 is the only supported format. */
47154             }
47155         } else {
47156             /* The listener is disabled. Output silence. */
47157             ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, pSpatializer->config.channelsOut);
47158         }
47159
47160         /*
47161         We're not doing attenuation so don't bother with doppler for now. I'm not sure if this is
47162         the correct thinking so might need to review this later.
47163         */
47164         pSpatializer->dopplerPitch = 1;
47165     } else {
47166         /*
47167         Let's first determine which listener the sound is closest to. Need to keep in mind that we
47168         might not have a world or any listeners, in which case we just spatializer based on the
47169         listener being positioned at the origin (0, 0, 0).
47170         */
47171         ma_vec3f relativePosNormalized;
47172         ma_vec3f relativePos;   /* The position relative to the listener. */
47173         ma_vec3f relativeDir;   /* The direction of the sound, relative to the listener. */
47174         ma_vec3f listenerVel;   /* The volocity of the listener. For doppler pitch calculation. */
47175         float speedOfSound;
47176         float distance = 0;
47177         float gain = 1;
47178         ma_uint32 iChannel;
47179         const ma_uint32 channelsOut = pSpatializer->config.channelsOut;
47180         const ma_uint32 channelsIn  = pSpatializer->config.channelsIn;
47181
47182         /*
47183         We'll need the listener velocity for doppler pitch calculations. The speed of sound is
47184         defined by the listener, so we'll grab that here too.
47185         */
47186         if (pListener != NULL) {
47187             listenerVel  = pListener->velocity;
47188             speedOfSound = pListener->config.speedOfSound;
47189         } else {
47190             listenerVel  = ma_vec3f_init_3f(0, 0, 0);
47191             speedOfSound = MA_DEFAULT_SPEED_OF_SOUND;
47192         }
47193
47194         if (pListener == NULL || pSpatializer->config.positioning == ma_positioning_relative) {
47195             /* There's no listener or we're using relative positioning. */
47196             relativePos = pSpatializer->position;
47197             relativeDir = pSpatializer->direction;
47198         } else {
47199             /*
47200             We've found a listener and we're using absolute positioning. We need to transform the
47201             sound's position and direction so that it's relative to listener. Later on we'll use
47202             this for determining the factors to apply to each channel to apply the panning effect.
47203             */
47204             ma_spatializer_get_relative_position_and_direction(pSpatializer, pListener, &relativePos, &relativeDir);
47205         }
47206
47207         distance = ma_vec3f_len(relativePos);
47208
47209         /* We've gathered the data, so now we can apply some spatialization. */
47210         switch (pSpatializer->config.attenuationModel) {
47211             case ma_attenuation_model_inverse:
47212             {
47213                 gain = ma_attenuation_inverse(distance, pSpatializer->config.minDistance, pSpatializer->config.maxDistance, pSpatializer->config.rolloff);
47214             } break;
47215             case ma_attenuation_model_linear:
47216             {
47217                 gain = ma_attenuation_linear(distance, pSpatializer->config.minDistance, pSpatializer->config.maxDistance, pSpatializer->config.rolloff);
47218             } break;
47219             case ma_attenuation_model_exponential:
47220             {
47221                 gain = ma_attenuation_exponential(distance, pSpatializer->config.minDistance, pSpatializer->config.maxDistance, pSpatializer->config.rolloff);
47222             } break;
47223             case ma_attenuation_model_none:
47224             default:
47225             {
47226                 gain = 1;
47227             } break;
47228         }
47229
47230         /* Normalize the position. */
47231         if (distance > 0.001f) {
47232             float distanceInv = 1/distance;
47233             relativePosNormalized    = relativePos;
47234             relativePosNormalized.x *= distanceInv;
47235             relativePosNormalized.y *= distanceInv;
47236             relativePosNormalized.z *= distanceInv;
47237         } else {
47238             distance = 0;
47239             relativePosNormalized = ma_vec3f_init_3f(0, 0, 0);
47240         }
47241
47242         /*
47243         Angular attenuation.
47244
47245         Unlike distance gain, the math for this is not specified by the OpenAL spec so we'll just go ahead and figure
47246         this out for ourselves at the expense of possibly being inconsistent with other implementations.
47247
47248         To do cone attenuation, I'm just using the same math that we'd use to implement a basic spotlight in OpenGL. We
47249         just need to get the direction from the source to the listener and then do a dot product against that and the
47250         direction of the spotlight. Then we just compare that dot product against the cosine of the inner and outer
47251         angles. If the dot product is greater than the the outer angle, we just use coneOuterGain. If it's less than
47252         the inner angle, we just use a gain of 1. Otherwise we linearly interpolate between 1 and coneOuterGain.
47253         */
47254         if (distance > 0) {
47255             /* Source anglular gain. */
47256             gain *= ma_calculate_angular_gain(relativeDir, ma_vec3f_neg(relativePosNormalized), pSpatializer->config.coneInnerAngleInRadians, pSpatializer->config.coneOuterAngleInRadians, pSpatializer->config.coneOuterGain);
47257
47258             /*
47259             We're supporting angular gain on the listener as well for those who want to reduce the volume of sounds that
47260             are positioned behind the listener. On default settings, this will have no effect.
47261             */
47262             if (pListener != NULL && pListener->config.coneInnerAngleInRadians < 6.283185f) {
47263                 ma_vec3f listenerDirection;
47264                 float listenerInnerAngle;
47265                 float listenerOuterAngle;
47266                 float listenerOuterGain;
47267
47268                 if (pListener->config.handedness == ma_handedness_right) {
47269                     listenerDirection = ma_vec3f_init_3f(0, 0, -1);
47270                 } else {
47271                     listenerDirection = ma_vec3f_init_3f(0, 0, +1);
47272                 }
47273
47274                 listenerInnerAngle = pListener->config.coneInnerAngleInRadians;
47275                 listenerOuterAngle = pListener->config.coneOuterAngleInRadians;
47276                 listenerOuterGain  = pListener->config.coneOuterGain;
47277
47278                 gain *= ma_calculate_angular_gain(listenerDirection, relativePosNormalized, listenerInnerAngle, listenerOuterAngle, listenerOuterGain);
47279             }
47280         } else {
47281             /* The sound is right on top of the listener. Don't do any angular attenuation. */
47282         }
47283
47284
47285         /* Clamp the gain. */
47286         gain = ma_clamp(gain, pSpatializer->config.minGain, pSpatializer->config.maxGain);
47287
47288         /*
47289         Panning. This is where we'll apply the gain and convert to the output channel count. We have an optimized path for
47290         when we're converting to a mono stream. In that case we don't really need to do any panning - we just apply the
47291         gain to the final output.
47292         */
47293         /*printf("distance=%f; gain=%f\n", distance, gain);*/
47294
47295         /* We must have a valid channel map here to ensure we spatialize properly. */
47296         MA_ASSERT(pChannelMapOut != NULL);
47297
47298         /*
47299         We're not converting to mono so we'll want to apply some panning. This is where the feeling of something being
47300         to the left, right, infront or behind the listener is calculated. I'm just using a basic model here. Note that
47301         the code below is not based on any specific algorithm. I'm just implementing this off the top of my head and
47302         seeing how it goes. There might be better ways to do this.
47303
47304         To determine the direction of the sound relative to a speaker I'm using dot products. Each speaker is given a
47305         direction. For example, the left channel in a stereo system will be -1 on the X axis and the right channel will
47306         be +1 on the X axis. A dot product is performed against the direction vector of the channel and the normalized
47307         position of the sound.
47308         */
47309         for (iChannel = 0; iChannel < channelsOut; iChannel += 1) {
47310             pSpatializer->pNewChannelGainsOut[iChannel] = gain;
47311         }
47312
47313         /*
47314         Convert to our output channel count. If the listener is disabled we just output silence here. We cannot ignore
47315         the whole section of code here because we need to update some internal spatialization state.
47316         */
47317         if (ma_spatializer_listener_is_enabled(pListener)) {
47318             ma_channel_map_apply_f32((float*)pFramesOut, pChannelMapOut, channelsOut, (const float*)pFramesIn, pChannelMapIn, channelsIn, frameCount, ma_channel_mix_mode_rectangular, ma_mono_expansion_mode_default);
47319         } else {
47320             ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, pSpatializer->config.channelsOut);
47321         }
47322
47323         /*
47324         Calculate our per-channel gains. We do this based on the normalized relative position of the sound and it's
47325         relation to the direction of the channel.
47326         */
47327         if (distance > 0) {
47328             ma_vec3f unitPos = relativePos;
47329             float distanceInv = 1/distance;
47330             unitPos.x *= distanceInv;
47331             unitPos.y *= distanceInv;
47332             unitPos.z *= distanceInv;
47333
47334             for (iChannel = 0; iChannel < channelsOut; iChannel += 1) {
47335                 ma_channel channelOut;
47336                 float d;
47337                 float dMin;
47338
47339                 channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannel);
47340                 if (ma_is_spatial_channel_position(channelOut)) {
47341                     d = ma_mix_f32_fast(1, ma_vec3f_dot(unitPos, ma_get_channel_direction(channelOut)), pSpatializer->config.directionalAttenuationFactor);
47342                 } else {
47343                     d = 1;  /* It's not a spatial channel so there's no real notion of direction. */
47344                 }
47345
47346                 /*
47347                 In my testing, if the panning effect is too aggressive it makes spatialization feel uncomfortable.
47348                 The "dMin" variable below is used to control the aggressiveness of the panning effect. When set to
47349                 0, panning will be most extreme and any sounds that are positioned on the opposite side of the
47350                 speaker will be completely silent from that speaker. Not only does this feel uncomfortable, it
47351                 doesn't even remotely represent the real world at all because sounds that come from your right side
47352                 are still clearly audible from your left side. Setting "dMin" to 1 will  result in no panning at
47353                 all, which is also not ideal. By setting it to something greater than 0, the spatialization effect
47354                 becomes much less dramatic and a lot more bearable.
47355
47356                 Summary: 0 = more extreme panning; 1 = no panning.
47357                 */
47358                 dMin = 0.2f;  /* TODO: Consider making this configurable. */
47359
47360                 /*
47361                 At this point, "d" will be positive if the sound is on the same side as the channel and negative if
47362                 it's on the opposite side. It will be in the range of -1..1. There's two ways I can think of to
47363                 calculate a panning value. The first is to simply convert it to 0..1, however this has a problem
47364                 which I'm not entirely happy with. Considering a stereo system, when a sound is positioned right
47365                 in front of the listener it'll result in each speaker getting a gain of 0.5. I don't know if I like
47366                 the idea of having a scaling factor of 0.5 being applied to a sound when it's sitting right in front
47367                 of the listener. I would intuitively expect that to be played at full volume, or close to it.
47368
47369                 The second idea I think of is to only apply a reduction in gain when the sound is on the opposite
47370                 side of the speaker. That is, reduce the gain only when the dot product is negative. The problem
47371                 with this is that there will not be any attenuation as the sound sweeps around the 180 degrees
47372                 where the dot product is positive. The idea with this option is that you leave the gain at 1 when
47373                 the sound is being played on the same side as the speaker and then you just reduce the volume when
47374                 the sound is on the other side.
47375
47376                 The summarize, I think the first option should give a better sense of spatialization, but the second
47377                 option is better for preserving the sound's power.
47378
47379                 UPDATE: In my testing, I find the first option to sound better. You can feel the sense of space a
47380                 bit better, but you can also hear the reduction in volume when it's right in front.
47381                 */
47382                 #if 1
47383                 {
47384                     /*
47385                     Scale the dot product from -1..1 to 0..1. Will result in a sound directly in front losing power
47386                     by being played at 0.5 gain.
47387                     */
47388                     d = (d + 1) * 0.5f;  /* -1..1 to 0..1 */
47389                     d = ma_max(d, dMin);
47390                     pSpatializer->pNewChannelGainsOut[iChannel] *= d;
47391                 }
47392                 #else
47393                 {
47394                     /*
47395                     Only reduce the volume of the sound if it's on the opposite side. This path keeps the volume more
47396                     consistent, but comes at the expense of a worse sense of space and positioning.
47397                     */
47398                     if (d < 0) {
47399                         d += 1; /* Move into the positive range. */
47400                         d = ma_max(d, dMin);
47401                         channelGainsOut[iChannel] *= d;
47402                     }
47403                 }
47404                 #endif
47405             }
47406         } else {
47407             /* Assume the sound is right on top of us. Don't do any panning. */
47408         }
47409
47410         /* Now we need to apply the volume to each channel. This needs to run through the gainer to ensure we get a smooth volume transition. */
47411         ma_gainer_set_gains(&pSpatializer->gainer, pSpatializer->pNewChannelGainsOut);
47412         ma_gainer_process_pcm_frames(&pSpatializer->gainer, pFramesOut, pFramesOut, frameCount);
47413
47414         /*
47415         Before leaving we'll want to update our doppler pitch so that the caller can apply some
47416         pitch shifting if they desire. Note that we need to negate the relative position here
47417         because the doppler calculation needs to be source-to-listener, but ours is listener-to-
47418         source.
47419         */
47420         if (pSpatializer->config.dopplerFactor > 0) {
47421             pSpatializer->dopplerPitch = ma_doppler_pitch(ma_vec3f_sub(pListener->position, pSpatializer->position), pSpatializer->velocity, listenerVel, speedOfSound, pSpatializer->config.dopplerFactor);
47422         } else {
47423             pSpatializer->dopplerPitch = 1;
47424         }
47425     }
47426
47427     return MA_SUCCESS;
47428 }
47429
47430 MA_API ma_uint32 ma_spatializer_get_input_channels(const ma_spatializer* pSpatializer)
47431 {
47432     if (pSpatializer == NULL) {
47433         return 0;
47434     }
47435
47436     return pSpatializer->config.channelsIn;
47437 }
47438
47439 MA_API ma_uint32 ma_spatializer_get_output_channels(const ma_spatializer* pSpatializer)
47440 {
47441     if (pSpatializer == NULL) {
47442         return 0;
47443     }
47444
47445     return pSpatializer->config.channelsOut;
47446 }
47447
47448 MA_API void ma_spatializer_set_attenuation_model(ma_spatializer* pSpatializer, ma_attenuation_model attenuationModel)
47449 {
47450     if (pSpatializer == NULL) {
47451         return;
47452     }
47453
47454     pSpatializer->config.attenuationModel = attenuationModel;
47455 }
47456
47457 MA_API ma_attenuation_model ma_spatializer_get_attenuation_model(const ma_spatializer* pSpatializer)
47458 {
47459     if (pSpatializer == NULL) {
47460         return ma_attenuation_model_none;
47461     }
47462
47463     return pSpatializer->config.attenuationModel;
47464 }
47465
47466 MA_API void ma_spatializer_set_positioning(ma_spatializer* pSpatializer, ma_positioning positioning)
47467 {
47468     if (pSpatializer == NULL) {
47469         return;
47470     }
47471
47472     pSpatializer->config.positioning = positioning;
47473 }
47474
47475 MA_API ma_positioning ma_spatializer_get_positioning(const ma_spatializer* pSpatializer)
47476 {
47477     if (pSpatializer == NULL) {
47478         return ma_positioning_absolute;
47479     }
47480
47481     return pSpatializer->config.positioning;
47482 }
47483
47484 MA_API void ma_spatializer_set_rolloff(ma_spatializer* pSpatializer, float rolloff)
47485 {
47486     if (pSpatializer == NULL) {
47487         return;
47488     }
47489
47490     pSpatializer->config.rolloff = rolloff;
47491 }
47492
47493 MA_API float ma_spatializer_get_rolloff(const ma_spatializer* pSpatializer)
47494 {
47495     if (pSpatializer == NULL) {
47496         return 0;
47497     }
47498
47499     return pSpatializer->config.rolloff;
47500 }
47501
47502 MA_API void ma_spatializer_set_min_gain(ma_spatializer* pSpatializer, float minGain)
47503 {
47504     if (pSpatializer == NULL) {
47505         return;
47506     }
47507
47508     pSpatializer->config.minGain = minGain;
47509 }
47510
47511 MA_API float ma_spatializer_get_min_gain(const ma_spatializer* pSpatializer)
47512 {
47513     if (pSpatializer == NULL) {
47514         return 0;
47515     }
47516
47517     return pSpatializer->config.minGain;
47518 }
47519
47520 MA_API void ma_spatializer_set_max_gain(ma_spatializer* pSpatializer, float maxGain)
47521 {
47522     if (pSpatializer == NULL) {
47523         return;
47524     }
47525
47526     pSpatializer->config.maxGain = maxGain;
47527 }
47528
47529 MA_API float ma_spatializer_get_max_gain(const ma_spatializer* pSpatializer)
47530 {
47531     if (pSpatializer == NULL) {
47532         return 0;
47533     }
47534
47535     return pSpatializer->config.maxGain;
47536 }
47537
47538 MA_API void ma_spatializer_set_min_distance(ma_spatializer* pSpatializer, float minDistance)
47539 {
47540     if (pSpatializer == NULL) {
47541         return;
47542     }
47543
47544     pSpatializer->config.minDistance = minDistance;
47545 }
47546
47547 MA_API float ma_spatializer_get_min_distance(const ma_spatializer* pSpatializer)
47548 {
47549     if (pSpatializer == NULL) {
47550         return 0;
47551     }
47552
47553     return pSpatializer->config.minDistance;
47554 }
47555
47556 MA_API void ma_spatializer_set_max_distance(ma_spatializer* pSpatializer, float maxDistance)
47557 {
47558     if (pSpatializer == NULL) {
47559         return;
47560     }
47561
47562     pSpatializer->config.maxDistance = maxDistance;
47563 }
47564
47565 MA_API float ma_spatializer_get_max_distance(const ma_spatializer* pSpatializer)
47566 {
47567     if (pSpatializer == NULL) {
47568         return 0;
47569     }
47570
47571     return pSpatializer->config.maxDistance;
47572 }
47573
47574 MA_API void ma_spatializer_set_cone(ma_spatializer* pSpatializer, float innerAngleInRadians, float outerAngleInRadians, float outerGain)
47575 {
47576     if (pSpatializer == NULL) {
47577         return;
47578     }
47579
47580     pSpatializer->config.coneInnerAngleInRadians = innerAngleInRadians;
47581     pSpatializer->config.coneOuterAngleInRadians = outerAngleInRadians;
47582     pSpatializer->config.coneOuterGain           = outerGain;
47583 }
47584
47585 MA_API void ma_spatializer_get_cone(const ma_spatializer* pSpatializer, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain)
47586 {
47587     if (pSpatializer == NULL) {
47588         return;
47589     }
47590
47591     if (pInnerAngleInRadians != NULL) {
47592         *pInnerAngleInRadians = pSpatializer->config.coneInnerAngleInRadians;
47593     }
47594
47595     if (pOuterAngleInRadians != NULL) {
47596         *pOuterAngleInRadians = pSpatializer->config.coneOuterAngleInRadians;
47597     }
47598
47599     if (pOuterGain != NULL) {
47600         *pOuterGain = pSpatializer->config.coneOuterGain;
47601     }
47602 }
47603
47604 MA_API void ma_spatializer_set_doppler_factor(ma_spatializer* pSpatializer, float dopplerFactor)
47605 {
47606     if (pSpatializer == NULL) {
47607         return;
47608     }
47609
47610     pSpatializer->config.dopplerFactor = dopplerFactor;
47611 }
47612
47613 MA_API float ma_spatializer_get_doppler_factor(const ma_spatializer* pSpatializer)
47614 {
47615     if (pSpatializer == NULL) {
47616         return 1;
47617     }
47618
47619     return pSpatializer->config.dopplerFactor;
47620 }
47621
47622 MA_API void ma_spatializer_set_directional_attenuation_factor(ma_spatializer* pSpatializer, float directionalAttenuationFactor)
47623 {
47624     if (pSpatializer == NULL) {
47625         return;
47626     }
47627
47628     pSpatializer->config.directionalAttenuationFactor = directionalAttenuationFactor;
47629 }
47630
47631 MA_API float ma_spatializer_get_directional_attenuation_factor(const ma_spatializer* pSpatializer)
47632 {
47633     if (pSpatializer == NULL) {
47634         return 1;
47635     }
47636
47637     return pSpatializer->config.directionalAttenuationFactor;
47638 }
47639
47640 MA_API void ma_spatializer_set_position(ma_spatializer* pSpatializer, float x, float y, float z)
47641 {
47642     if (pSpatializer == NULL) {
47643         return;
47644     }
47645
47646     pSpatializer->position = ma_vec3f_init_3f(x, y, z);
47647 }
47648
47649 MA_API ma_vec3f ma_spatializer_get_position(const ma_spatializer* pSpatializer)
47650 {
47651     if (pSpatializer == NULL) {
47652         return ma_vec3f_init_3f(0, 0, 0);
47653     }
47654
47655     return pSpatializer->position;
47656 }
47657
47658 MA_API void ma_spatializer_set_direction(ma_spatializer* pSpatializer, float x, float y, float z)
47659 {
47660     if (pSpatializer == NULL) {
47661         return;
47662     }
47663
47664     pSpatializer->direction = ma_vec3f_init_3f(x, y, z);
47665 }
47666
47667 MA_API ma_vec3f ma_spatializer_get_direction(const ma_spatializer* pSpatializer)
47668 {
47669     if (pSpatializer == NULL) {
47670         return ma_vec3f_init_3f(0, 0, -1);
47671     }
47672
47673     return pSpatializer->direction;
47674 }
47675
47676 MA_API void ma_spatializer_set_velocity(ma_spatializer* pSpatializer, float x, float y, float z)
47677 {
47678     if (pSpatializer == NULL) {
47679         return;
47680     }
47681
47682     pSpatializer->velocity = ma_vec3f_init_3f(x, y, z);
47683 }
47684
47685 MA_API ma_vec3f ma_spatializer_get_velocity(const ma_spatializer* pSpatializer)
47686 {
47687     if (pSpatializer == NULL) {
47688         return ma_vec3f_init_3f(0, 0, 0);
47689     }
47690
47691     return pSpatializer->velocity;
47692 }
47693
47694 MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatializer* pSpatializer, const ma_spatializer_listener* pListener, ma_vec3f* pRelativePos, ma_vec3f* pRelativeDir)
47695 {
47696     if (pRelativePos != NULL) {
47697         pRelativePos->x = 0;
47698         pRelativePos->y = 0;
47699         pRelativePos->z = 0;
47700     }
47701
47702     if (pRelativeDir != NULL) {
47703         pRelativeDir->x = 0;
47704         pRelativeDir->y = 0;
47705         pRelativeDir->z = -1;
47706     }
47707
47708     if (pSpatializer == NULL) {
47709         return;
47710     }
47711
47712     if (pListener == NULL || pSpatializer->config.positioning == ma_positioning_relative) {
47713         /* There's no listener or we're using relative positioning. */
47714         if (pRelativePos != NULL) {
47715             *pRelativePos = pSpatializer->position;
47716         }
47717         if (pRelativeDir != NULL) {
47718             *pRelativeDir = pSpatializer->direction;
47719         }
47720     } else {
47721         ma_vec3f v;
47722         ma_vec3f axisX;
47723         ma_vec3f axisY;
47724         ma_vec3f axisZ;
47725         float m[4][4];
47726
47727         /*
47728         We need to calcualte the right vector from our forward and up vectors. This is done with
47729         a cross product.
47730         */
47731         axisZ = ma_vec3f_normalize(pListener->direction);                               /* Normalization required here because we can't trust the caller. */
47732         axisX = ma_vec3f_normalize(ma_vec3f_cross(axisZ, pListener->config.worldUp));   /* Normalization required here because the world up vector may not be perpendicular with the forward vector. */
47733
47734         /*
47735         The calculation of axisX above can result in a zero-length vector if the listener is
47736         looking straight up on the Y axis. We'll need to fall back to a +X in this case so that
47737         the calculations below don't fall apart. This is where a quaternion based listener and
47738         sound orientation would come in handy.
47739         */
47740         if (ma_vec3f_len2(axisX) == 0) {
47741             axisX = ma_vec3f_init_3f(1, 0, 0);
47742         }
47743
47744         axisY = ma_vec3f_cross(axisX, axisZ);                                           /* No normalization is required here because axisX and axisZ are unit length and perpendicular. */
47745
47746         /*
47747         We need to swap the X axis if we're left handed because otherwise the cross product above
47748         will have resulted in it pointing in the wrong direction (right handed was assumed in the
47749         cross products above).
47750         */
47751         if (pListener->config.handedness == ma_handedness_left) {
47752             axisX = ma_vec3f_neg(axisX);
47753         }
47754
47755         /* Lookat. */
47756         m[0][0] =  axisX.x; m[1][0] =  axisX.y; m[2][0] =  axisX.z; m[3][0] = -ma_vec3f_dot(axisX,               pListener->position);
47757         m[0][1] =  axisY.x; m[1][1] =  axisY.y; m[2][1] =  axisY.z; m[3][1] = -ma_vec3f_dot(axisY,               pListener->position);
47758         m[0][2] = -axisZ.x; m[1][2] = -axisZ.y; m[2][2] = -axisZ.z; m[3][2] = -ma_vec3f_dot(ma_vec3f_neg(axisZ), pListener->position);
47759         m[0][3] = 0;        m[1][3] = 0;        m[2][3] = 0;        m[3][3] = 1;
47760
47761         /*
47762         Multiply the lookat matrix by the spatializer position to transform it to listener
47763         space. This allows calculations to work based on the sound being relative to the
47764         origin which makes things simpler.
47765         */
47766         if (pRelativePos != NULL) {
47767             v = pSpatializer->position;
47768             pRelativePos->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * 1;
47769             pRelativePos->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * 1;
47770             pRelativePos->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * 1;
47771         }
47772
47773         /*
47774         The direction of the sound needs to also be transformed so that it's relative to the
47775         rotation of the listener.
47776         */
47777         if (pRelativeDir != NULL) {
47778             v = pSpatializer->direction;
47779             pRelativeDir->x = m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z;
47780             pRelativeDir->y = m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z;
47781             pRelativeDir->z = m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z;
47782         }
47783     }
47784 }
47785
47786
47787
47788
47789 /**************************************************************************************************************************************************************
47790
47791 Resampling
47792
47793 **************************************************************************************************************************************************************/
47794 MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
47795 {
47796     ma_linear_resampler_config config;
47797     MA_ZERO_OBJECT(&config);
47798     config.format           = format;
47799     config.channels         = channels;
47800     config.sampleRateIn     = sampleRateIn;
47801     config.sampleRateOut    = sampleRateOut;
47802     config.lpfOrder         = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
47803     config.lpfNyquistFactor = 1;
47804
47805     return config;
47806 }
47807
47808
47809 typedef struct
47810 {
47811     size_t sizeInBytes;
47812     size_t x0Offset;
47813     size_t x1Offset;
47814     size_t lpfOffset;
47815 } ma_linear_resampler_heap_layout;
47816
47817
47818 static void ma_linear_resampler_adjust_timer_for_new_rate(ma_linear_resampler* pResampler, ma_uint32 oldSampleRateOut, ma_uint32 newSampleRateOut)
47819 {
47820     /*
47821     So what's happening here? Basically we need to adjust the fractional component of the time advance based on the new rate. The old time advance will
47822     be based on the old sample rate, but we are needing to adjust it to that it's based on the new sample rate.
47823     */
47824     ma_uint32 oldRateTimeWhole = pResampler->inTimeFrac / oldSampleRateOut;  /* <-- This should almost never be anything other than 0, but leaving it here to make this more general and robust just in case. */
47825     ma_uint32 oldRateTimeFract = pResampler->inTimeFrac % oldSampleRateOut;
47826
47827     pResampler->inTimeFrac =
47828          (oldRateTimeWhole * newSampleRateOut) +
47829         ((oldRateTimeFract * newSampleRateOut) / oldSampleRateOut);
47830
47831     /* Make sure the fractional part is less than the output sample rate. */
47832     pResampler->inTimeInt += pResampler->inTimeFrac / pResampler->config.sampleRateOut;
47833     pResampler->inTimeFrac = pResampler->inTimeFrac % pResampler->config.sampleRateOut;
47834 }
47835
47836 static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pResampler, void* pHeap, ma_linear_resampler_heap_layout* pHeapLayout, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_bool32 isResamplerAlreadyInitialized)
47837 {
47838     ma_result result;
47839     ma_uint32 gcf;
47840     ma_uint32 lpfSampleRate;
47841     double lpfCutoffFrequency;
47842     ma_lpf_config lpfConfig;
47843     ma_uint32 oldSampleRateOut; /* Required for adjusting time advance down the bottom. */
47844
47845     if (pResampler == NULL) {
47846         return MA_INVALID_ARGS;
47847     }
47848
47849     if (sampleRateIn == 0 || sampleRateOut == 0) {
47850         return MA_INVALID_ARGS;
47851     }
47852
47853     oldSampleRateOut = pResampler->config.sampleRateOut;
47854
47855     pResampler->config.sampleRateIn  = sampleRateIn;
47856     pResampler->config.sampleRateOut = sampleRateOut;
47857
47858     /* Simplify the sample rate. */
47859     gcf = ma_gcf_u32(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut);
47860     pResampler->config.sampleRateIn  /= gcf;
47861     pResampler->config.sampleRateOut /= gcf;
47862
47863     /* Always initialize the low-pass filter, even when the order is 0. */
47864     if (pResampler->config.lpfOrder > MA_MAX_FILTER_ORDER) {
47865         return MA_INVALID_ARGS;
47866     }
47867
47868     lpfSampleRate      = (ma_uint32)(ma_max(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut));
47869     lpfCutoffFrequency = (   double)(ma_min(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut) * 0.5 * pResampler->config.lpfNyquistFactor);
47870
47871     lpfConfig = ma_lpf_config_init(pResampler->config.format, pResampler->config.channels, lpfSampleRate, lpfCutoffFrequency, pResampler->config.lpfOrder);
47872
47873     /*
47874     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
47875     getting cleared. Instead we re-initialize the filter which will maintain any cached frames.
47876     */
47877     if (isResamplerAlreadyInitialized) {
47878         result = ma_lpf_reinit(&lpfConfig, &pResampler->lpf);
47879     } else {
47880         result = ma_lpf_init_preallocated(&lpfConfig, ma_offset_ptr(pHeap, pHeapLayout->lpfOffset), &pResampler->lpf);
47881     }
47882
47883     if (result != MA_SUCCESS) {
47884         return result;
47885     }
47886
47887
47888     pResampler->inAdvanceInt  = pResampler->config.sampleRateIn / pResampler->config.sampleRateOut;
47889     pResampler->inAdvanceFrac = pResampler->config.sampleRateIn % pResampler->config.sampleRateOut;
47890
47891     /* Our timer was based on the old rate. We need to adjust it so that it's based on the new rate. */
47892     ma_linear_resampler_adjust_timer_for_new_rate(pResampler, oldSampleRateOut, pResampler->config.sampleRateOut);
47893
47894     return MA_SUCCESS;
47895 }
47896
47897 static ma_result ma_linear_resampler_get_heap_layout(const ma_linear_resampler_config* pConfig, ma_linear_resampler_heap_layout* pHeapLayout)
47898 {
47899     MA_ASSERT(pHeapLayout != NULL);
47900
47901     MA_ZERO_OBJECT(pHeapLayout);
47902
47903     if (pConfig == NULL) {
47904         return MA_INVALID_ARGS;
47905     }
47906
47907     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
47908         return MA_INVALID_ARGS;
47909     }
47910
47911     if (pConfig->channels == 0) {
47912         return MA_INVALID_ARGS;
47913     }
47914
47915     pHeapLayout->sizeInBytes = 0;
47916
47917     /* x0 */
47918     pHeapLayout->x0Offset = pHeapLayout->sizeInBytes;
47919     if (pConfig->format == ma_format_f32) {
47920         pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels;
47921     } else {
47922         pHeapLayout->sizeInBytes += sizeof(ma_int16) * pConfig->channels;
47923     }
47924
47925     /* x1 */
47926     pHeapLayout->x1Offset = pHeapLayout->sizeInBytes;
47927     if (pConfig->format == ma_format_f32) {
47928         pHeapLayout->sizeInBytes += sizeof(float) * pConfig->channels;
47929     } else {
47930         pHeapLayout->sizeInBytes += sizeof(ma_int16) * pConfig->channels;
47931     }
47932
47933     /* LPF */
47934     pHeapLayout->lpfOffset = pHeapLayout->sizeInBytes;
47935     {
47936         ma_result result;
47937         size_t lpfHeapSizeInBytes;
47938         ma_lpf_config lpfConfig = ma_lpf_config_init(pConfig->format, pConfig->channels, 1, 1, pConfig->lpfOrder);  /* Sample rate and cutoff frequency do not matter. */
47939
47940         result = ma_lpf_get_heap_size(&lpfConfig, &lpfHeapSizeInBytes);
47941         if (result != MA_SUCCESS) {
47942             return result;
47943         }
47944
47945         pHeapLayout->sizeInBytes += lpfHeapSizeInBytes;
47946     }
47947
47948     /* Make sure allocation size is aligned. */
47949     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
47950
47951     return MA_SUCCESS;
47952 }
47953
47954 MA_API ma_result ma_linear_resampler_get_heap_size(const ma_linear_resampler_config* pConfig, size_t* pHeapSizeInBytes)
47955 {
47956     ma_result result;
47957     ma_linear_resampler_heap_layout heapLayout;
47958
47959     if (pHeapSizeInBytes == NULL) {
47960         return MA_INVALID_ARGS;
47961     }
47962
47963     *pHeapSizeInBytes = 0;
47964
47965     result = ma_linear_resampler_get_heap_layout(pConfig, &heapLayout);
47966     if (result != MA_SUCCESS) {
47967         return result;
47968     }
47969
47970     *pHeapSizeInBytes = heapLayout.sizeInBytes;
47971
47972     return MA_SUCCESS;
47973 }
47974
47975 MA_API ma_result ma_linear_resampler_init_preallocated(const ma_linear_resampler_config* pConfig, void* pHeap, ma_linear_resampler* pResampler)
47976 {
47977     ma_result result;
47978     ma_linear_resampler_heap_layout heapLayout;
47979
47980     if (pResampler == NULL) {
47981         return MA_INVALID_ARGS;
47982     }
47983
47984     MA_ZERO_OBJECT(pResampler);
47985
47986     result = ma_linear_resampler_get_heap_layout(pConfig, &heapLayout);
47987     if (result != MA_SUCCESS) {
47988         return result;
47989     }
47990
47991     pResampler->config = *pConfig;
47992
47993     pResampler->_pHeap = pHeap;
47994     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
47995
47996     if (pConfig->format == ma_format_f32) {
47997         pResampler->x0.f32 = (float*)ma_offset_ptr(pHeap, heapLayout.x0Offset);
47998         pResampler->x1.f32 = (float*)ma_offset_ptr(pHeap, heapLayout.x1Offset);
47999     } else {
48000         pResampler->x0.s16 = (ma_int16*)ma_offset_ptr(pHeap, heapLayout.x0Offset);
48001         pResampler->x1.s16 = (ma_int16*)ma_offset_ptr(pHeap, heapLayout.x1Offset);
48002     }
48003
48004     /* Setting the rate will set up the filter and time advances for us. */
48005     result = ma_linear_resampler_set_rate_internal(pResampler, pHeap, &heapLayout, pConfig->sampleRateIn, pConfig->sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_FALSE);
48006     if (result != MA_SUCCESS) {
48007         return result;
48008     }
48009
48010     pResampler->inTimeInt  = 1;  /* Set this to one to force an input sample to always be loaded for the first output frame. */
48011     pResampler->inTimeFrac = 0;
48012
48013     return MA_SUCCESS;
48014 }
48015
48016 MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_linear_resampler* pResampler)
48017 {
48018     ma_result result;
48019     size_t heapSizeInBytes;
48020     void* pHeap;
48021
48022     result = ma_linear_resampler_get_heap_size(pConfig, &heapSizeInBytes);
48023     if (result != MA_SUCCESS) {
48024         return result;
48025     }
48026
48027     if (heapSizeInBytes > 0) {
48028         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
48029         if (pHeap == NULL) {
48030             return MA_OUT_OF_MEMORY;
48031         }
48032     } else {
48033         pHeap = NULL;
48034     }
48035
48036     result = ma_linear_resampler_init_preallocated(pConfig, pHeap, pResampler);
48037     if (result != MA_SUCCESS) {
48038         ma_free(pHeap, pAllocationCallbacks);
48039         return result;
48040     }
48041
48042     pResampler->_ownsHeap = MA_TRUE;
48043     return MA_SUCCESS;
48044 }
48045
48046 MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks)
48047 {
48048     if (pResampler == NULL) {
48049         return;
48050     }
48051
48052     ma_lpf_uninit(&pResampler->lpf, pAllocationCallbacks);
48053
48054     if (pResampler->_ownsHeap) {
48055         ma_free(pResampler->_pHeap, pAllocationCallbacks);
48056     }
48057 }
48058
48059 static MA_INLINE ma_int16 ma_linear_resampler_mix_s16(ma_int16 x, ma_int16 y, ma_int32 a, const ma_int32 shift)
48060 {
48061     ma_int32 b;
48062     ma_int32 c;
48063     ma_int32 r;
48064
48065     MA_ASSERT(a <= (1<<shift));
48066
48067     b = x * ((1<<shift) - a);
48068     c = y * a;
48069     r = b + c;
48070
48071     return (ma_int16)(r >> shift);
48072 }
48073
48074 static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResampler, ma_int16* MA_RESTRICT pFrameOut)
48075 {
48076     ma_uint32 c;
48077     ma_uint32 a;
48078     const ma_uint32 channels = pResampler->config.channels;
48079     const ma_uint32 shift = 12;
48080
48081     MA_ASSERT(pResampler != NULL);
48082     MA_ASSERT(pFrameOut  != NULL);
48083
48084     a = (pResampler->inTimeFrac << shift) / pResampler->config.sampleRateOut;
48085
48086     MA_ASSUME(channels > 0);
48087     for (c = 0; c < channels; c += 1) {
48088         ma_int16 s = ma_linear_resampler_mix_s16(pResampler->x0.s16[c], pResampler->x1.s16[c], a, shift);
48089         pFrameOut[c] = s;
48090     }
48091 }
48092
48093
48094 static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResampler, float* MA_RESTRICT pFrameOut)
48095 {
48096     ma_uint32 c;
48097     float a;
48098     const ma_uint32 channels = pResampler->config.channels;
48099
48100     MA_ASSERT(pResampler != NULL);
48101     MA_ASSERT(pFrameOut  != NULL);
48102
48103     a = (float)pResampler->inTimeFrac / pResampler->config.sampleRateOut;
48104
48105     MA_ASSUME(channels > 0);
48106     for (c = 0; c < channels; c += 1) {
48107         float s = ma_mix_f32_fast(pResampler->x0.f32[c], pResampler->x1.f32[c], a);
48108         pFrameOut[c] = s;
48109     }
48110 }
48111
48112 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)
48113 {
48114     const ma_int16* pFramesInS16;
48115     /* */ ma_int16* pFramesOutS16;
48116     ma_uint64 frameCountIn;
48117     ma_uint64 frameCountOut;
48118     ma_uint64 framesProcessedIn;
48119     ma_uint64 framesProcessedOut;
48120
48121     MA_ASSERT(pResampler     != NULL);
48122     MA_ASSERT(pFrameCountIn  != NULL);
48123     MA_ASSERT(pFrameCountOut != NULL);
48124
48125     pFramesInS16       = (const ma_int16*)pFramesIn;
48126     pFramesOutS16      = (      ma_int16*)pFramesOut;
48127     frameCountIn       = *pFrameCountIn;
48128     frameCountOut      = *pFrameCountOut;
48129     framesProcessedIn  = 0;
48130     framesProcessedOut = 0;
48131
48132     while (framesProcessedOut < frameCountOut) {
48133         /* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */
48134         while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
48135             ma_uint32 iChannel;
48136
48137             if (pFramesInS16 != NULL) {
48138                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
48139                     pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
48140                     pResampler->x1.s16[iChannel] = pFramesInS16[iChannel];
48141                 }
48142                 pFramesInS16 += pResampler->config.channels;
48143             } else {
48144                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
48145                     pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
48146                     pResampler->x1.s16[iChannel] = 0;
48147                 }
48148             }
48149
48150             /* Filter. */
48151             ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pResampler->x1.s16, pResampler->x1.s16);
48152
48153             framesProcessedIn     += 1;
48154             pResampler->inTimeInt -= 1;
48155         }
48156
48157         if (pResampler->inTimeInt > 0) {
48158             break;  /* Ran out of input data. */
48159         }
48160
48161         /* Getting here means the frames have been loaded and filtered and we can generate the next output frame. */
48162         if (pFramesOutS16 != NULL) {
48163             MA_ASSERT(pResampler->inTimeInt == 0);
48164             ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16);
48165
48166             pFramesOutS16 += pResampler->config.channels;
48167         }
48168
48169         framesProcessedOut += 1;
48170
48171         /* Advance time forward. */
48172         pResampler->inTimeInt  += pResampler->inAdvanceInt;
48173         pResampler->inTimeFrac += pResampler->inAdvanceFrac;
48174         if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
48175             pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
48176             pResampler->inTimeInt  += 1;
48177         }
48178     }
48179
48180     *pFrameCountIn  = framesProcessedIn;
48181     *pFrameCountOut = framesProcessedOut;
48182
48183     return MA_SUCCESS;
48184 }
48185
48186 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)
48187 {
48188     const ma_int16* pFramesInS16;
48189     /* */ ma_int16* pFramesOutS16;
48190     ma_uint64 frameCountIn;
48191     ma_uint64 frameCountOut;
48192     ma_uint64 framesProcessedIn;
48193     ma_uint64 framesProcessedOut;
48194
48195     MA_ASSERT(pResampler     != NULL);
48196     MA_ASSERT(pFrameCountIn  != NULL);
48197     MA_ASSERT(pFrameCountOut != NULL);
48198
48199     pFramesInS16       = (const ma_int16*)pFramesIn;
48200     pFramesOutS16      = (      ma_int16*)pFramesOut;
48201     frameCountIn       = *pFrameCountIn;
48202     frameCountOut      = *pFrameCountOut;
48203     framesProcessedIn  = 0;
48204     framesProcessedOut = 0;
48205
48206     while (framesProcessedOut < frameCountOut) {
48207         /* Before interpolating we need to load the buffers. */
48208         while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
48209             ma_uint32 iChannel;
48210
48211             if (pFramesInS16 != NULL) {
48212                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
48213                     pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
48214                     pResampler->x1.s16[iChannel] = pFramesInS16[iChannel];
48215                 }
48216                 pFramesInS16 += pResampler->config.channels;
48217             } else {
48218                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
48219                     pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
48220                     pResampler->x1.s16[iChannel] = 0;
48221                 }
48222             }
48223
48224             framesProcessedIn     += 1;
48225             pResampler->inTimeInt -= 1;
48226         }
48227
48228         if (pResampler->inTimeInt > 0) {
48229             break;  /* Ran out of input data. */
48230         }
48231
48232         /* Getting here means the frames have been loaded and we can generate the next output frame. */
48233         if (pFramesOutS16 != NULL) {
48234             MA_ASSERT(pResampler->inTimeInt == 0);
48235             ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16);
48236
48237             /* Filter. */
48238             ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pFramesOutS16, pFramesOutS16);
48239
48240             pFramesOutS16 += pResampler->config.channels;
48241         }
48242
48243         framesProcessedOut += 1;
48244
48245         /* Advance time forward. */
48246         pResampler->inTimeInt  += pResampler->inAdvanceInt;
48247         pResampler->inTimeFrac += pResampler->inAdvanceFrac;
48248         if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
48249             pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
48250             pResampler->inTimeInt  += 1;
48251         }
48252     }
48253
48254     *pFrameCountIn  = framesProcessedIn;
48255     *pFrameCountOut = framesProcessedOut;
48256
48257     return MA_SUCCESS;
48258 }
48259
48260 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)
48261 {
48262     MA_ASSERT(pResampler != NULL);
48263
48264     if (pResampler->config.sampleRateIn > pResampler->config.sampleRateOut) {
48265         return ma_linear_resampler_process_pcm_frames_s16_downsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
48266     } else {
48267         return ma_linear_resampler_process_pcm_frames_s16_upsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
48268     }
48269 }
48270
48271
48272 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)
48273 {
48274     const float* pFramesInF32;
48275     /* */ float* pFramesOutF32;
48276     ma_uint64 frameCountIn;
48277     ma_uint64 frameCountOut;
48278     ma_uint64 framesProcessedIn;
48279     ma_uint64 framesProcessedOut;
48280
48281     MA_ASSERT(pResampler     != NULL);
48282     MA_ASSERT(pFrameCountIn  != NULL);
48283     MA_ASSERT(pFrameCountOut != NULL);
48284
48285     pFramesInF32       = (const float*)pFramesIn;
48286     pFramesOutF32      = (      float*)pFramesOut;
48287     frameCountIn       = *pFrameCountIn;
48288     frameCountOut      = *pFrameCountOut;
48289     framesProcessedIn  = 0;
48290     framesProcessedOut = 0;
48291
48292     while (framesProcessedOut < frameCountOut) {
48293         /* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */
48294         while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
48295             ma_uint32 iChannel;
48296
48297             if (pFramesInF32 != NULL) {
48298                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
48299                     pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
48300                     pResampler->x1.f32[iChannel] = pFramesInF32[iChannel];
48301                 }
48302                 pFramesInF32 += pResampler->config.channels;
48303             } else {
48304                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
48305                     pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
48306                     pResampler->x1.f32[iChannel] = 0;
48307                 }
48308             }
48309
48310             /* Filter. */
48311             ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pResampler->x1.f32, pResampler->x1.f32);
48312
48313             framesProcessedIn     += 1;
48314             pResampler->inTimeInt -= 1;
48315         }
48316
48317         if (pResampler->inTimeInt > 0) {
48318             break;  /* Ran out of input data. */
48319         }
48320
48321         /* Getting here means the frames have been loaded and filtered and we can generate the next output frame. */
48322         if (pFramesOutF32 != NULL) {
48323             MA_ASSERT(pResampler->inTimeInt == 0);
48324             ma_linear_resampler_interpolate_frame_f32(pResampler, pFramesOutF32);
48325
48326             pFramesOutF32 += pResampler->config.channels;
48327         }
48328
48329         framesProcessedOut += 1;
48330
48331         /* Advance time forward. */
48332         pResampler->inTimeInt  += pResampler->inAdvanceInt;
48333         pResampler->inTimeFrac += pResampler->inAdvanceFrac;
48334         if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
48335             pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
48336             pResampler->inTimeInt  += 1;
48337         }
48338     }
48339
48340     *pFrameCountIn  = framesProcessedIn;
48341     *pFrameCountOut = framesProcessedOut;
48342
48343     return MA_SUCCESS;
48344 }
48345
48346 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)
48347 {
48348     const float* pFramesInF32;
48349     /* */ float* pFramesOutF32;
48350     ma_uint64 frameCountIn;
48351     ma_uint64 frameCountOut;
48352     ma_uint64 framesProcessedIn;
48353     ma_uint64 framesProcessedOut;
48354
48355     MA_ASSERT(pResampler     != NULL);
48356     MA_ASSERT(pFrameCountIn  != NULL);
48357     MA_ASSERT(pFrameCountOut != NULL);
48358
48359     pFramesInF32       = (const float*)pFramesIn;
48360     pFramesOutF32      = (      float*)pFramesOut;
48361     frameCountIn       = *pFrameCountIn;
48362     frameCountOut      = *pFrameCountOut;
48363     framesProcessedIn  = 0;
48364     framesProcessedOut = 0;
48365
48366     while (framesProcessedOut < frameCountOut) {
48367         /* Before interpolating we need to load the buffers. */
48368         while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
48369             ma_uint32 iChannel;
48370
48371             if (pFramesInF32 != NULL) {
48372                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
48373                     pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
48374                     pResampler->x1.f32[iChannel] = pFramesInF32[iChannel];
48375                 }
48376                 pFramesInF32 += pResampler->config.channels;
48377             } else {
48378                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
48379                     pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
48380                     pResampler->x1.f32[iChannel] = 0;
48381                 }
48382             }
48383
48384             framesProcessedIn     += 1;
48385             pResampler->inTimeInt -= 1;
48386         }
48387
48388         if (pResampler->inTimeInt > 0) {
48389             break;  /* Ran out of input data. */
48390         }
48391
48392         /* Getting here means the frames have been loaded and we can generate the next output frame. */
48393         if (pFramesOutF32 != NULL) {
48394             MA_ASSERT(pResampler->inTimeInt == 0);
48395             ma_linear_resampler_interpolate_frame_f32(pResampler, pFramesOutF32);
48396
48397             /* Filter. */
48398             ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pFramesOutF32, pFramesOutF32);
48399
48400             pFramesOutF32 += pResampler->config.channels;
48401         }
48402
48403         framesProcessedOut += 1;
48404
48405         /* Advance time forward. */
48406         pResampler->inTimeInt  += pResampler->inAdvanceInt;
48407         pResampler->inTimeFrac += pResampler->inAdvanceFrac;
48408         if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
48409             pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
48410             pResampler->inTimeInt  += 1;
48411         }
48412     }
48413
48414     *pFrameCountIn  = framesProcessedIn;
48415     *pFrameCountOut = framesProcessedOut;
48416
48417     return MA_SUCCESS;
48418 }
48419
48420 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)
48421 {
48422     MA_ASSERT(pResampler != NULL);
48423
48424     if (pResampler->config.sampleRateIn > pResampler->config.sampleRateOut) {
48425         return ma_linear_resampler_process_pcm_frames_f32_downsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
48426     } else {
48427         return ma_linear_resampler_process_pcm_frames_f32_upsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
48428     }
48429 }
48430
48431
48432 MA_API ma_result ma_linear_resampler_process_pcm_frames(ma_linear_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
48433 {
48434     if (pResampler == NULL) {
48435         return MA_INVALID_ARGS;
48436     }
48437
48438     /*  */ if (pResampler->config.format == ma_format_s16) {
48439         return ma_linear_resampler_process_pcm_frames_s16(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
48440     } else if (pResampler->config.format == ma_format_f32) {
48441         return ma_linear_resampler_process_pcm_frames_f32(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
48442     } else {
48443         /* 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(). */
48444         MA_ASSERT(MA_FALSE);
48445         return MA_INVALID_ARGS;
48446     }
48447 }
48448
48449
48450 MA_API ma_result ma_linear_resampler_set_rate(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
48451 {
48452     return ma_linear_resampler_set_rate_internal(pResampler, NULL, NULL, sampleRateIn, sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_TRUE);
48453 }
48454
48455 MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResampler, float ratioInOut)
48456 {
48457     ma_uint32 n;
48458     ma_uint32 d;
48459
48460     d = 1000;
48461     n = (ma_uint32)(ratioInOut * d);
48462
48463     if (n == 0) {
48464         return MA_INVALID_ARGS; /* Ratio too small. */
48465     }
48466
48467     MA_ASSERT(n != 0);
48468
48469     return ma_linear_resampler_set_rate(pResampler, n, d);
48470 }
48471
48472 MA_API ma_uint64 ma_linear_resampler_get_input_latency(const ma_linear_resampler* pResampler)
48473 {
48474     if (pResampler == NULL) {
48475         return 0;
48476     }
48477
48478     return 1 + ma_lpf_get_latency(&pResampler->lpf);
48479 }
48480
48481 MA_API ma_uint64 ma_linear_resampler_get_output_latency(const ma_linear_resampler* pResampler)
48482 {
48483     if (pResampler == NULL) {
48484         return 0;
48485     }
48486
48487     return ma_linear_resampler_get_input_latency(pResampler) * pResampler->config.sampleRateOut / pResampler->config.sampleRateIn;
48488 }
48489
48490 MA_API ma_result ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount)
48491 {
48492     ma_uint64 inputFrameCount;
48493
48494     if (pInputFrameCount == NULL) {
48495         return MA_INVALID_ARGS;
48496     }
48497
48498     *pInputFrameCount = 0;
48499
48500     if (pResampler == NULL) {
48501         return MA_INVALID_ARGS;
48502     }
48503
48504     if (outputFrameCount == 0) {
48505         return MA_SUCCESS;
48506     }
48507
48508     /* Any whole input frames are consumed before the first output frame is generated. */
48509     inputFrameCount = pResampler->inTimeInt;
48510     outputFrameCount -= 1;
48511
48512     /* The rest of the output frames can be calculated in constant time. */
48513     inputFrameCount += outputFrameCount * pResampler->inAdvanceInt;
48514     inputFrameCount += (pResampler->inTimeFrac + (outputFrameCount * pResampler->inAdvanceFrac)) / pResampler->config.sampleRateOut;
48515
48516     *pInputFrameCount = inputFrameCount;
48517
48518     return MA_SUCCESS;
48519 }
48520
48521 MA_API ma_result ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount)
48522 {
48523     ma_uint64 outputFrameCount;
48524     ma_uint64 preliminaryInputFrameCountFromFrac;
48525     ma_uint64 preliminaryInputFrameCount;
48526
48527     if (pOutputFrameCount == NULL) {
48528         return MA_INVALID_ARGS;
48529     }
48530
48531     *pOutputFrameCount = 0;
48532
48533     if (pResampler == NULL) {
48534         return MA_INVALID_ARGS;
48535     }
48536
48537     /*
48538     The first step is to get a preliminary output frame count. This will either be exactly equal to what we need, or less by 1. We need to
48539     determine how many input frames will be consumed by this value. If it's greater than our original input frame count it means we won't
48540     be able to generate an extra frame because we will have run out of input data. Otherwise we will have enough input for the generation
48541     of an extra output frame. This add-by-one logic is necessary due to how the data loading logic works when processing frames.
48542     */
48543     outputFrameCount = (inputFrameCount * pResampler->config.sampleRateOut) / pResampler->config.sampleRateIn;
48544
48545     /*
48546     We need to determine how many *whole* input frames will have been processed to generate our preliminary output frame count. This is
48547     used in the logic below to determine whether or not we need to add an extra output frame.
48548     */
48549     preliminaryInputFrameCountFromFrac = (pResampler->inTimeFrac + outputFrameCount*pResampler->inAdvanceFrac) / pResampler->config.sampleRateOut;
48550     preliminaryInputFrameCount         = (pResampler->inTimeInt  + outputFrameCount*pResampler->inAdvanceInt ) + preliminaryInputFrameCountFromFrac;
48551
48552     /*
48553     If the total number of *whole* input frames that would be required to generate our preliminary output frame count is greather than
48554     the amount of whole input frames we have available as input we need to *not* add an extra output frame as there won't be enough data
48555     to actually process. Otherwise we need to add the extra output frame.
48556     */
48557     if (preliminaryInputFrameCount <= inputFrameCount) {
48558         outputFrameCount += 1;
48559     }
48560
48561     *pOutputFrameCount = outputFrameCount;
48562
48563     return MA_SUCCESS;
48564 }
48565
48566
48567 /* Linear resampler backend vtable. */
48568 static ma_linear_resampler_config ma_resampling_backend_get_config__linear(const ma_resampler_config* pConfig)
48569 {
48570     ma_linear_resampler_config linearConfig;
48571
48572     linearConfig = ma_linear_resampler_config_init(pConfig->format, pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut);
48573     linearConfig.lpfOrder = pConfig->linear.lpfOrder;
48574
48575     return linearConfig;
48576 }
48577
48578 static ma_result ma_resampling_backend_get_heap_size__linear(void* pUserData, const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes)
48579 {
48580     ma_linear_resampler_config linearConfig;
48581
48582     (void)pUserData;
48583
48584     linearConfig = ma_resampling_backend_get_config__linear(pConfig);
48585
48586     return ma_linear_resampler_get_heap_size(&linearConfig, pHeapSizeInBytes);
48587 }
48588
48589 static ma_result ma_resampling_backend_init__linear(void* pUserData, const ma_resampler_config* pConfig, void* pHeap, ma_resampling_backend** ppBackend)
48590 {
48591     ma_resampler* pResampler = (ma_resampler*)pUserData;
48592     ma_result result;
48593     ma_linear_resampler_config linearConfig;
48594
48595     (void)pUserData;
48596
48597     linearConfig = ma_resampling_backend_get_config__linear(pConfig);
48598
48599     result = ma_linear_resampler_init_preallocated(&linearConfig, pHeap, &pResampler->state.linear);
48600     if (result != MA_SUCCESS) {
48601         return result;
48602     }
48603
48604     *ppBackend = &pResampler->state.linear;
48605
48606     return MA_SUCCESS;
48607 }
48608
48609 static void ma_resampling_backend_uninit__linear(void* pUserData, ma_resampling_backend* pBackend, const ma_allocation_callbacks* pAllocationCallbacks)
48610 {
48611     (void)pUserData;
48612
48613     ma_linear_resampler_uninit((ma_linear_resampler*)pBackend, pAllocationCallbacks);
48614 }
48615
48616 static ma_result ma_resampling_backend_process__linear(void* pUserData, ma_resampling_backend* pBackend, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
48617 {
48618     (void)pUserData;
48619
48620     return ma_linear_resampler_process_pcm_frames((ma_linear_resampler*)pBackend, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
48621 }
48622
48623 static ma_result ma_resampling_backend_set_rate__linear(void* pUserData, ma_resampling_backend* pBackend, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
48624 {
48625     (void)pUserData;
48626
48627     return ma_linear_resampler_set_rate((ma_linear_resampler*)pBackend, sampleRateIn, sampleRateOut);
48628 }
48629
48630 static ma_uint64 ma_resampling_backend_get_input_latency__linear(void* pUserData, const ma_resampling_backend* pBackend)
48631 {
48632     (void)pUserData;
48633
48634     return ma_linear_resampler_get_input_latency((const ma_linear_resampler*)pBackend);
48635 }
48636
48637 static ma_uint64 ma_resampling_backend_get_output_latency__linear(void* pUserData, const ma_resampling_backend* pBackend)
48638 {
48639     (void)pUserData;
48640
48641     return ma_linear_resampler_get_output_latency((const ma_linear_resampler*)pBackend);
48642 }
48643
48644 static ma_result ma_resampling_backend_get_required_input_frame_count__linear(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount)
48645 {
48646     (void)pUserData;
48647
48648     return ma_linear_resampler_get_required_input_frame_count((const ma_linear_resampler*)pBackend, outputFrameCount, pInputFrameCount);
48649 }
48650
48651 static ma_result ma_resampling_backend_get_expected_output_frame_count__linear(void* pUserData, const ma_resampling_backend* pBackend, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount)
48652 {
48653     (void)pUserData;
48654
48655     return ma_linear_resampler_get_expected_output_frame_count((const ma_linear_resampler*)pBackend, inputFrameCount, pOutputFrameCount);
48656 }
48657
48658 static ma_resampling_backend_vtable g_ma_linear_resampler_vtable =
48659 {
48660     ma_resampling_backend_get_heap_size__linear,
48661     ma_resampling_backend_init__linear,
48662     ma_resampling_backend_uninit__linear,
48663     ma_resampling_backend_process__linear,
48664     ma_resampling_backend_set_rate__linear,
48665     ma_resampling_backend_get_input_latency__linear,
48666     ma_resampling_backend_get_output_latency__linear,
48667     ma_resampling_backend_get_required_input_frame_count__linear,
48668     ma_resampling_backend_get_expected_output_frame_count__linear
48669 };
48670
48671
48672
48673 MA_API ma_resampler_config ma_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_resample_algorithm algorithm)
48674 {
48675     ma_resampler_config config;
48676
48677     MA_ZERO_OBJECT(&config);
48678     config.format = format;
48679     config.channels = channels;
48680     config.sampleRateIn = sampleRateIn;
48681     config.sampleRateOut = sampleRateOut;
48682     config.algorithm = algorithm;
48683
48684     /* Linear. */
48685     config.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
48686
48687     return config;
48688 }
48689
48690 static ma_result ma_resampler_get_vtable(const ma_resampler_config* pConfig, ma_resampler* pResampler, ma_resampling_backend_vtable** ppVTable, void** ppUserData)
48691 {
48692     MA_ASSERT(pConfig    != NULL);
48693     MA_ASSERT(ppVTable   != NULL);
48694     MA_ASSERT(ppUserData != NULL);
48695
48696     /* Safety. */
48697     *ppVTable   = NULL;
48698     *ppUserData = NULL;
48699
48700     switch (pConfig->algorithm)
48701     {
48702         case ma_resample_algorithm_linear:
48703         {
48704             *ppVTable   = &g_ma_linear_resampler_vtable;
48705             *ppUserData = pResampler;
48706         } break;
48707
48708         case ma_resample_algorithm_custom:
48709         {
48710             *ppVTable   = pConfig->pBackendVTable;
48711             *ppUserData = pConfig->pBackendUserData;
48712         } break;
48713
48714         default: return MA_INVALID_ARGS;
48715     }
48716
48717     return MA_SUCCESS;
48718 }
48719
48720 MA_API ma_result ma_resampler_get_heap_size(const ma_resampler_config* pConfig, size_t* pHeapSizeInBytes)
48721 {
48722     ma_result result;
48723     ma_resampling_backend_vtable* pVTable;
48724     void* pVTableUserData;
48725
48726     if (pHeapSizeInBytes == NULL) {
48727         return MA_INVALID_ARGS;
48728     }
48729
48730     *pHeapSizeInBytes = 0;
48731
48732     if (pConfig == NULL) {
48733         return MA_INVALID_ARGS;
48734     }
48735
48736     result = ma_resampler_get_vtable(pConfig, NULL, &pVTable, &pVTableUserData);
48737     if (result != MA_SUCCESS) {
48738         return result;
48739     }
48740
48741     if (pVTable == NULL || pVTable->onGetHeapSize == NULL) {
48742         return MA_NOT_IMPLEMENTED;
48743     }
48744
48745     result = pVTable->onGetHeapSize(pVTableUserData, pConfig, pHeapSizeInBytes);
48746     if (result != MA_SUCCESS) {
48747         return result;
48748     }
48749
48750     return MA_SUCCESS;
48751 }
48752
48753 MA_API ma_result ma_resampler_init_preallocated(const ma_resampler_config* pConfig, void* pHeap, ma_resampler* pResampler)
48754 {
48755     ma_result result;
48756
48757     if (pResampler == NULL) {
48758         return MA_INVALID_ARGS;
48759     }
48760
48761     MA_ZERO_OBJECT(pResampler);
48762
48763     if (pConfig == NULL) {
48764         return MA_INVALID_ARGS;
48765     }
48766
48767     pResampler->_pHeap        = pHeap;
48768     pResampler->format        = pConfig->format;
48769     pResampler->channels      = pConfig->channels;
48770     pResampler->sampleRateIn  = pConfig->sampleRateIn;
48771     pResampler->sampleRateOut = pConfig->sampleRateOut;
48772
48773     result = ma_resampler_get_vtable(pConfig, pResampler, &pResampler->pBackendVTable, &pResampler->pBackendUserData);
48774     if (result != MA_SUCCESS) {
48775         return result;
48776     }
48777
48778     if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onInit == NULL) {
48779         return MA_NOT_IMPLEMENTED;  /* onInit not implemented. */
48780     }
48781
48782     result = pResampler->pBackendVTable->onInit(pResampler->pBackendUserData, pConfig, pHeap, &pResampler->pBackend);
48783     if (result != MA_SUCCESS) {
48784         return result;
48785     }
48786
48787     return MA_SUCCESS;
48788 }
48789
48790 MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_resampler* pResampler)
48791 {
48792     ma_result result;
48793     size_t heapSizeInBytes;
48794     void* pHeap;
48795
48796     result = ma_resampler_get_heap_size(pConfig, &heapSizeInBytes);
48797     if (result != MA_SUCCESS) {
48798         return result;
48799     }
48800
48801     if (heapSizeInBytes > 0) {
48802         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
48803         if (pHeap == NULL) {
48804             return MA_OUT_OF_MEMORY;
48805         }
48806     } else {
48807         pHeap = NULL;
48808     }
48809
48810     result = ma_resampler_init_preallocated(pConfig, pHeap, pResampler);
48811     if (result != MA_SUCCESS) {
48812         return result;
48813     }
48814
48815     pResampler->_ownsHeap = MA_TRUE;
48816     return MA_SUCCESS;
48817 }
48818
48819 MA_API void ma_resampler_uninit(ma_resampler* pResampler, const ma_allocation_callbacks* pAllocationCallbacks)
48820 {
48821     if (pResampler == NULL) {
48822         return;
48823     }
48824
48825     if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onUninit == NULL) {
48826         return;
48827     }
48828
48829     pResampler->pBackendVTable->onUninit(pResampler->pBackendUserData, pResampler->pBackend, pAllocationCallbacks);
48830
48831     if (pResampler->_ownsHeap) {
48832         ma_free(pResampler->_pHeap, pAllocationCallbacks);
48833     }
48834 }
48835
48836 MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
48837 {
48838     if (pResampler == NULL) {
48839         return MA_INVALID_ARGS;
48840     }
48841
48842     if (pFrameCountOut == NULL && pFrameCountIn == NULL) {
48843         return MA_INVALID_ARGS;
48844     }
48845
48846     if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onProcess == NULL) {
48847         return MA_NOT_IMPLEMENTED;
48848     }
48849
48850     return pResampler->pBackendVTable->onProcess(pResampler->pBackendUserData, pResampler->pBackend, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
48851 }
48852
48853 MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
48854 {
48855     ma_result result;
48856
48857     if (pResampler == NULL) {
48858         return MA_INVALID_ARGS;
48859     }
48860
48861     if (sampleRateIn == 0 || sampleRateOut == 0) {
48862         return MA_INVALID_ARGS;
48863     }
48864
48865     if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onSetRate == NULL) {
48866         return MA_NOT_IMPLEMENTED;
48867     }
48868
48869     result = pResampler->pBackendVTable->onSetRate(pResampler->pBackendUserData, pResampler->pBackend, sampleRateIn, sampleRateOut);
48870     if (result != MA_SUCCESS) {
48871         return result;
48872     }
48873
48874     pResampler->sampleRateIn  = sampleRateIn;
48875     pResampler->sampleRateOut = sampleRateOut;
48876
48877     return MA_SUCCESS;
48878 }
48879
48880 MA_API ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio)
48881 {
48882     ma_uint32 n;
48883     ma_uint32 d;
48884
48885     if (pResampler == NULL) {
48886         return MA_INVALID_ARGS;
48887     }
48888
48889     d = 1000;
48890     n = (ma_uint32)(ratio * d);
48891
48892     if (n == 0) {
48893         return MA_INVALID_ARGS; /* Ratio too small. */
48894     }
48895
48896     MA_ASSERT(n != 0);
48897
48898     return ma_resampler_set_rate(pResampler, n, d);
48899 }
48900
48901 MA_API ma_uint64 ma_resampler_get_input_latency(const ma_resampler* pResampler)
48902 {
48903     if (pResampler == NULL) {
48904         return 0;
48905     }
48906
48907     if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetInputLatency == NULL) {
48908         return 0;
48909     }
48910
48911     return pResampler->pBackendVTable->onGetInputLatency(pResampler->pBackendUserData, pResampler->pBackend);
48912 }
48913
48914 MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler)
48915 {
48916     if (pResampler == NULL) {
48917         return 0;
48918     }
48919
48920     if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetOutputLatency == NULL) {
48921         return 0;
48922     }
48923
48924     return pResampler->pBackendVTable->onGetOutputLatency(pResampler->pBackendUserData, pResampler->pBackend);
48925 }
48926
48927 MA_API ma_result ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount)
48928 {
48929     if (pInputFrameCount == NULL) {
48930         return MA_INVALID_ARGS;
48931     }
48932
48933     *pInputFrameCount = 0;
48934
48935     if (pResampler == NULL) {
48936         return MA_INVALID_ARGS;
48937     }
48938
48939     if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetRequiredInputFrameCount == NULL) {
48940         return MA_NOT_IMPLEMENTED;
48941     }
48942
48943     return pResampler->pBackendVTable->onGetRequiredInputFrameCount(pResampler->pBackendUserData, pResampler->pBackend, outputFrameCount, pInputFrameCount);
48944 }
48945
48946 MA_API ma_result ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount)
48947 {
48948     if (pOutputFrameCount == NULL) {
48949         return MA_INVALID_ARGS;
48950     }
48951
48952     *pOutputFrameCount = 0;
48953
48954     if (pResampler == NULL) {
48955         return MA_INVALID_ARGS;
48956     }
48957
48958     if (pResampler->pBackendVTable == NULL || pResampler->pBackendVTable->onGetExpectedOutputFrameCount == NULL) {
48959         return MA_NOT_IMPLEMENTED;
48960     }
48961
48962     return pResampler->pBackendVTable->onGetExpectedOutputFrameCount(pResampler->pBackendUserData, pResampler->pBackend, inputFrameCount, pOutputFrameCount);
48963 }
48964
48965 /**************************************************************************************************************************************************************
48966
48967 Channel Conversion
48968
48969 **************************************************************************************************************************************************************/
48970 #ifndef MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT
48971 #define MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT  12
48972 #endif
48973
48974 #define MA_PLANE_LEFT      0
48975 #define MA_PLANE_RIGHT     1
48976 #define MA_PLANE_FRONT     2
48977 #define MA_PLANE_BACK      3
48978 #define MA_PLANE_BOTTOM    4
48979 #define MA_PLANE_TOP       5
48980
48981 static float g_maChannelPlaneRatios[MA_CHANNEL_POSITION_COUNT][6] = {
48982     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_NONE */
48983     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_MONO */
48984     { 0.5f,  0.0f,  0.5f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_FRONT_LEFT */
48985     { 0.0f,  0.5f,  0.5f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_FRONT_RIGHT */
48986     { 0.0f,  0.0f,  1.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_FRONT_CENTER */
48987     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_LFE */
48988     { 0.5f,  0.0f,  0.0f,  0.5f,  0.0f,  0.0f},  /* MA_CHANNEL_BACK_LEFT */
48989     { 0.0f,  0.5f,  0.0f,  0.5f,  0.0f,  0.0f},  /* MA_CHANNEL_BACK_RIGHT */
48990     { 0.25f, 0.0f,  0.75f, 0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_FRONT_LEFT_CENTER */
48991     { 0.0f,  0.25f, 0.75f, 0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_FRONT_RIGHT_CENTER */
48992     { 0.0f,  0.0f,  0.0f,  1.0f,  0.0f,  0.0f},  /* MA_CHANNEL_BACK_CENTER */
48993     { 1.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_SIDE_LEFT */
48994     { 0.0f,  1.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_SIDE_RIGHT */
48995     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  1.0f},  /* MA_CHANNEL_TOP_CENTER */
48996     { 0.33f, 0.0f,  0.33f, 0.0f,  0.0f,  0.34f}, /* MA_CHANNEL_TOP_FRONT_LEFT */
48997     { 0.0f,  0.0f,  0.5f,  0.0f,  0.0f,  0.5f},  /* MA_CHANNEL_TOP_FRONT_CENTER */
48998     { 0.0f,  0.33f, 0.33f, 0.0f,  0.0f,  0.34f}, /* MA_CHANNEL_TOP_FRONT_RIGHT */
48999     { 0.33f, 0.0f,  0.0f,  0.33f, 0.0f,  0.34f}, /* MA_CHANNEL_TOP_BACK_LEFT */
49000     { 0.0f,  0.0f,  0.0f,  0.5f,  0.0f,  0.5f},  /* MA_CHANNEL_TOP_BACK_CENTER */
49001     { 0.0f,  0.33f, 0.0f,  0.33f, 0.0f,  0.34f}, /* MA_CHANNEL_TOP_BACK_RIGHT */
49002     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_0 */
49003     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_1 */
49004     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_2 */
49005     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_3 */
49006     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_4 */
49007     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_5 */
49008     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_6 */
49009     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_7 */
49010     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_8 */
49011     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_9 */
49012     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_10 */
49013     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_11 */
49014     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_12 */
49015     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_13 */
49016     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_14 */
49017     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_15 */
49018     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_16 */
49019     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_17 */
49020     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_18 */
49021     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_19 */
49022     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_20 */
49023     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_21 */
49024     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_22 */
49025     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_23 */
49026     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_24 */
49027     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_25 */
49028     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_26 */
49029     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_27 */
49030     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_28 */
49031     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_29 */
49032     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_30 */
49033     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_31 */
49034 };
49035
49036 static float ma_calculate_channel_position_rectangular_weight(ma_channel channelPositionA, ma_channel channelPositionB)
49037 {
49038     /*
49039     Imagine the following simplified example: You have a single input speaker which is the front/left speaker which you want to convert to
49040     the following output configuration:
49041
49042      - front/left
49043      - side/left
49044      - back/left
49045
49046     The front/left output is easy - it the same speaker position so it receives the full contribution of the front/left input. The amount
49047     of contribution to apply to the side/left and back/left speakers, however, is a bit more complicated.
49048
49049     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
49050     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
49051     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
49052     receive some amount of contribution from front/left speaker. The amount of contribution depends on how many planes are shared between
49053     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
49054     across 3 spatial dimensions.
49055
49056     The first thing to do is figure out how each speaker's volume is spread over each of plane:
49057      - front/left:     2 planes (front and left)      = 1/2 = half it's total volume on each plane
49058      - side/left:      1 plane (left only)            = 1/1 = entire volume from left plane
49059      - back/left:      2 planes (back and left)       = 1/2 = half it's total volume on each plane
49060      - top/front/left: 3 planes (top, front and left) = 1/3 = one third it's total volume on each plane
49061
49062     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
49063     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
49064     taken by the other to produce the final contribution.
49065     */
49066
49067     /* Contribution = Sum(Volume to Give * Volume to Take) */
49068     float contribution =
49069         g_maChannelPlaneRatios[channelPositionA][0] * g_maChannelPlaneRatios[channelPositionB][0] +
49070         g_maChannelPlaneRatios[channelPositionA][1] * g_maChannelPlaneRatios[channelPositionB][1] +
49071         g_maChannelPlaneRatios[channelPositionA][2] * g_maChannelPlaneRatios[channelPositionB][2] +
49072         g_maChannelPlaneRatios[channelPositionA][3] * g_maChannelPlaneRatios[channelPositionB][3] +
49073         g_maChannelPlaneRatios[channelPositionA][4] * g_maChannelPlaneRatios[channelPositionB][4] +
49074         g_maChannelPlaneRatios[channelPositionA][5] * g_maChannelPlaneRatios[channelPositionB][5];
49075
49076     return contribution;
49077 }
49078
49079 MA_API ma_channel_converter_config ma_channel_converter_config_init(ma_format format, ma_uint32 channelsIn, const ma_channel* pChannelMapIn, ma_uint32 channelsOut, const ma_channel* pChannelMapOut, ma_channel_mix_mode mixingMode)
49080 {
49081     ma_channel_converter_config config;
49082
49083     MA_ZERO_OBJECT(&config);
49084     config.format         = format;
49085     config.channelsIn     = channelsIn;
49086     config.channelsOut    = channelsOut;
49087     config.pChannelMapIn  = pChannelMapIn;
49088     config.pChannelMapOut = pChannelMapOut;
49089     config.mixingMode     = mixingMode;
49090
49091     return config;
49092 }
49093
49094 static ma_int32 ma_channel_converter_float_to_fixed(float x)
49095 {
49096     return (ma_int32)(x * (1<<MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT));
49097 }
49098
49099 static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition)
49100 {
49101     int i;
49102
49103     if (channelPosition == MA_CHANNEL_NONE || channelPosition == MA_CHANNEL_MONO || channelPosition == MA_CHANNEL_LFE) {
49104         return MA_FALSE;
49105     }
49106
49107     if (channelPosition >= MA_CHANNEL_AUX_0 && channelPosition <= MA_CHANNEL_AUX_31) {
49108         return MA_FALSE;
49109     }
49110
49111     for (i = 0; i < 6; ++i) {   /* Each side of a cube. */
49112         if (g_maChannelPlaneRatios[channelPosition][i] != 0) {
49113             return MA_TRUE;
49114         }
49115     }
49116
49117     return MA_FALSE;
49118 }
49119
49120
49121 static ma_bool32 ma_channel_map_is_passthrough(const ma_channel* pChannelMapIn, ma_uint32 channelsIn, const ma_channel* pChannelMapOut, ma_uint32 channelsOut)
49122 {
49123     if (channelsOut == channelsIn) {
49124         return ma_channel_map_is_equal(pChannelMapOut, pChannelMapIn, channelsOut);
49125     } else {
49126         return MA_FALSE;    /* Channel counts differ, so cannot be a passthrough. */
49127     }
49128 }
49129
49130 static ma_channel_conversion_path ma_channel_map_get_conversion_path(const ma_channel* pChannelMapIn, ma_uint32 channelsIn, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, ma_channel_mix_mode mode)
49131 {
49132     if (ma_channel_map_is_passthrough(pChannelMapIn, channelsIn, pChannelMapOut, channelsOut)) {
49133         return ma_channel_conversion_path_passthrough;
49134     }
49135
49136     if (channelsOut == 1 && (pChannelMapOut == NULL || pChannelMapOut[0] == MA_CHANNEL_MONO)) {
49137         return ma_channel_conversion_path_mono_out;
49138     }
49139
49140     if (channelsIn == 1 && (pChannelMapIn == NULL || pChannelMapIn[0] == MA_CHANNEL_MONO)) {
49141         return ma_channel_conversion_path_mono_in;
49142     }
49143
49144     if (mode == ma_channel_mix_mode_custom_weights) {
49145         return ma_channel_conversion_path_weights;
49146     }
49147
49148     /*
49149     We can use a simple shuffle if both channel maps have the same channel count and all channel
49150     positions are present in both.
49151     */
49152     if (channelsIn == channelsOut) {
49153         ma_uint32 iChannelIn;
49154         ma_bool32 areAllChannelPositionsPresent = MA_TRUE;
49155         for (iChannelIn = 0; iChannelIn < channelsIn; ++iChannelIn) {
49156             ma_bool32 isInputChannelPositionInOutput = MA_FALSE;
49157             if (ma_channel_map_contains_channel_position(channelsOut, pChannelMapOut, ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn))) {
49158                 isInputChannelPositionInOutput = MA_TRUE;
49159                 break;
49160             }
49161
49162             if (!isInputChannelPositionInOutput) {
49163                 areAllChannelPositionsPresent = MA_FALSE;
49164                 break;
49165             }
49166         }
49167
49168         if (areAllChannelPositionsPresent) {
49169             return ma_channel_conversion_path_shuffle;
49170         }
49171     }
49172
49173     /* Getting here means we'll need to use weights. */
49174     return ma_channel_conversion_path_weights;
49175 }
49176
49177
49178 static ma_result ma_channel_map_build_shuffle_table(const ma_channel* pChannelMapIn, ma_uint32 channelCountIn, const ma_channel* pChannelMapOut, ma_uint32 channelCountOut, ma_uint8* pShuffleTable)
49179 {
49180     ma_uint32 iChannelIn;
49181     ma_uint32 iChannelOut;
49182
49183     if (pShuffleTable == NULL || channelCountIn == 0 || channelCountOut == 0) {
49184         return MA_INVALID_ARGS;
49185     }
49186
49187     /*
49188     When building the shuffle table we just do a 1:1 mapping based on the first occurance of a channel. If the
49189     input channel has more than one occurance of a channel position, the second one will be ignored.
49190     */
49191     for (iChannelOut = 0; iChannelOut < channelCountOut; iChannelOut += 1) {
49192         ma_channel channelOut;
49193
49194         /* Default to MA_CHANNEL_INDEX_NULL so that if a mapping is not found it'll be set appropriately. */
49195         pShuffleTable[iChannelOut] = MA_CHANNEL_INDEX_NULL;
49196
49197         channelOut = ma_channel_map_get_channel(pChannelMapOut, channelCountOut, iChannelOut);
49198         for (iChannelIn = 0; iChannelIn < channelCountIn; iChannelIn += 1) {
49199             ma_channel channelIn;
49200
49201             channelIn = ma_channel_map_get_channel(pChannelMapIn, channelCountIn, iChannelIn);
49202             if (channelOut == channelIn) {
49203                 pShuffleTable[iChannelOut] = (ma_uint8)iChannelIn;
49204                 break;
49205             }
49206
49207             /*
49208             Getting here means the channels don't exactly match, but we are going to support some
49209             relaxed matching for practicality. If, for example, there are two stereo channel maps,
49210             but one uses front left/right and the other uses side left/right, it makes logical
49211             sense to just map these. The way we'll do it is we'll check if there is a logical
49212             corresponding mapping, and if so, apply it, but we will *not* break from the loop,
49213             thereby giving the loop a chance to find an exact match later which will take priority.
49214             */
49215             switch (channelOut)
49216             {
49217                 /* Left channels. */
49218                 case MA_CHANNEL_FRONT_LEFT:
49219                 case MA_CHANNEL_SIDE_LEFT:
49220                 {
49221                     switch (channelIn) {
49222                         case MA_CHANNEL_FRONT_LEFT:
49223                         case MA_CHANNEL_SIDE_LEFT:
49224                         {
49225                             pShuffleTable[iChannelOut] = (ma_uint8)iChannelIn;
49226                         } break;
49227                     }
49228                 } break;
49229
49230                 /* Right channels. */
49231                 case MA_CHANNEL_FRONT_RIGHT:
49232                 case MA_CHANNEL_SIDE_RIGHT:
49233                 {
49234                     switch (channelIn) {
49235                         case MA_CHANNEL_FRONT_RIGHT:
49236                         case MA_CHANNEL_SIDE_RIGHT:
49237                         {
49238                             pShuffleTable[iChannelOut] = (ma_uint8)iChannelIn;
49239                         } break;
49240                     }
49241                 } break;
49242
49243                 default: break;
49244             }
49245         }
49246     }
49247
49248     return MA_SUCCESS;
49249 }
49250
49251
49252 static void ma_channel_map_apply_shuffle_table_u8(ma_uint8* pFramesOut, ma_uint32 channelsOut, const ma_uint8* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable)
49253 {
49254     ma_uint64 iFrame;
49255     ma_uint32 iChannelOut;
49256
49257     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
49258         for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49259             ma_uint8 iChannelIn = pShuffleTable[iChannelOut];
49260             if (iChannelIn < channelsIn) {  /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */
49261                 pFramesOut[iChannelOut] = pFramesIn[iChannelIn];
49262             } else {
49263                 pFramesOut[iChannelOut] = 0;
49264             }
49265         }
49266
49267         pFramesOut += channelsOut;
49268         pFramesIn  += channelsIn;
49269     }
49270 }
49271
49272 static void ma_channel_map_apply_shuffle_table_s16(ma_int16* pFramesOut, ma_uint32 channelsOut, const ma_int16* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable)
49273 {
49274     ma_uint64 iFrame;
49275     ma_uint32 iChannelOut;
49276
49277     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
49278         for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49279             ma_uint8 iChannelIn = pShuffleTable[iChannelOut];
49280             if (iChannelIn < channelsIn) {  /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */
49281                 pFramesOut[iChannelOut] = pFramesIn[iChannelIn];
49282             } else {
49283                 pFramesOut[iChannelOut] = 0;
49284             }
49285         }
49286
49287         pFramesOut += channelsOut;
49288         pFramesIn  += channelsIn;
49289     }
49290 }
49291
49292 static void ma_channel_map_apply_shuffle_table_s24(ma_uint8* pFramesOut, ma_uint32 channelsOut, const ma_uint8* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable)
49293 {
49294     ma_uint64 iFrame;
49295     ma_uint32 iChannelOut;
49296
49297     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
49298         for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49299             ma_uint8 iChannelIn = pShuffleTable[iChannelOut];
49300             if (iChannelIn < channelsIn) {  /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */
49301                 pFramesOut[iChannelOut*3 + 0] = pFramesIn[iChannelIn*3 + 0];
49302                 pFramesOut[iChannelOut*3 + 1] = pFramesIn[iChannelIn*3 + 1];
49303                 pFramesOut[iChannelOut*3 + 2] = pFramesIn[iChannelIn*3 + 2];
49304             } else {
49305                 pFramesOut[iChannelOut*3 + 0] = 0;
49306             }   pFramesOut[iChannelOut*3 + 1] = 0;
49307         }       pFramesOut[iChannelOut*3 + 2] = 0;
49308
49309         pFramesOut += channelsOut*3;
49310         pFramesIn  += channelsIn*3;
49311     }
49312 }
49313
49314 static void ma_channel_map_apply_shuffle_table_s32(ma_int32* pFramesOut, ma_uint32 channelsOut, const ma_int32* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable)
49315 {
49316     ma_uint64 iFrame;
49317     ma_uint32 iChannelOut;
49318
49319     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
49320         for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49321             ma_uint8 iChannelIn = pShuffleTable[iChannelOut];
49322             if (iChannelIn < channelsIn) {  /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */
49323                 pFramesOut[iChannelOut] = pFramesIn[iChannelIn];
49324             } else {
49325                 pFramesOut[iChannelOut] = 0;
49326             }
49327         }
49328
49329         pFramesOut += channelsOut;
49330         pFramesIn  += channelsIn;
49331     }
49332 }
49333
49334 static void ma_channel_map_apply_shuffle_table_f32(float* pFramesOut, ma_uint32 channelsOut, const float* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable)
49335 {
49336     ma_uint64 iFrame;
49337     ma_uint32 iChannelOut;
49338
49339     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
49340         for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49341             ma_uint8 iChannelIn = pShuffleTable[iChannelOut];
49342             if (iChannelIn < channelsIn) {  /* For safety, and to deal with MA_CHANNEL_INDEX_NULL. */
49343                 pFramesOut[iChannelOut] = pFramesIn[iChannelIn];
49344             } else {
49345                 pFramesOut[iChannelOut] = 0;
49346             }
49347         }
49348
49349         pFramesOut += channelsOut;
49350         pFramesIn  += channelsIn;
49351     }
49352 }
49353
49354 static ma_result ma_channel_map_apply_shuffle_table(void* pFramesOut, ma_uint32 channelsOut, const void* pFramesIn, ma_uint32 channelsIn, ma_uint64 frameCount, const ma_uint8* pShuffleTable, ma_format format)
49355 {
49356     if (pFramesOut == NULL || pFramesIn == NULL || channelsOut == 0 || pShuffleTable == NULL) {
49357         return MA_INVALID_ARGS;
49358     }
49359
49360     switch (format)
49361     {
49362         case ma_format_u8:
49363         {
49364             ma_channel_map_apply_shuffle_table_u8((ma_uint8*)pFramesOut, channelsOut, (const ma_uint8*)pFramesIn, channelsIn, frameCount, pShuffleTable);
49365         } break;
49366
49367         case ma_format_s16:
49368         {
49369             ma_channel_map_apply_shuffle_table_s16((ma_int16*)pFramesOut, channelsOut, (const ma_int16*)pFramesIn, channelsIn, frameCount, pShuffleTable);
49370         } break;
49371
49372         case ma_format_s24:
49373         {
49374             ma_channel_map_apply_shuffle_table_s24((ma_uint8*)pFramesOut, channelsOut, (const ma_uint8*)pFramesIn, channelsIn, frameCount, pShuffleTable);
49375         } break;
49376
49377         case ma_format_s32:
49378         {
49379             ma_channel_map_apply_shuffle_table_s32((ma_int32*)pFramesOut, channelsOut, (const ma_int32*)pFramesIn, channelsIn, frameCount, pShuffleTable);
49380         } break;
49381
49382         case ma_format_f32:
49383         {
49384             ma_channel_map_apply_shuffle_table_f32((float*)pFramesOut, channelsOut, (const float*)pFramesIn, channelsIn, frameCount, pShuffleTable);
49385         } break;
49386
49387         default: return MA_INVALID_ARGS;    /* Unknown format. */
49388     }
49389
49390     return MA_SUCCESS;
49391 }
49392
49393 static ma_result ma_channel_map_apply_mono_out_f32(float* pFramesOut, const float* pFramesIn, const ma_channel* pChannelMapIn, ma_uint32 channelsIn, ma_uint64 frameCount)
49394 {
49395     ma_uint64 iFrame;
49396     ma_uint32 iChannelIn;
49397     ma_uint32 accumulationCount;
49398
49399     if (pFramesOut == NULL || pFramesIn == NULL || channelsIn == 0) {
49400         return MA_INVALID_ARGS;
49401     }
49402
49403     /* In this case the output stream needs to be the average of all channels, ignoring NONE. */
49404
49405     /* A quick pre-processing step to get the accumulation counter since we're ignoring NONE channels. */
49406     accumulationCount = 0;
49407     for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) {
49408         if (ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn) != MA_CHANNEL_NONE) {
49409             accumulationCount += 1;
49410         }
49411     }
49412
49413     if (accumulationCount > 0) {    /* <-- Prevent a division by zero. */
49414         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
49415             float accumulation = 0;
49416
49417             for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) {
49418                 ma_channel channelIn = ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn);
49419                 if (channelIn != MA_CHANNEL_NONE) {
49420                     accumulation += pFramesIn[iChannelIn];
49421                 }
49422             }
49423
49424             pFramesOut[0] = accumulation / accumulationCount;
49425             pFramesOut += 1;
49426             pFramesIn  += channelsIn;
49427         }
49428     } else {
49429         ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, 1);
49430     }
49431
49432     return MA_SUCCESS;
49433 }
49434
49435 static ma_result ma_channel_map_apply_mono_in_f32(float* pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* pFramesIn, ma_uint64 frameCount, ma_mono_expansion_mode monoExpansionMode)
49436 {
49437     ma_uint64 iFrame;
49438     ma_uint32 iChannelOut;
49439
49440     if (pFramesOut == NULL || channelsOut == 0 || pFramesIn == NULL) {
49441         return MA_INVALID_ARGS;
49442     }
49443
49444     /* Note that the MA_CHANNEL_NONE channel must be ignored in all cases. */
49445     switch (monoExpansionMode)
49446     {
49447         case ma_mono_expansion_mode_average:
49448         {
49449             float weight;
49450             ma_uint32 validChannelCount = 0;
49451
49452             for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49453                 ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut);
49454                 if (channelOut != MA_CHANNEL_NONE) {
49455                     validChannelCount += 1;
49456                 }
49457             }
49458
49459             weight = 1.0f / validChannelCount;
49460
49461             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
49462                 for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49463                     ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut);
49464                     if (channelOut != MA_CHANNEL_NONE) {
49465                         pFramesOut[iChannelOut] = pFramesIn[0] * weight;
49466                     }
49467                 }
49468
49469                 pFramesOut += channelsOut;
49470                 pFramesIn  += 1;
49471             }
49472         } break;
49473
49474         case ma_mono_expansion_mode_stereo_only:
49475         {
49476             if (channelsOut >= 2) {
49477                 ma_uint32 iChannelLeft  = (ma_uint32)-1;
49478                 ma_uint32 iChannelRight = (ma_uint32)-1;
49479
49480                 /*
49481                 We first need to find our stereo channels. We prefer front-left and front-right, but
49482                 if they're not available, we'll also try side-left and side-right. If neither are
49483                 available we'll fall through to the default case below.
49484                 */
49485                 for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49486                     ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut);
49487                     if (channelOut == MA_CHANNEL_SIDE_LEFT) {
49488                         iChannelLeft  = iChannelOut;
49489                     }
49490                     if (channelOut == MA_CHANNEL_SIDE_RIGHT) {
49491                         iChannelRight = iChannelOut;
49492                     }
49493                 }
49494
49495                 for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49496                     ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut);
49497                     if (channelOut == MA_CHANNEL_FRONT_LEFT) {
49498                         iChannelLeft  = iChannelOut;
49499                     }
49500                     if (channelOut == MA_CHANNEL_FRONT_RIGHT) {
49501                         iChannelRight = iChannelOut;
49502                     }
49503                 }
49504
49505
49506                 if (iChannelLeft != (ma_uint32)-1 && iChannelRight != (ma_uint32)-1) {
49507                     /* We found our stereo channels so we can duplicate the signal across those channels. */
49508                     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
49509                         for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49510                             ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut);
49511                             if (channelOut != MA_CHANNEL_NONE) {
49512                                 if (iChannelOut == iChannelLeft || iChannelOut == iChannelRight) {
49513                                     pFramesOut[iChannelOut] = pFramesIn[0];
49514                                 } else {
49515                                     pFramesOut[iChannelOut] = 0.0f;
49516                                 }
49517                             }
49518                         }
49519
49520                         pFramesOut += channelsOut;
49521                         pFramesIn  += 1;
49522                     }
49523
49524                     break;  /* Get out of the switch. */
49525                 } else {
49526                     /* Fallthrough. Does not have left and right channels. */
49527                     goto default_handler;
49528                 }
49529             } else {
49530                 /* Fallthrough. Does not have stereo channels. */
49531                 goto default_handler;
49532             }
49533         };  /* Fallthrough. See comments above. */
49534
49535         case ma_mono_expansion_mode_duplicate:
49536         default:
49537         {
49538             default_handler:
49539             {
49540                 for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
49541                     for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49542                         ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut);
49543                         if (channelOut != MA_CHANNEL_NONE) {
49544                             pFramesOut[iChannelOut] = pFramesIn[0];
49545                         }
49546                     }
49547
49548                     pFramesOut += channelsOut;
49549                     pFramesIn  += 1;
49550                 }
49551             }
49552         } break;
49553     }
49554
49555     return MA_SUCCESS;
49556 }
49557
49558 static void ma_channel_map_apply_f32(float* pFramesOut, const ma_channel* pChannelMapOut, ma_uint32 channelsOut, const float* pFramesIn, const ma_channel* pChannelMapIn, ma_uint32 channelsIn, ma_uint64 frameCount, ma_channel_mix_mode mode, ma_mono_expansion_mode monoExpansionMode)
49559 {
49560     ma_channel_conversion_path conversionPath = ma_channel_map_get_conversion_path(pChannelMapIn, channelsIn, pChannelMapOut, channelsOut, mode);
49561
49562     /* Optimized Path: Passthrough */
49563     if (conversionPath == ma_channel_conversion_path_passthrough) {
49564         ma_copy_pcm_frames(pFramesOut, pFramesIn, frameCount, ma_format_f32, channelsOut);
49565         return;
49566     }
49567
49568     /* Special Path: Mono Output. */
49569     if (conversionPath == ma_channel_conversion_path_mono_out) {
49570         ma_channel_map_apply_mono_out_f32(pFramesOut, pFramesIn, pChannelMapIn, channelsIn, frameCount);
49571         return;
49572     }
49573
49574     /* Special Path: Mono Input. */
49575     if (conversionPath == ma_channel_conversion_path_mono_in) {
49576         ma_channel_map_apply_mono_in_f32(pFramesOut, pChannelMapOut, channelsOut, pFramesIn, frameCount, monoExpansionMode);
49577         return;
49578     }
49579
49580     /* Getting here means we aren't running on an optimized conversion path. */
49581     if (channelsOut <= MA_MAX_CHANNELS) {
49582         ma_result result;
49583
49584         if (mode == ma_channel_mix_mode_simple) {
49585             ma_channel shuffleTable[MA_MAX_CHANNELS];
49586
49587             result = ma_channel_map_build_shuffle_table(pChannelMapIn, channelsIn, pChannelMapOut, channelsOut, shuffleTable);
49588             if (result != MA_SUCCESS) {
49589                 return;
49590             }
49591
49592             result = ma_channel_map_apply_shuffle_table(pFramesOut, channelsOut, pFramesIn, channelsIn, frameCount, shuffleTable, ma_format_f32);
49593             if (result != MA_SUCCESS) {
49594                 return;
49595             }
49596         } else {
49597             ma_uint32 iFrame;
49598             ma_uint32 iChannelOut;
49599             ma_uint32 iChannelIn;
49600             float weights[32][32];  /* Do not use MA_MAX_CHANNELS here! */
49601
49602             /*
49603             If we have a small enough number of channels, pre-compute the weights. Otherwise we'll just need to
49604             fall back to a slower path because otherwise we'll run out of stack space.
49605             */
49606             if (channelsIn <= ma_countof(weights) && channelsOut <= ma_countof(weights)) {
49607                 /* Pre-compute weights. */
49608                 for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49609                     ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut);
49610                     for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) {
49611                         ma_channel channelIn = ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn);
49612                         weights[iChannelOut][iChannelIn] = ma_calculate_channel_position_rectangular_weight(channelOut, channelIn);
49613                     }
49614                 }
49615
49616                 for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
49617                     for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49618                         float accumulation = 0;
49619
49620                         for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) {
49621                             accumulation += pFramesIn[iChannelIn] * weights[iChannelOut][iChannelIn];
49622                         }
49623
49624                         pFramesOut[iChannelOut] = accumulation;
49625                     }
49626
49627                     pFramesOut += channelsOut;
49628                     pFramesIn  += channelsIn;
49629                 }
49630             } else {
49631                 /* Cannot pre-compute weights because not enough room in stack-allocated buffer. */
49632                 for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
49633                     for (iChannelOut = 0; iChannelOut < channelsOut; iChannelOut += 1) {
49634                         float accumulation = 0;
49635                         ma_channel channelOut = ma_channel_map_get_channel(pChannelMapOut, channelsOut, iChannelOut);
49636
49637                         for (iChannelIn = 0; iChannelIn < channelsIn; iChannelIn += 1) {
49638                             ma_channel channelIn = ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn);
49639                             accumulation += pFramesIn[iChannelIn] * ma_calculate_channel_position_rectangular_weight(channelOut, channelIn);
49640                         }
49641
49642                         pFramesOut[iChannelOut] = accumulation;
49643                     }
49644
49645                     pFramesOut += channelsOut;
49646                     pFramesIn  += channelsIn;
49647                 }
49648             }
49649         }
49650     } else {
49651         /* Fall back to silence. If you hit this, what are you doing with so many channels?! */
49652         ma_silence_pcm_frames(pFramesOut, frameCount, ma_format_f32, channelsOut);
49653     }
49654 }
49655
49656
49657 typedef struct
49658 {
49659     size_t sizeInBytes;
49660     size_t channelMapInOffset;
49661     size_t channelMapOutOffset;
49662     size_t shuffleTableOffset;
49663     size_t weightsOffset;
49664 } ma_channel_converter_heap_layout;
49665
49666 static ma_channel_conversion_path ma_channel_converter_config_get_conversion_path(const ma_channel_converter_config* pConfig)
49667 {
49668     return ma_channel_map_get_conversion_path(pConfig->pChannelMapIn, pConfig->channelsIn, pConfig->pChannelMapOut, pConfig->channelsOut, pConfig->mixingMode);
49669 }
49670
49671 static ma_result ma_channel_converter_get_heap_layout(const ma_channel_converter_config* pConfig, ma_channel_converter_heap_layout* pHeapLayout)
49672 {
49673     ma_channel_conversion_path conversionPath;
49674
49675     MA_ASSERT(pHeapLayout != NULL);
49676
49677     if (pConfig == NULL) {
49678         return MA_INVALID_ARGS;
49679     }
49680
49681     if (pConfig->channelsIn == 0 || pConfig->channelsOut == 0) {
49682         return MA_INVALID_ARGS;
49683     }
49684
49685     if (!ma_channel_map_is_valid(pConfig->pChannelMapIn, pConfig->channelsIn)) {
49686         return MA_INVALID_ARGS;
49687     }
49688
49689     if (!ma_channel_map_is_valid(pConfig->pChannelMapOut, pConfig->channelsOut)) {
49690         return MA_INVALID_ARGS;
49691     }
49692
49693     pHeapLayout->sizeInBytes = 0;
49694
49695     /* Input channel map. Only need to allocate this if we have an input channel map (otherwise default channel map is assumed). */
49696     pHeapLayout->channelMapInOffset = pHeapLayout->sizeInBytes;
49697     if (pConfig->pChannelMapIn != NULL) {
49698         pHeapLayout->sizeInBytes += sizeof(ma_channel) * pConfig->channelsIn;
49699     }
49700
49701     /* Output channel map. Only need to allocate this if we have an output channel map (otherwise default channel map is assumed). */
49702     pHeapLayout->channelMapOutOffset = pHeapLayout->sizeInBytes;
49703     if (pConfig->pChannelMapOut != NULL) {
49704         pHeapLayout->sizeInBytes += sizeof(ma_channel) * pConfig->channelsOut;
49705     }
49706
49707     /* Alignment for the next section. */
49708     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
49709
49710     /* Whether or not we use weights of a shuffle table depends on the channel map themselves and the algorithm we've chosen. */
49711     conversionPath = ma_channel_converter_config_get_conversion_path(pConfig);
49712
49713     /* Shuffle table */
49714     pHeapLayout->shuffleTableOffset = pHeapLayout->sizeInBytes;
49715     if (conversionPath == ma_channel_conversion_path_shuffle) {
49716         pHeapLayout->sizeInBytes += sizeof(ma_uint8) * pConfig->channelsOut;
49717     }
49718
49719     /* Weights */
49720     pHeapLayout->weightsOffset = pHeapLayout->sizeInBytes;
49721     if (conversionPath == ma_channel_conversion_path_weights) {
49722         pHeapLayout->sizeInBytes += sizeof(float*) * pConfig->channelsIn;
49723         pHeapLayout->sizeInBytes += sizeof(float ) * pConfig->channelsIn * pConfig->channelsOut;
49724     }
49725
49726     /* Make sure allocation size is aligned. */
49727     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
49728
49729     return MA_SUCCESS;
49730 }
49731
49732 MA_API ma_result ma_channel_converter_get_heap_size(const ma_channel_converter_config* pConfig, size_t* pHeapSizeInBytes)
49733 {
49734     ma_result result;
49735     ma_channel_converter_heap_layout heapLayout;
49736
49737     if (pHeapSizeInBytes == NULL) {
49738         return MA_INVALID_ARGS;
49739     }
49740
49741     *pHeapSizeInBytes = 0;
49742
49743     result = ma_channel_converter_get_heap_layout(pConfig, &heapLayout);
49744     if (result != MA_SUCCESS) {
49745         return result;
49746     }
49747
49748     *pHeapSizeInBytes = heapLayout.sizeInBytes;
49749
49750     return MA_SUCCESS;
49751 }
49752
49753 MA_API ma_result ma_channel_converter_init_preallocated(const ma_channel_converter_config* pConfig, void* pHeap, ma_channel_converter* pConverter)
49754 {
49755     ma_result result;
49756     ma_channel_converter_heap_layout heapLayout;
49757
49758     if (pConverter == NULL) {
49759         return MA_INVALID_ARGS;
49760     }
49761
49762     MA_ZERO_OBJECT(pConverter);
49763
49764     result = ma_channel_converter_get_heap_layout(pConfig, &heapLayout);
49765     if (result != MA_SUCCESS) {
49766         return result;
49767     }
49768
49769     pConverter->_pHeap = pHeap;
49770     MA_ZERO_MEMORY(pConverter->_pHeap, heapLayout.sizeInBytes);
49771
49772     pConverter->format      = pConfig->format;
49773     pConverter->channelsIn  = pConfig->channelsIn;
49774     pConverter->channelsOut = pConfig->channelsOut;
49775     pConverter->mixingMode  = pConfig->mixingMode;
49776
49777     if (pConfig->pChannelMapIn != NULL) {
49778         pConverter->pChannelMapIn = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapInOffset);
49779         ma_channel_map_copy_or_default(pConverter->pChannelMapIn, pConfig->channelsIn, pConfig->pChannelMapIn, pConfig->channelsIn);
49780     } else {
49781         pConverter->pChannelMapIn = NULL;   /* Use default channel map. */
49782     }
49783
49784     if (pConfig->pChannelMapOut != NULL) {
49785         pConverter->pChannelMapOut = (ma_channel*)ma_offset_ptr(pHeap, heapLayout.channelMapOutOffset);
49786         ma_channel_map_copy_or_default(pConverter->pChannelMapOut, pConfig->channelsOut, pConfig->pChannelMapOut, pConfig->channelsOut);
49787     } else {
49788         pConverter->pChannelMapOut = NULL;  /* Use default channel map. */
49789     }
49790
49791     pConverter->conversionPath = ma_channel_converter_config_get_conversion_path(pConfig);
49792
49793     if (pConverter->conversionPath == ma_channel_conversion_path_shuffle) {
49794         pConverter->pShuffleTable = (ma_uint8*)ma_offset_ptr(pHeap, heapLayout.shuffleTableOffset);
49795         ma_channel_map_build_shuffle_table(pConverter->pChannelMapIn, pConverter->channelsIn, pConverter->pChannelMapOut, pConverter->channelsOut, pConverter->pShuffleTable);
49796     }
49797
49798     if (pConverter->conversionPath == ma_channel_conversion_path_weights) {
49799         ma_uint32 iChannelIn;
49800         ma_uint32 iChannelOut;
49801
49802         if (pConverter->format == ma_format_f32) {
49803             pConverter->weights.f32 = (float**   )ma_offset_ptr(pHeap, heapLayout.weightsOffset);
49804             for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) {
49805                 pConverter->weights.f32[iChannelIn] = (float*)ma_offset_ptr(pHeap, heapLayout.weightsOffset + ((sizeof(float*) * pConverter->channelsIn) + (sizeof(float) * pConverter->channelsOut * iChannelIn)));
49806             }
49807         } else {
49808             pConverter->weights.s16 = (ma_int32**)ma_offset_ptr(pHeap, heapLayout.weightsOffset);
49809             for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) {
49810                 pConverter->weights.s16[iChannelIn] = (ma_int32*)ma_offset_ptr(pHeap, heapLayout.weightsOffset + ((sizeof(ma_int32*) * pConverter->channelsIn) + (sizeof(ma_int32) * pConverter->channelsOut * iChannelIn)));
49811             }
49812         }
49813
49814         /* Silence our weights by default. */
49815         for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) {
49816             for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; iChannelOut += 1) {
49817                 if (pConverter->format == ma_format_f32) {
49818                     pConverter->weights.f32[iChannelIn][iChannelOut] = 0.0f;
49819                 } else {
49820                     pConverter->weights.s16[iChannelIn][iChannelOut] = 0;
49821                 }
49822             }
49823         }
49824
49825         /*
49826         We now need to fill out our weights table. This is determined by the mixing mode.
49827         */
49828         switch (pConverter->mixingMode)
49829         {
49830             case ma_channel_mix_mode_custom_weights:
49831             {
49832                 if (pConfig->ppWeights == NULL) {
49833                     return MA_INVALID_ARGS; /* Config specified a custom weights mixing mode, but no custom weights have been specified. */
49834                 }
49835
49836                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) {
49837                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; iChannelOut += 1) {
49838                         float weight = pConfig->ppWeights[iChannelIn][iChannelOut];
49839
49840                         if (pConverter->format == ma_format_f32) {
49841                             pConverter->weights.f32[iChannelIn][iChannelOut] = weight;
49842                         } else {
49843                             pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight);
49844                         }
49845                     }
49846                 }
49847             } break;
49848
49849             case ma_channel_mix_mode_simple:
49850             {
49851                 /* In simple mode, excess channels need to be silenced or dropped. */
49852                 ma_uint32 iChannel;
49853                 for (iChannel = 0; iChannel < ma_min(pConverter->channelsIn, pConverter->channelsOut); iChannel += 1) {
49854                     if (pConverter->format == ma_format_f32) {
49855                         if (pConverter->weights.f32[iChannel][iChannel] == 0) {
49856                             pConverter->weights.f32[iChannel][iChannel] = 1;
49857                         }
49858                     } else {
49859                         if (pConverter->weights.s16[iChannel][iChannel] == 0) {
49860                             pConverter->weights.s16[iChannel][iChannel] = ma_channel_converter_float_to_fixed(1);
49861                         }
49862                     }
49863                 }
49864             } break;
49865
49866             case ma_channel_mix_mode_rectangular:
49867             default:
49868             {
49869                 /* Unmapped input channels. */
49870                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
49871                     ma_channel channelPosIn = pConverter->pChannelMapIn[iChannelIn];
49872
49873                     if (ma_is_spatial_channel_position(channelPosIn)) {
49874                         if (!ma_channel_map_contains_channel_position(pConverter->channelsOut, pConverter->pChannelMapOut, channelPosIn)) {
49875                             for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
49876                                 ma_channel channelPosOut = pConverter->pChannelMapOut[iChannelOut];
49877
49878                                 if (ma_is_spatial_channel_position(channelPosOut)) {
49879                                     float weight = 0;
49880                                     if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) {
49881                                         weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut);
49882                                     }
49883
49884                                     /* Only apply the weight if we haven't already got some contribution from the respective channels. */
49885                                     if (pConverter->format == ma_format_f32) {
49886                                         if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) {
49887                                             pConverter->weights.f32[iChannelIn][iChannelOut] = weight;
49888                                         }
49889                                     } else {
49890                                         if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) {
49891                                             pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight);
49892                                         }
49893                                     }
49894                                 }
49895                             }
49896                         }
49897                     }
49898                 }
49899
49900                 /* Unmapped output channels. */
49901                 for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
49902                     ma_channel channelPosOut = pConverter->pChannelMapOut[iChannelOut];
49903
49904                     if (ma_is_spatial_channel_position(channelPosOut)) {
49905                         if (!ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->pChannelMapIn, channelPosOut)) {
49906                             for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
49907                                 ma_channel channelPosIn = pConverter->pChannelMapIn[iChannelIn];
49908
49909                                 if (ma_is_spatial_channel_position(channelPosIn)) {
49910                                     float weight = 0;
49911                                     if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) {
49912                                         weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut);
49913                                     }
49914
49915                                     /* Only apply the weight if we haven't already got some contribution from the respective channels. */
49916                                     if (pConverter->format == ma_format_f32) {
49917                                         if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) {
49918                                             pConverter->weights.f32[iChannelIn][iChannelOut] = weight;
49919                                         }
49920                                     } else {
49921                                         if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) {
49922                                             pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight);
49923                                         }
49924                                     }
49925                                 }
49926                             }
49927                         }
49928                     }
49929                 }
49930             } break;
49931         }
49932     }
49933
49934     return MA_SUCCESS;
49935 }
49936
49937 MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_channel_converter* pConverter)
49938 {
49939     ma_result result;
49940     size_t heapSizeInBytes;
49941     void* pHeap;
49942
49943     result = ma_channel_converter_get_heap_size(pConfig, &heapSizeInBytes);
49944     if (result != MA_SUCCESS) {
49945         return result;
49946     }
49947
49948     if (heapSizeInBytes > 0) {
49949         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
49950         if (pHeap == NULL) {
49951             return MA_OUT_OF_MEMORY;
49952         }
49953     } else {
49954         pHeap = NULL;
49955     }
49956
49957     result = ma_channel_converter_init_preallocated(pConfig, pHeap, pConverter);
49958     if (result != MA_SUCCESS) {
49959         ma_free(pHeap, pAllocationCallbacks);
49960         return result;
49961     }
49962
49963     pConverter->_ownsHeap = MA_TRUE;
49964     return MA_SUCCESS;
49965 }
49966
49967 MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks)
49968 {
49969     if (pConverter == NULL) {
49970         return;
49971     }
49972
49973     if (pConverter->_ownsHeap) {
49974         ma_free(pConverter->_pHeap, pAllocationCallbacks);
49975     }
49976 }
49977
49978 static ma_result ma_channel_converter_process_pcm_frames__passthrough(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
49979 {
49980     MA_ASSERT(pConverter != NULL);
49981     MA_ASSERT(pFramesOut != NULL);
49982     MA_ASSERT(pFramesIn  != NULL);
49983
49984     ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut));
49985     return MA_SUCCESS;
49986 }
49987
49988 static ma_result ma_channel_converter_process_pcm_frames__shuffle(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
49989 {
49990     MA_ASSERT(pConverter != NULL);
49991     MA_ASSERT(pFramesOut != NULL);
49992     MA_ASSERT(pFramesIn  != NULL);
49993     MA_ASSERT(pConverter->channelsIn == pConverter->channelsOut);
49994
49995     return ma_channel_map_apply_shuffle_table(pFramesOut, pConverter->channelsOut, pFramesIn, pConverter->channelsIn, frameCount, pConverter->pShuffleTable, pConverter->format);
49996 }
49997
49998 static ma_result ma_channel_converter_process_pcm_frames__mono_in(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
49999 {
50000     ma_uint64 iFrame;
50001
50002     MA_ASSERT(pConverter != NULL);
50003     MA_ASSERT(pFramesOut != NULL);
50004     MA_ASSERT(pFramesIn  != NULL);
50005     MA_ASSERT(pConverter->channelsIn == 1);
50006
50007     switch (pConverter->format)
50008     {
50009         case ma_format_u8:
50010         {
50011             /* */ ma_uint8* pFramesOutU8 = (      ma_uint8*)pFramesOut;
50012             const ma_uint8* pFramesInU8  = (const ma_uint8*)pFramesIn;
50013
50014             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50015                 ma_uint32 iChannel;
50016                 for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
50017                     pFramesOutU8[iFrame*pConverter->channelsOut + iChannel] = pFramesInU8[iFrame];
50018                 }
50019             }
50020         } break;
50021
50022         case ma_format_s16:
50023         {
50024             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
50025             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
50026
50027             if (pConverter->channelsOut == 2) {
50028                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50029                     pFramesOutS16[iFrame*2 + 0] = pFramesInS16[iFrame];
50030                     pFramesOutS16[iFrame*2 + 1] = pFramesInS16[iFrame];
50031                 }
50032             } else {
50033                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50034                     ma_uint32 iChannel;
50035                     for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
50036                         pFramesOutS16[iFrame*pConverter->channelsOut + iChannel] = pFramesInS16[iFrame];
50037                     }
50038                 }
50039             }
50040         } break;
50041
50042         case ma_format_s24:
50043         {
50044             /* */ ma_uint8* pFramesOutS24 = (      ma_uint8*)pFramesOut;
50045             const ma_uint8* pFramesInS24  = (const ma_uint8*)pFramesIn;
50046
50047             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50048                 ma_uint32 iChannel;
50049                 for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
50050                     ma_uint64 iSampleOut = iFrame*pConverter->channelsOut + iChannel;
50051                     ma_uint64 iSampleIn  = iFrame;
50052                     pFramesOutS24[iSampleOut*3 + 0] = pFramesInS24[iSampleIn*3 + 0];
50053                     pFramesOutS24[iSampleOut*3 + 1] = pFramesInS24[iSampleIn*3 + 1];
50054                     pFramesOutS24[iSampleOut*3 + 2] = pFramesInS24[iSampleIn*3 + 2];
50055                 }
50056             }
50057         } break;
50058
50059         case ma_format_s32:
50060         {
50061             /* */ ma_int32* pFramesOutS32 = (      ma_int32*)pFramesOut;
50062             const ma_int32* pFramesInS32  = (const ma_int32*)pFramesIn;
50063
50064             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50065                 ma_uint32 iChannel;
50066                 for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
50067                     pFramesOutS32[iFrame*pConverter->channelsOut + iChannel] = pFramesInS32[iFrame];
50068                 }
50069             }
50070         } break;
50071
50072         case ma_format_f32:
50073         {
50074             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
50075             const float* pFramesInF32  = (const float*)pFramesIn;
50076
50077             if (pConverter->channelsOut == 2) {
50078                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50079                     pFramesOutF32[iFrame*2 + 0] = pFramesInF32[iFrame];
50080                     pFramesOutF32[iFrame*2 + 1] = pFramesInF32[iFrame];
50081                 }
50082             } else {
50083                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50084                     ma_uint32 iChannel;
50085                     for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
50086                         pFramesOutF32[iFrame*pConverter->channelsOut + iChannel] = pFramesInF32[iFrame];
50087                     }
50088                 }
50089             }
50090         } break;
50091
50092         default: return MA_INVALID_OPERATION;   /* Unknown format. */
50093     }
50094
50095     return MA_SUCCESS;
50096 }
50097
50098 static ma_result ma_channel_converter_process_pcm_frames__mono_out(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
50099 {
50100     ma_uint64 iFrame;
50101     ma_uint32 iChannel;
50102
50103     MA_ASSERT(pConverter != NULL);
50104     MA_ASSERT(pFramesOut != NULL);
50105     MA_ASSERT(pFramesIn  != NULL);
50106     MA_ASSERT(pConverter->channelsOut == 1);
50107
50108     switch (pConverter->format)
50109     {
50110         case ma_format_u8:
50111         {
50112             /* */ ma_uint8* pFramesOutU8 = (      ma_uint8*)pFramesOut;
50113             const ma_uint8* pFramesInU8  = (const ma_uint8*)pFramesIn;
50114
50115             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50116                 ma_int32 t = 0;
50117                 for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) {
50118                     t += ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8[iFrame*pConverter->channelsIn + iChannel]);
50119                 }
50120
50121                 pFramesOutU8[iFrame] = ma_clip_u8(t / pConverter->channelsOut);
50122             }
50123         } break;
50124
50125         case ma_format_s16:
50126         {
50127             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
50128             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
50129
50130             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50131                 ma_int32 t = 0;
50132                 for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) {
50133                     t += pFramesInS16[iFrame*pConverter->channelsIn + iChannel];
50134                 }
50135
50136                 pFramesOutS16[iFrame] = (ma_int16)(t / pConverter->channelsIn);
50137             }
50138         } break;
50139
50140         case ma_format_s24:
50141         {
50142             /* */ ma_uint8* pFramesOutS24 = (      ma_uint8*)pFramesOut;
50143             const ma_uint8* pFramesInS24  = (const ma_uint8*)pFramesIn;
50144
50145             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50146                 ma_int64 t = 0;
50147                 for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) {
50148                     t += ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24[(iFrame*pConverter->channelsIn + iChannel)*3]);
50149                 }
50150
50151                 ma_pcm_sample_s32_to_s24_no_scale(t / pConverter->channelsIn, &pFramesOutS24[iFrame*3]);
50152             }
50153         } break;
50154
50155         case ma_format_s32:
50156         {
50157             /* */ ma_int32* pFramesOutS32 = (      ma_int32*)pFramesOut;
50158             const ma_int32* pFramesInS32  = (const ma_int32*)pFramesIn;
50159
50160             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50161                 ma_int64 t = 0;
50162                 for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) {
50163                     t += pFramesInS32[iFrame*pConverter->channelsIn + iChannel];
50164                 }
50165
50166                 pFramesOutS32[iFrame] = (ma_int32)(t / pConverter->channelsIn);
50167             }
50168         } break;
50169
50170         case ma_format_f32:
50171         {
50172             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
50173             const float* pFramesInF32  = (const float*)pFramesIn;
50174
50175             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
50176                 float t = 0;
50177                 for (iChannel = 0; iChannel < pConverter->channelsIn; iChannel += 1) {
50178                     t += pFramesInF32[iFrame*pConverter->channelsIn + iChannel];
50179                 }
50180
50181                 pFramesOutF32[iFrame] = t / pConverter->channelsIn;
50182             }
50183         } break;
50184
50185         default: return MA_INVALID_OPERATION;   /* Unknown format. */
50186     }
50187
50188     return MA_SUCCESS;
50189 }
50190
50191 static ma_result ma_channel_converter_process_pcm_frames__weights(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
50192 {
50193     ma_uint32 iFrame;
50194     ma_uint32 iChannelIn;
50195     ma_uint32 iChannelOut;
50196
50197     MA_ASSERT(pConverter != NULL);
50198     MA_ASSERT(pFramesOut != NULL);
50199     MA_ASSERT(pFramesIn  != NULL);
50200
50201     /* This is the more complicated case. Each of the output channels is accumulated with 0 or more input channels. */
50202
50203     /* Clear. */
50204     ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut));
50205
50206     /* Accumulate. */
50207     switch (pConverter->format)
50208     {
50209         case ma_format_u8:
50210         {
50211             /* */ ma_uint8* pFramesOutU8 = (      ma_uint8*)pFramesOut;
50212             const ma_uint8* pFramesInU8  = (const ma_uint8*)pFramesIn;
50213
50214             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
50215                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
50216                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
50217                         ma_int16 u8_O = ma_pcm_sample_u8_to_s16_no_scale(pFramesOutU8[iFrame*pConverter->channelsOut + iChannelOut]);
50218                         ma_int16 u8_I = ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8 [iFrame*pConverter->channelsIn  + iChannelIn ]);
50219                         ma_int32 s    = (ma_int32)ma_clamp(u8_O + ((u8_I * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT), -128, 127);
50220                         pFramesOutU8[iFrame*pConverter->channelsOut + iChannelOut] = ma_clip_u8((ma_int16)s);
50221                     }
50222                 }
50223             }
50224         } break;
50225
50226         case ma_format_s16:
50227         {
50228             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
50229             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
50230
50231             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
50232                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
50233                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
50234                         ma_int32 s = pFramesOutS16[iFrame*pConverter->channelsOut + iChannelOut];
50235                         s += (pFramesInS16[iFrame*pConverter->channelsIn + iChannelIn] * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT;
50236
50237                         pFramesOutS16[iFrame*pConverter->channelsOut + iChannelOut] = (ma_int16)ma_clamp(s, -32768, 32767);
50238                     }
50239                 }
50240             }
50241         } break;
50242
50243         case ma_format_s24:
50244         {
50245             /* */ ma_uint8* pFramesOutS24 = (      ma_uint8*)pFramesOut;
50246             const ma_uint8* pFramesInS24  = (const ma_uint8*)pFramesIn;
50247
50248             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
50249                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
50250                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
50251                         ma_int64 s24_O = ma_pcm_sample_s24_to_s32_no_scale(&pFramesOutS24[(iFrame*pConverter->channelsOut + iChannelOut)*3]);
50252                         ma_int64 s24_I = ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24 [(iFrame*pConverter->channelsIn  + iChannelIn )*3]);
50253                         ma_int64 s24   = (ma_int32)ma_clamp(s24_O + ((s24_I * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT), -8388608, 8388607);
50254                         ma_pcm_sample_s32_to_s24_no_scale(s24, &pFramesOutS24[(iFrame*pConverter->channelsOut + iChannelOut)*3]);
50255                     }
50256                 }
50257             }
50258         } break;
50259
50260         case ma_format_s32:
50261         {
50262             /* */ ma_int32* pFramesOutS32 = (      ma_int32*)pFramesOut;
50263             const ma_int32* pFramesInS32  = (const ma_int32*)pFramesIn;
50264
50265             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
50266                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
50267                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
50268                         ma_int64 s = pFramesOutS32[iFrame*pConverter->channelsOut + iChannelOut];
50269                         s += ((ma_int64)pFramesInS32[iFrame*pConverter->channelsIn + iChannelIn] * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT;
50270
50271                         pFramesOutS32[iFrame*pConverter->channelsOut + iChannelOut] = ma_clip_s32(s);
50272                     }
50273                 }
50274             }
50275         } break;
50276
50277         case ma_format_f32:
50278         {
50279             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
50280             const float* pFramesInF32  = (const float*)pFramesIn;
50281
50282             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
50283                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
50284                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
50285                         pFramesOutF32[iFrame*pConverter->channelsOut + iChannelOut] += pFramesInF32[iFrame*pConverter->channelsIn + iChannelIn] * pConverter->weights.f32[iChannelIn][iChannelOut];
50286                     }
50287                 }
50288             }
50289         } break;
50290
50291         default: return MA_INVALID_OPERATION;   /* Unknown format. */
50292     }
50293
50294     return MA_SUCCESS;
50295 }
50296
50297 MA_API ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
50298 {
50299     if (pConverter == NULL) {
50300         return MA_INVALID_ARGS;
50301     }
50302
50303     if (pFramesOut == NULL) {
50304         return MA_INVALID_ARGS;
50305     }
50306
50307     if (pFramesIn == NULL) {
50308         ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut));
50309         return MA_SUCCESS;
50310     }
50311
50312     switch (pConverter->conversionPath)
50313     {
50314         case ma_channel_conversion_path_passthrough: return ma_channel_converter_process_pcm_frames__passthrough(pConverter, pFramesOut, pFramesIn, frameCount);
50315         case ma_channel_conversion_path_mono_out:    return ma_channel_converter_process_pcm_frames__mono_out(pConverter, pFramesOut, pFramesIn, frameCount);
50316         case ma_channel_conversion_path_mono_in:     return ma_channel_converter_process_pcm_frames__mono_in(pConverter, pFramesOut, pFramesIn, frameCount);
50317         case ma_channel_conversion_path_shuffle:     return ma_channel_converter_process_pcm_frames__shuffle(pConverter, pFramesOut, pFramesIn, frameCount);
50318         case ma_channel_conversion_path_weights:
50319         default:
50320         {
50321             return ma_channel_converter_process_pcm_frames__weights(pConverter, pFramesOut, pFramesIn, frameCount);
50322         }
50323     }
50324 }
50325
50326 MA_API ma_result ma_channel_converter_get_input_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap)
50327 {
50328     if (pConverter == NULL || pChannelMap == NULL) {
50329         return MA_INVALID_ARGS;
50330     }
50331
50332     ma_channel_map_copy_or_default(pChannelMap, channelMapCap, pConverter->pChannelMapIn, pConverter->channelsIn);
50333
50334     return MA_SUCCESS;
50335 }
50336
50337 MA_API ma_result ma_channel_converter_get_output_channel_map(const ma_channel_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap)
50338 {
50339     if (pConverter == NULL || pChannelMap == NULL) {
50340         return MA_INVALID_ARGS;
50341     }
50342
50343     ma_channel_map_copy_or_default(pChannelMap, channelMapCap, pConverter->pChannelMapOut, pConverter->channelsOut);
50344
50345     return MA_SUCCESS;
50346 }
50347
50348
50349 /**************************************************************************************************************************************************************
50350
50351 Data Conversion
50352
50353 **************************************************************************************************************************************************************/
50354 MA_API ma_data_converter_config ma_data_converter_config_init_default()
50355 {
50356     ma_data_converter_config config;
50357     MA_ZERO_OBJECT(&config);
50358
50359     config.ditherMode = ma_dither_mode_none;
50360     config.resampling.algorithm = ma_resample_algorithm_linear;
50361     config.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. */
50362
50363     /* Linear resampling defaults. */
50364     config.resampling.linear.lpfOrder = 1;
50365
50366     return config;
50367 }
50368
50369 MA_API 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)
50370 {
50371     ma_data_converter_config config = ma_data_converter_config_init_default();
50372     config.formatIn      = formatIn;
50373     config.formatOut     = formatOut;
50374     config.channelsIn    = channelsIn;
50375     config.channelsOut   = channelsOut;
50376     config.sampleRateIn  = sampleRateIn;
50377     config.sampleRateOut = sampleRateOut;
50378
50379     return config;
50380 }
50381
50382
50383 typedef struct
50384 {
50385     size_t sizeInBytes;
50386     size_t channelConverterOffset;
50387     size_t resamplerOffset;
50388 } ma_data_converter_heap_layout;
50389
50390 static ma_bool32 ma_data_converter_config_is_resampler_required(const ma_data_converter_config* pConfig)
50391 {
50392     MA_ASSERT(pConfig != NULL);
50393
50394     return pConfig->allowDynamicSampleRate || pConfig->sampleRateIn != pConfig->sampleRateOut;
50395 }
50396
50397 static ma_format ma_data_converter_config_get_mid_format(const ma_data_converter_config* pConfig)
50398 {
50399     MA_ASSERT(pConfig != NULL);
50400
50401     /*
50402     We want to avoid as much data conversion as possible. The channel converter and linear
50403     resampler both support s16 and f32 natively. We need to decide on the format to use for this
50404     stage. We call this the mid format because it's used in the middle stage of the conversion
50405     pipeline. If the output format is either s16 or f32 we use that one. If that is not the case it
50406     will do the same thing for the input format. If it's neither we just use f32. If we are using a
50407     custom resampling backend, we can only guarantee that f32 will be supported so we'll be forced
50408     to use that if resampling is required.
50409     */
50410     if (ma_data_converter_config_is_resampler_required(pConfig) && pConfig->resampling.algorithm != ma_resample_algorithm_linear) {
50411         return ma_format_f32;  /* <-- Force f32 since that is the only one we can guarantee will be supported by the resampler. */
50412     } else {
50413         /*  */ if (pConfig->formatOut == ma_format_s16 || pConfig->formatOut == ma_format_f32) {
50414             return pConfig->formatOut;
50415         } else if (pConfig->formatIn  == ma_format_s16 || pConfig->formatIn  == ma_format_f32) {
50416             return pConfig->formatIn;
50417         } else {
50418             return ma_format_f32;
50419         }
50420     }
50421 }
50422
50423 static ma_channel_converter_config ma_channel_converter_config_init_from_data_converter_config(const ma_data_converter_config* pConfig)
50424 {
50425     ma_channel_converter_config channelConverterConfig;
50426
50427     MA_ASSERT(pConfig != NULL);
50428
50429     channelConverterConfig = ma_channel_converter_config_init(ma_data_converter_config_get_mid_format(pConfig), pConfig->channelsIn, pConfig->pChannelMapIn, pConfig->channelsOut, pConfig->pChannelMapOut, pConfig->channelMixMode);
50430     channelConverterConfig.ppWeights = pConfig->ppChannelWeights;
50431
50432     return channelConverterConfig;
50433 }
50434
50435 static ma_resampler_config ma_resampler_config_init_from_data_converter_config(const ma_data_converter_config* pConfig)
50436 {
50437     ma_resampler_config resamplerConfig;
50438     ma_uint32 resamplerChannels;
50439
50440     MA_ASSERT(pConfig != NULL);
50441
50442     /* 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. */
50443     if (pConfig->channelsIn < pConfig->channelsOut) {
50444         resamplerChannels = pConfig->channelsIn;
50445     } else {
50446         resamplerChannels = pConfig->channelsOut;
50447     }
50448
50449     resamplerConfig = ma_resampler_config_init(ma_data_converter_config_get_mid_format(pConfig), resamplerChannels, pConfig->sampleRateIn, pConfig->sampleRateOut, pConfig->resampling.algorithm);
50450     resamplerConfig.linear           = pConfig->resampling.linear;
50451     resamplerConfig.pBackendVTable   = pConfig->resampling.pBackendVTable;
50452     resamplerConfig.pBackendUserData = pConfig->resampling.pBackendUserData;
50453
50454     return resamplerConfig;
50455 }
50456
50457 static ma_result ma_data_converter_get_heap_layout(const ma_data_converter_config* pConfig, ma_data_converter_heap_layout* pHeapLayout)
50458 {
50459     ma_result result;
50460
50461     MA_ASSERT(pHeapLayout != NULL);
50462
50463     MA_ZERO_OBJECT(pHeapLayout);
50464
50465     if (pConfig == NULL) {
50466         return MA_INVALID_ARGS;
50467     }
50468
50469     if (pConfig->channelsIn == 0 || pConfig->channelsOut == 0) {
50470         return MA_INVALID_ARGS;
50471     }
50472
50473     pHeapLayout->sizeInBytes = 0;
50474
50475     /* Channel converter. */
50476     pHeapLayout->channelConverterOffset = pHeapLayout->sizeInBytes;
50477     {
50478         size_t heapSizeInBytes;
50479         ma_channel_converter_config channelConverterConfig = ma_channel_converter_config_init_from_data_converter_config(pConfig);
50480
50481         result = ma_channel_converter_get_heap_size(&channelConverterConfig, &heapSizeInBytes);
50482         if (result != MA_SUCCESS) {
50483             return result;
50484         }
50485
50486         pHeapLayout->sizeInBytes += heapSizeInBytes;
50487     }
50488
50489     /* Resampler. */
50490     pHeapLayout->resamplerOffset = pHeapLayout->sizeInBytes;
50491     if (ma_data_converter_config_is_resampler_required(pConfig)) {
50492         size_t heapSizeInBytes;
50493         ma_resampler_config resamplerConfig = ma_resampler_config_init_from_data_converter_config(pConfig);
50494
50495         result = ma_resampler_get_heap_size(&resamplerConfig, &heapSizeInBytes);
50496         if (result != MA_SUCCESS) {
50497             return result;
50498         }
50499
50500         pHeapLayout->sizeInBytes += heapSizeInBytes;
50501     }
50502
50503     /* Make sure allocation size is aligned. */
50504     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
50505
50506     return MA_SUCCESS;
50507 }
50508
50509 MA_API ma_result ma_data_converter_get_heap_size(const ma_data_converter_config* pConfig, size_t* pHeapSizeInBytes)
50510 {
50511     ma_result result;
50512     ma_data_converter_heap_layout heapLayout;
50513
50514     if (pHeapSizeInBytes == NULL) {
50515         return MA_INVALID_ARGS;
50516     }
50517
50518     *pHeapSizeInBytes = 0;
50519
50520     result = ma_data_converter_get_heap_layout(pConfig, &heapLayout);
50521     if (result != MA_SUCCESS) {
50522         return result;
50523     }
50524
50525     *pHeapSizeInBytes = heapLayout.sizeInBytes;
50526
50527     return MA_SUCCESS;
50528 }
50529
50530 MA_API ma_result ma_data_converter_init_preallocated(const ma_data_converter_config* pConfig, void* pHeap, ma_data_converter* pConverter)
50531 {
50532     ma_result result;
50533     ma_data_converter_heap_layout heapLayout;
50534     ma_format midFormat;
50535     ma_bool32 isResamplingRequired;
50536
50537     if (pConverter == NULL) {
50538         return MA_INVALID_ARGS;
50539     }
50540
50541     MA_ZERO_OBJECT(pConverter);
50542
50543     result = ma_data_converter_get_heap_layout(pConfig, &heapLayout);
50544     if (result != MA_SUCCESS) {
50545         return result;
50546     }
50547
50548     pConverter->_pHeap = pHeap;
50549     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
50550
50551     pConverter->formatIn      = pConfig->formatIn;
50552     pConverter->formatOut     = pConfig->formatOut;
50553     pConverter->channelsIn    = pConfig->channelsIn;
50554     pConverter->channelsOut   = pConfig->channelsOut;
50555     pConverter->sampleRateIn  = pConfig->sampleRateIn;
50556     pConverter->sampleRateOut = pConfig->sampleRateOut;
50557     pConverter->ditherMode    = pConfig->ditherMode;
50558
50559     /*
50560     Determine if resampling is required. We need to do this so we can determine an appropriate
50561     mid format to use. If resampling is required, the mid format must be ma_format_f32 since
50562     that is the only one that is guaranteed to supported by custom resampling backends.
50563     */
50564     isResamplingRequired = ma_data_converter_config_is_resampler_required(pConfig);
50565     midFormat = ma_data_converter_config_get_mid_format(pConfig);
50566
50567
50568     /* Channel converter. We always initialize this, but we check if it configures itself as a passthrough to determine whether or not it's needed. */
50569     {
50570         ma_channel_converter_config channelConverterConfig = ma_channel_converter_config_init_from_data_converter_config(pConfig);
50571
50572         result = ma_channel_converter_init_preallocated(&channelConverterConfig, ma_offset_ptr(pHeap, heapLayout.channelConverterOffset), &pConverter->channelConverter);
50573         if (result != MA_SUCCESS) {
50574             return result;
50575         }
50576
50577         /* If the channel converter is not a passthrough we need to enable it. Otherwise we can skip it. */
50578         if (pConverter->channelConverter.conversionPath != ma_channel_conversion_path_passthrough) {
50579             pConverter->hasChannelConverter = MA_TRUE;
50580         }
50581     }
50582
50583
50584     /* Resampler. */
50585     if (isResamplingRequired) {
50586         ma_resampler_config resamplerConfig = ma_resampler_config_init_from_data_converter_config(pConfig);
50587
50588         result = ma_resampler_init_preallocated(&resamplerConfig, ma_offset_ptr(pHeap, heapLayout.resamplerOffset), &pConverter->resampler);
50589         if (result != MA_SUCCESS) {
50590             return result;
50591         }
50592
50593         pConverter->hasResampler = MA_TRUE;
50594     }
50595
50596
50597     /* We can simplify pre- and post-format conversion if we have neither channel conversion nor resampling. */
50598     if (pConverter->hasChannelConverter == MA_FALSE && pConverter->hasResampler == MA_FALSE) {
50599         /* We have neither channel conversion nor resampling so we'll only need one of pre- or post-format conversion, or none if the input and output formats are the same. */
50600         if (pConverter->formatIn == pConverter->formatOut) {
50601             /* The formats are the same so we can just pass through. */
50602             pConverter->hasPreFormatConversion  = MA_FALSE;
50603             pConverter->hasPostFormatConversion = MA_FALSE;
50604         } else {
50605             /* The formats are different so we need to do either pre- or post-format conversion. It doesn't matter which. */
50606             pConverter->hasPreFormatConversion  = MA_FALSE;
50607             pConverter->hasPostFormatConversion = MA_TRUE;
50608         }
50609     } else {
50610         /* We have a channel converter and/or resampler so we'll need channel conversion based on the mid format. */
50611         if (pConverter->formatIn != midFormat) {
50612             pConverter->hasPreFormatConversion  = MA_TRUE;
50613         }
50614         if (pConverter->formatOut != midFormat) {
50615             pConverter->hasPostFormatConversion = MA_TRUE;
50616         }
50617     }
50618
50619     /* We can enable passthrough optimizations if applicable. Note that we'll only be able to do this if the sample rate is static. */
50620     if (pConverter->hasPreFormatConversion  == MA_FALSE &&
50621         pConverter->hasPostFormatConversion == MA_FALSE &&
50622         pConverter->hasChannelConverter     == MA_FALSE &&
50623         pConverter->hasResampler            == MA_FALSE) {
50624         pConverter->isPassthrough = MA_TRUE;
50625     }
50626
50627
50628     /* We now need to determine our execution path. */
50629     if (pConverter->isPassthrough) {
50630         pConverter->executionPath = ma_data_converter_execution_path_passthrough;
50631     } else {
50632         if (pConverter->channelsIn < pConverter->channelsOut) {
50633             /* Do resampling first, if necessary. */
50634             MA_ASSERT(pConverter->hasChannelConverter == MA_TRUE);
50635
50636             if (pConverter->hasResampler) {
50637                 pConverter->executionPath = ma_data_converter_execution_path_resample_first;
50638             } else {
50639                 pConverter->executionPath = ma_data_converter_execution_path_channels_only;
50640             }
50641         } else {
50642             /* Do channel conversion first, if necessary. */
50643             if (pConverter->hasChannelConverter) {
50644                 if (pConverter->hasResampler) {
50645                     pConverter->executionPath = ma_data_converter_execution_path_channels_first;
50646                 } else {
50647                     pConverter->executionPath = ma_data_converter_execution_path_channels_only;
50648                 }
50649             } else {
50650                 /* Channel routing not required. */
50651                 if (pConverter->hasResampler) {
50652                     pConverter->executionPath = ma_data_converter_execution_path_resample_only;
50653                 } else {
50654                     pConverter->executionPath = ma_data_converter_execution_path_format_only;
50655                 }
50656             }
50657         }
50658     }
50659
50660     return MA_SUCCESS;
50661 }
50662
50663 MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_converter* pConverter)
50664 {
50665     ma_result result;
50666     size_t heapSizeInBytes;
50667     void* pHeap;
50668
50669     result = ma_data_converter_get_heap_size(pConfig, &heapSizeInBytes);
50670     if (result != MA_SUCCESS) {
50671         return result;
50672     }
50673
50674     if (heapSizeInBytes > 0) {
50675         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
50676         if (pHeap == NULL) {
50677             return MA_OUT_OF_MEMORY;
50678         }
50679     } else {
50680         pHeap = NULL;
50681     }
50682
50683     result = ma_data_converter_init_preallocated(pConfig, pHeap, pConverter);
50684     if (result != MA_SUCCESS) {
50685         ma_free(pHeap, pAllocationCallbacks);
50686         return result;
50687     }
50688
50689     pConverter->_ownsHeap = MA_TRUE;
50690     return MA_SUCCESS;
50691 }
50692
50693 MA_API void ma_data_converter_uninit(ma_data_converter* pConverter, const ma_allocation_callbacks* pAllocationCallbacks)
50694 {
50695     if (pConverter == NULL) {
50696         return;
50697     }
50698
50699     if (pConverter->hasResampler) {
50700         ma_resampler_uninit(&pConverter->resampler, pAllocationCallbacks);
50701     }
50702
50703     ma_channel_converter_uninit(&pConverter->channelConverter, pAllocationCallbacks);
50704
50705     if (pConverter->_ownsHeap) {
50706         ma_free(pConverter->_pHeap, pAllocationCallbacks);
50707     }
50708 }
50709
50710 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)
50711 {
50712     ma_uint64 frameCountIn;
50713     ma_uint64 frameCountOut;
50714     ma_uint64 frameCount;
50715
50716     MA_ASSERT(pConverter != NULL);
50717
50718     frameCountIn = 0;
50719     if (pFrameCountIn != NULL) {
50720         frameCountIn = *pFrameCountIn;
50721     }
50722
50723     frameCountOut = 0;
50724     if (pFrameCountOut != NULL) {
50725         frameCountOut = *pFrameCountOut;
50726     }
50727
50728     frameCount = ma_min(frameCountIn, frameCountOut);
50729
50730     if (pFramesOut != NULL) {
50731         if (pFramesIn != NULL) {
50732             ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut));
50733         } else {
50734             ma_zero_memory_64(pFramesOut,            frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut));
50735         }
50736     }
50737
50738     if (pFrameCountIn != NULL) {
50739         *pFrameCountIn = frameCount;
50740     }
50741     if (pFrameCountOut != NULL) {
50742         *pFrameCountOut = frameCount;
50743     }
50744
50745     return MA_SUCCESS;
50746 }
50747
50748 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)
50749 {
50750     ma_uint64 frameCountIn;
50751     ma_uint64 frameCountOut;
50752     ma_uint64 frameCount;
50753
50754     MA_ASSERT(pConverter != NULL);
50755
50756     frameCountIn = 0;
50757     if (pFrameCountIn != NULL) {
50758         frameCountIn = *pFrameCountIn;
50759     }
50760
50761     frameCountOut = 0;
50762     if (pFrameCountOut != NULL) {
50763         frameCountOut = *pFrameCountOut;
50764     }
50765
50766     frameCount = ma_min(frameCountIn, frameCountOut);
50767
50768     if (pFramesOut != NULL) {
50769         if (pFramesIn != NULL) {
50770             ma_convert_pcm_frames_format(pFramesOut, pConverter->formatOut, pFramesIn, pConverter->formatIn, frameCount, pConverter->channelsIn, pConverter->ditherMode);
50771         } else {
50772             ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut));
50773         }
50774     }
50775
50776     if (pFrameCountIn != NULL) {
50777         *pFrameCountIn = frameCount;
50778     }
50779     if (pFrameCountOut != NULL) {
50780         *pFrameCountOut = frameCount;
50781     }
50782
50783     return MA_SUCCESS;
50784 }
50785
50786
50787 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)
50788 {
50789     ma_result result = MA_SUCCESS;
50790     ma_uint64 frameCountIn;
50791     ma_uint64 frameCountOut;
50792     ma_uint64 framesProcessedIn;
50793     ma_uint64 framesProcessedOut;
50794
50795     MA_ASSERT(pConverter != NULL);
50796
50797     frameCountIn = 0;
50798     if (pFrameCountIn != NULL) {
50799         frameCountIn = *pFrameCountIn;
50800     }
50801
50802     frameCountOut = 0;
50803     if (pFrameCountOut != NULL) {
50804         frameCountOut = *pFrameCountOut;
50805     }
50806
50807     framesProcessedIn  = 0;
50808     framesProcessedOut = 0;
50809
50810     while (framesProcessedOut < frameCountOut) {
50811         ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
50812         const ma_uint32 tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels);
50813         const void* pFramesInThisIteration;
50814         /* */ void* pFramesOutThisIteration;
50815         ma_uint64 frameCountInThisIteration;
50816         ma_uint64 frameCountOutThisIteration;
50817
50818         if (pFramesIn != NULL) {
50819             pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn));
50820         } else {
50821             pFramesInThisIteration = NULL;
50822         }
50823
50824         if (pFramesOut != NULL) {
50825             pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut));
50826         } else {
50827             pFramesOutThisIteration = NULL;
50828         }
50829
50830         /* Do a pre format conversion if necessary. */
50831         if (pConverter->hasPreFormatConversion) {
50832             ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
50833             const ma_uint32 tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels);
50834
50835             frameCountInThisIteration  = (frameCountIn - framesProcessedIn);
50836             if (frameCountInThisIteration > tempBufferInCap) {
50837                 frameCountInThisIteration = tempBufferInCap;
50838             }
50839
50840             if (pConverter->hasPostFormatConversion) {
50841                if (frameCountInThisIteration > tempBufferOutCap) {
50842                    frameCountInThisIteration = tempBufferOutCap;
50843                }
50844             }
50845
50846             if (pFramesInThisIteration != NULL) {
50847                 ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.format, pFramesInThisIteration, pConverter->formatIn, frameCountInThisIteration, pConverter->channelsIn, pConverter->ditherMode);
50848             } else {
50849                 MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn));
50850             }
50851
50852             frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
50853
50854             if (pConverter->hasPostFormatConversion) {
50855                 /* Both input and output conversion required. Output to the temp buffer. */
50856                 if (frameCountOutThisIteration > tempBufferOutCap) {
50857                     frameCountOutThisIteration = tempBufferOutCap;
50858                 }
50859
50860                 result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferIn, &frameCountInThisIteration, pTempBufferOut, &frameCountOutThisIteration);
50861             } else {
50862                 /* Only pre-format required. Output straight to the output buffer. */
50863                 result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferIn, &frameCountInThisIteration, pFramesOutThisIteration, &frameCountOutThisIteration);
50864             }
50865
50866             if (result != MA_SUCCESS) {
50867                 break;
50868             }
50869         } else {
50870             /* No pre-format required. Just read straight from the input buffer. */
50871             MA_ASSERT(pConverter->hasPostFormatConversion == MA_TRUE);
50872
50873             frameCountInThisIteration  = (frameCountIn  - framesProcessedIn);
50874             frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
50875             if (frameCountOutThisIteration > tempBufferOutCap) {
50876                 frameCountOutThisIteration = tempBufferOutCap;
50877             }
50878
50879             result = ma_resampler_process_pcm_frames(&pConverter->resampler, pFramesInThisIteration, &frameCountInThisIteration, pTempBufferOut, &frameCountOutThisIteration);
50880             if (result != MA_SUCCESS) {
50881                 break;
50882             }
50883         }
50884
50885         /* If we are doing a post format conversion we need to do that now. */
50886         if (pConverter->hasPostFormatConversion) {
50887             if (pFramesOutThisIteration != NULL) {
50888                 ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->formatOut, pTempBufferOut, pConverter->resampler.format, frameCountOutThisIteration, pConverter->resampler.channels, pConverter->ditherMode);
50889             }
50890         }
50891
50892         framesProcessedIn  += frameCountInThisIteration;
50893         framesProcessedOut += frameCountOutThisIteration;
50894
50895         MA_ASSERT(framesProcessedIn  <= frameCountIn);
50896         MA_ASSERT(framesProcessedOut <= frameCountOut);
50897
50898         if (frameCountOutThisIteration == 0) {
50899             break;  /* Consumed all of our input data. */
50900         }
50901     }
50902
50903     if (pFrameCountIn != NULL) {
50904         *pFrameCountIn = framesProcessedIn;
50905     }
50906     if (pFrameCountOut != NULL) {
50907         *pFrameCountOut = framesProcessedOut;
50908     }
50909
50910     return result;
50911 }
50912
50913 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)
50914 {
50915     MA_ASSERT(pConverter != NULL);
50916
50917     if (pConverter->hasPreFormatConversion == MA_FALSE && pConverter->hasPostFormatConversion == MA_FALSE) {
50918         /* Neither pre- nor post-format required. This is simple case where only resampling is required. */
50919         return ma_resampler_process_pcm_frames(&pConverter->resampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
50920     } else {
50921         /* Format conversion required. */
50922         return ma_data_converter_process_pcm_frames__resample_with_format_conversion(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
50923     }
50924 }
50925
50926 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)
50927 {
50928     ma_result result;
50929     ma_uint64 frameCountIn;
50930     ma_uint64 frameCountOut;
50931     ma_uint64 frameCount;
50932
50933     MA_ASSERT(pConverter != NULL);
50934
50935     frameCountIn = 0;
50936     if (pFrameCountIn != NULL) {
50937         frameCountIn = *pFrameCountIn;
50938     }
50939
50940     frameCountOut = 0;
50941     if (pFrameCountOut != NULL) {
50942         frameCountOut = *pFrameCountOut;
50943     }
50944
50945     frameCount = ma_min(frameCountIn, frameCountOut);
50946
50947     if (pConverter->hasPreFormatConversion == MA_FALSE && pConverter->hasPostFormatConversion == MA_FALSE) {
50948         /* No format conversion required. */
50949         result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pFramesOut, pFramesIn, frameCount);
50950         if (result != MA_SUCCESS) {
50951             return result;
50952         }
50953     } else {
50954         /* Format conversion required. */
50955         ma_uint64 framesProcessed = 0;
50956
50957         while (framesProcessed < frameCount) {
50958             ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
50959             const ma_uint32 tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut);
50960             const void* pFramesInThisIteration;
50961             /* */ void* pFramesOutThisIteration;
50962             ma_uint64 frameCountThisIteration;
50963
50964             if (pFramesIn != NULL) {
50965                 pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessed * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn));
50966             } else {
50967                 pFramesInThisIteration = NULL;
50968             }
50969
50970             if (pFramesOut != NULL) {
50971                 pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessed * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut));
50972             } else {
50973                 pFramesOutThisIteration = NULL;
50974             }
50975
50976             /* Do a pre format conversion if necessary. */
50977             if (pConverter->hasPreFormatConversion) {
50978                 ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
50979                 const ma_uint32 tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsIn);
50980
50981                 frameCountThisIteration = (frameCount - framesProcessed);
50982                 if (frameCountThisIteration > tempBufferInCap) {
50983                     frameCountThisIteration = tempBufferInCap;
50984                 }
50985
50986                 if (pConverter->hasPostFormatConversion) {
50987                     if (frameCountThisIteration > tempBufferOutCap) {
50988                         frameCountThisIteration = tempBufferOutCap;
50989                     }
50990                 }
50991
50992                 if (pFramesInThisIteration != NULL) {
50993                     ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pFramesInThisIteration, pConverter->formatIn, frameCountThisIteration, pConverter->channelsIn, pConverter->ditherMode);
50994                 } else {
50995                     MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn));
50996                 }
50997
50998                 if (pConverter->hasPostFormatConversion) {
50999                     /* Both input and output conversion required. Output to the temp buffer. */
51000                     result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferOut, pTempBufferIn, frameCountThisIteration);
51001                 } else {
51002                     /* Only pre-format required. Output straight to the output buffer. */
51003                     result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pFramesOutThisIteration, pTempBufferIn, frameCountThisIteration);
51004                 }
51005
51006                 if (result != MA_SUCCESS) {
51007                     break;
51008                 }
51009             } else {
51010                 /* No pre-format required. Just read straight from the input buffer. */
51011                 MA_ASSERT(pConverter->hasPostFormatConversion == MA_TRUE);
51012
51013                 frameCountThisIteration = (frameCount - framesProcessed);
51014                 if (frameCountThisIteration > tempBufferOutCap) {
51015                     frameCountThisIteration = tempBufferOutCap;
51016                 }
51017
51018                 result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferOut, pFramesInThisIteration, frameCountThisIteration);
51019                 if (result != MA_SUCCESS) {
51020                     break;
51021                 }
51022             }
51023
51024             /* If we are doing a post format conversion we need to do that now. */
51025             if (pConverter->hasPostFormatConversion) {
51026                 if (pFramesOutThisIteration != NULL) {
51027                     ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->formatOut, pTempBufferOut, pConverter->channelConverter.format, frameCountThisIteration, pConverter->channelConverter.channelsOut, pConverter->ditherMode);
51028                 }
51029             }
51030
51031             framesProcessed += frameCountThisIteration;
51032         }
51033     }
51034
51035     if (pFrameCountIn != NULL) {
51036         *pFrameCountIn = frameCount;
51037     }
51038     if (pFrameCountOut != NULL) {
51039         *pFrameCountOut = frameCount;
51040     }
51041
51042     return MA_SUCCESS;
51043 }
51044
51045 static ma_result ma_data_converter_process_pcm_frames__resample_first(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
51046 {
51047     ma_result result;
51048     ma_uint64 frameCountIn;
51049     ma_uint64 frameCountOut;
51050     ma_uint64 framesProcessedIn;
51051     ma_uint64 framesProcessedOut;
51052     ma_uint8  pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];   /* In resampler format. */
51053     ma_uint64 tempBufferInCap;
51054     ma_uint8  pTempBufferMid[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In resampler format, channel converter input format. */
51055     ma_uint64 tempBufferMidCap;
51056     ma_uint8  pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In channel converter output format. */
51057     ma_uint64 tempBufferOutCap;
51058
51059     MA_ASSERT(pConverter != NULL);
51060     MA_ASSERT(pConverter->resampler.format   == pConverter->channelConverter.format);
51061     MA_ASSERT(pConverter->resampler.channels == pConverter->channelConverter.channelsIn);
51062     MA_ASSERT(pConverter->resampler.channels <  pConverter->channelConverter.channelsOut);
51063
51064     frameCountIn = 0;
51065     if (pFrameCountIn != NULL) {
51066         frameCountIn = *pFrameCountIn;
51067     }
51068
51069     frameCountOut = 0;
51070     if (pFrameCountOut != NULL) {
51071         frameCountOut = *pFrameCountOut;
51072     }
51073
51074     framesProcessedIn  = 0;
51075     framesProcessedOut = 0;
51076
51077     tempBufferInCap  = sizeof(pTempBufferIn)  / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels);
51078     tempBufferMidCap = sizeof(pTempBufferIn)  / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels);
51079     tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut);
51080
51081     while (framesProcessedOut < frameCountOut) {
51082         ma_uint64 frameCountInThisIteration;
51083         ma_uint64 frameCountOutThisIteration;
51084         const void* pRunningFramesIn = NULL;
51085         void* pRunningFramesOut = NULL;
51086         const void* pResampleBufferIn;
51087         void* pChannelsBufferOut;
51088
51089         if (pFramesIn != NULL) {
51090             pRunningFramesIn  = ma_offset_ptr(pFramesIn,  framesProcessedIn  * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn));
51091         }
51092         if (pFramesOut != NULL) {
51093             pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut));
51094         }
51095
51096         /* Run input data through the resampler and output it to the temporary buffer. */
51097         frameCountInThisIteration = (frameCountIn - framesProcessedIn);
51098
51099         if (pConverter->hasPreFormatConversion) {
51100             if (frameCountInThisIteration > tempBufferInCap) {
51101                 frameCountInThisIteration = tempBufferInCap;
51102             }
51103         }
51104
51105         frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
51106         if (frameCountOutThisIteration > tempBufferMidCap) {
51107             frameCountOutThisIteration = tempBufferMidCap;
51108         }
51109
51110         /* We can't read more frames than can fit in the output buffer. */
51111         if (pConverter->hasPostFormatConversion) {
51112             if (frameCountOutThisIteration > tempBufferOutCap) {
51113                 frameCountOutThisIteration = tempBufferOutCap;
51114             }
51115         }
51116
51117         /* 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. */
51118
51119         /*
51120         We need to try to predict how many input frames will be required for the resampler. If the
51121         resampler can tell us, we'll use that. Otherwise we'll need to make a best guess. The further
51122         off we are from this, the more wasted format conversions we'll end up doing.
51123         */
51124         #if 1
51125         {
51126             ma_uint64 requiredInputFrameCount;
51127
51128             result = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration, &requiredInputFrameCount);
51129             if (result != MA_SUCCESS) {
51130                 /* Fall back to a best guess. */
51131                 requiredInputFrameCount = (frameCountOutThisIteration * pConverter->resampler.sampleRateIn) / pConverter->resampler.sampleRateOut;
51132             }
51133
51134             if (frameCountInThisIteration > requiredInputFrameCount) {
51135                 frameCountInThisIteration = requiredInputFrameCount;
51136             }
51137         }
51138         #endif
51139
51140         if (pConverter->hasPreFormatConversion) {
51141             if (pFramesIn != NULL) {
51142                 ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.format, pRunningFramesIn, pConverter->formatIn, frameCountInThisIteration, pConverter->channelsIn, pConverter->ditherMode);
51143                 pResampleBufferIn = pTempBufferIn;
51144             } else {
51145                 pResampleBufferIn = NULL;
51146             }
51147         } else {
51148             pResampleBufferIn = pRunningFramesIn;
51149         }
51150
51151         result = ma_resampler_process_pcm_frames(&pConverter->resampler, pResampleBufferIn, &frameCountInThisIteration, pTempBufferMid, &frameCountOutThisIteration);
51152         if (result != MA_SUCCESS) {
51153             return result;
51154         }
51155
51156
51157         /*
51158         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
51159         this part if we have an output buffer.
51160         */
51161         if (pFramesOut != NULL) {
51162             if (pConverter->hasPostFormatConversion) {
51163                 pChannelsBufferOut = pTempBufferOut;
51164             } else {
51165                 pChannelsBufferOut = pRunningFramesOut;
51166             }
51167
51168             result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pChannelsBufferOut, pTempBufferMid, frameCountOutThisIteration);
51169             if (result != MA_SUCCESS) {
51170                 return result;
51171             }
51172
51173             /* Finally we do post format conversion. */
51174             if (pConverter->hasPostFormatConversion) {
51175                 ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->formatOut, pChannelsBufferOut, pConverter->channelConverter.format, frameCountOutThisIteration, pConverter->channelConverter.channelsOut, pConverter->ditherMode);
51176             }
51177         }
51178
51179
51180         framesProcessedIn  += frameCountInThisIteration;
51181         framesProcessedOut += frameCountOutThisIteration;
51182
51183         MA_ASSERT(framesProcessedIn  <= frameCountIn);
51184         MA_ASSERT(framesProcessedOut <= frameCountOut);
51185
51186         if (frameCountOutThisIteration == 0) {
51187             break;  /* Consumed all of our input data. */
51188         }
51189     }
51190
51191     if (pFrameCountIn != NULL) {
51192         *pFrameCountIn = framesProcessedIn;
51193     }
51194     if (pFrameCountOut != NULL) {
51195         *pFrameCountOut = framesProcessedOut;
51196     }
51197
51198     return MA_SUCCESS;
51199 }
51200
51201 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)
51202 {
51203     ma_result result;
51204     ma_uint64 frameCountIn;
51205     ma_uint64 frameCountOut;
51206     ma_uint64 framesProcessedIn;
51207     ma_uint64 framesProcessedOut;
51208     ma_uint8  pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];   /* In resampler format. */
51209     ma_uint64 tempBufferInCap;
51210     ma_uint8  pTempBufferMid[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In resampler format, channel converter input format. */
51211     ma_uint64 tempBufferMidCap;
51212     ma_uint8  pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In channel converter output format. */
51213     ma_uint64 tempBufferOutCap;
51214
51215     MA_ASSERT(pConverter != NULL);
51216     MA_ASSERT(pConverter->resampler.format   == pConverter->channelConverter.format);
51217     MA_ASSERT(pConverter->resampler.channels == pConverter->channelConverter.channelsOut);
51218     MA_ASSERT(pConverter->resampler.channels <  pConverter->channelConverter.channelsIn);
51219
51220     frameCountIn = 0;
51221     if (pFrameCountIn != NULL) {
51222         frameCountIn = *pFrameCountIn;
51223     }
51224
51225     frameCountOut = 0;
51226     if (pFrameCountOut != NULL) {
51227         frameCountOut = *pFrameCountOut;
51228     }
51229
51230     framesProcessedIn  = 0;
51231     framesProcessedOut = 0;
51232
51233     tempBufferInCap  = sizeof(pTempBufferIn)  / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsIn);
51234     tempBufferMidCap = sizeof(pTempBufferIn)  / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut);
51235     tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.format, pConverter->resampler.channels);
51236
51237     while (framesProcessedOut < frameCountOut) {
51238         ma_uint64 frameCountInThisIteration;
51239         ma_uint64 frameCountOutThisIteration;
51240         const void* pRunningFramesIn = NULL;
51241         void* pRunningFramesOut = NULL;
51242         const void* pChannelsBufferIn;
51243         void* pResampleBufferOut;
51244
51245         if (pFramesIn != NULL) {
51246             pRunningFramesIn  = ma_offset_ptr(pFramesIn,  framesProcessedIn  * ma_get_bytes_per_frame(pConverter->formatIn, pConverter->channelsIn));
51247         }
51248         if (pFramesOut != NULL) {
51249             pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->formatOut, pConverter->channelsOut));
51250         }
51251
51252         /*
51253         Before doing any processing we need to determine how many frames we should try processing
51254         this iteration, for both input and output. The resampler requires us to perform format and
51255         channel conversion before passing any data into it. If we get our input count wrong, we'll
51256         end up peforming redundant pre-processing. This isn't the end of the world, but it does
51257         result in some inefficiencies proportionate to how far our estimates are off.
51258
51259         If the resampler has a means to calculate exactly how much we'll need, we'll use that.
51260         Otherwise we'll make a best guess. In order to do this, we'll need to calculate the output
51261         frame count first.
51262         */
51263         frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
51264         if (frameCountOutThisIteration > tempBufferMidCap) {
51265             frameCountOutThisIteration = tempBufferMidCap;
51266         }
51267
51268         if (pConverter->hasPostFormatConversion) {
51269             if (frameCountOutThisIteration > tempBufferOutCap) {
51270                 frameCountOutThisIteration = tempBufferOutCap;
51271             }
51272         }
51273
51274         /* Now that we have the output frame count we can determine the input frame count. */
51275         frameCountInThisIteration = (frameCountIn - framesProcessedIn);
51276         if (pConverter->hasPreFormatConversion) {
51277             if (frameCountInThisIteration > tempBufferInCap) {
51278                 frameCountInThisIteration = tempBufferInCap;
51279             }
51280         }
51281
51282         if (frameCountInThisIteration > tempBufferMidCap) {
51283             frameCountInThisIteration = tempBufferMidCap;
51284         }
51285
51286         #if 1
51287         {
51288             ma_uint64 requiredInputFrameCount;
51289
51290             result = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration, &requiredInputFrameCount);
51291             if (result != MA_SUCCESS) {
51292                 /* Fall back to a best guess. */
51293                 requiredInputFrameCount = (frameCountOutThisIteration * pConverter->resampler.sampleRateIn) / pConverter->resampler.sampleRateOut;
51294             }
51295
51296             if (frameCountInThisIteration > requiredInputFrameCount) {
51297                 frameCountInThisIteration = requiredInputFrameCount;
51298             }
51299         }
51300         #endif
51301
51302
51303         /* Pre format conversion. */
51304         if (pConverter->hasPreFormatConversion) {
51305             if (pRunningFramesIn != NULL) {
51306                 ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pRunningFramesIn, pConverter->formatIn, frameCountInThisIteration, pConverter->channelsIn, pConverter->ditherMode);
51307                 pChannelsBufferIn = pTempBufferIn;
51308             } else {
51309                 pChannelsBufferIn = NULL;
51310             }
51311         } else {
51312             pChannelsBufferIn = pRunningFramesIn;
51313         }
51314
51315
51316         /* Channel conversion. */
51317         result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferMid, pChannelsBufferIn, frameCountInThisIteration);
51318         if (result != MA_SUCCESS) {
51319             return result;
51320         }
51321
51322
51323         /* Resampling. */
51324         if (pConverter->hasPostFormatConversion) {
51325             pResampleBufferOut = pTempBufferOut;
51326         } else {
51327             pResampleBufferOut = pRunningFramesOut;
51328         }
51329
51330         result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferMid, &frameCountInThisIteration, pResampleBufferOut, &frameCountOutThisIteration);
51331         if (result != MA_SUCCESS) {
51332             return result;
51333         }
51334
51335
51336         /* Post format conversion. */
51337         if (pConverter->hasPostFormatConversion) {
51338             if (pRunningFramesOut != NULL) {
51339                 ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->formatOut, pResampleBufferOut, pConverter->resampler.format, frameCountOutThisIteration, pConverter->channelsOut, pConverter->ditherMode);
51340             }
51341         }
51342
51343
51344         framesProcessedIn  += frameCountInThisIteration;
51345         framesProcessedOut += frameCountOutThisIteration;
51346
51347         MA_ASSERT(framesProcessedIn  <= frameCountIn);
51348         MA_ASSERT(framesProcessedOut <= frameCountOut);
51349
51350         if (frameCountOutThisIteration == 0) {
51351             break;  /* Consumed all of our input data. */
51352         }
51353     }
51354
51355     if (pFrameCountIn != NULL) {
51356         *pFrameCountIn = framesProcessedIn;
51357     }
51358     if (pFrameCountOut != NULL) {
51359         *pFrameCountOut = framesProcessedOut;
51360     }
51361
51362     return MA_SUCCESS;
51363 }
51364
51365 MA_API ma_result ma_data_converter_process_pcm_frames(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
51366 {
51367     if (pConverter == NULL) {
51368         return MA_INVALID_ARGS;
51369     }
51370
51371     switch (pConverter->executionPath)
51372     {
51373         case ma_data_converter_execution_path_passthrough:    return ma_data_converter_process_pcm_frames__passthrough(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
51374         case ma_data_converter_execution_path_format_only:    return ma_data_converter_process_pcm_frames__format_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
51375         case ma_data_converter_execution_path_channels_only:  return ma_data_converter_process_pcm_frames__channels_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
51376         case ma_data_converter_execution_path_resample_only:  return ma_data_converter_process_pcm_frames__resample_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
51377         case ma_data_converter_execution_path_resample_first: return ma_data_converter_process_pcm_frames__resample_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
51378         case ma_data_converter_execution_path_channels_first: return ma_data_converter_process_pcm_frames__channels_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
51379         default: return MA_INVALID_OPERATION;   /* Should never hit this. */
51380     }
51381 }
51382
51383 MA_API ma_result ma_data_converter_set_rate(ma_data_converter* pConverter, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
51384 {
51385     if (pConverter == NULL) {
51386         return MA_INVALID_ARGS;
51387     }
51388
51389     if (pConverter->hasResampler == MA_FALSE) {
51390         return MA_INVALID_OPERATION;    /* Dynamic resampling not enabled. */
51391     }
51392
51393     return ma_resampler_set_rate(&pConverter->resampler, sampleRateIn, sampleRateOut);
51394 }
51395
51396 MA_API ma_result ma_data_converter_set_rate_ratio(ma_data_converter* pConverter, float ratioInOut)
51397 {
51398     if (pConverter == NULL) {
51399         return MA_INVALID_ARGS;
51400     }
51401
51402     if (pConverter->hasResampler == MA_FALSE) {
51403         return MA_INVALID_OPERATION;    /* Dynamic resampling not enabled. */
51404     }
51405
51406     return ma_resampler_set_rate_ratio(&pConverter->resampler, ratioInOut);
51407 }
51408
51409 MA_API ma_uint64 ma_data_converter_get_input_latency(const ma_data_converter* pConverter)
51410 {
51411     if (pConverter == NULL) {
51412         return 0;
51413     }
51414
51415     if (pConverter->hasResampler) {
51416         return ma_resampler_get_input_latency(&pConverter->resampler);
51417     }
51418
51419     return 0;   /* No latency without a resampler. */
51420 }
51421
51422 MA_API ma_uint64 ma_data_converter_get_output_latency(const ma_data_converter* pConverter)
51423 {
51424     if (pConverter == NULL) {
51425         return 0;
51426     }
51427
51428     if (pConverter->hasResampler) {
51429         return ma_resampler_get_output_latency(&pConverter->resampler);
51430     }
51431
51432     return 0;   /* No latency without a resampler. */
51433 }
51434
51435 MA_API ma_result ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount, ma_uint64* pInputFrameCount)
51436 {
51437     if (pInputFrameCount == NULL) {
51438         return MA_INVALID_ARGS;
51439     }
51440
51441     *pInputFrameCount = 0;
51442
51443     if (pConverter == NULL) {
51444         return MA_INVALID_ARGS;
51445     }
51446
51447     if (pConverter->hasResampler) {
51448         return ma_resampler_get_required_input_frame_count(&pConverter->resampler, outputFrameCount, pInputFrameCount);
51449     } else {
51450         *pInputFrameCount = outputFrameCount;   /* 1:1 */
51451         return MA_SUCCESS;
51452     }
51453 }
51454
51455 MA_API ma_result ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount)
51456 {
51457     if (pOutputFrameCount == NULL) {
51458         return MA_INVALID_ARGS;
51459     }
51460
51461     *pOutputFrameCount = 0;
51462
51463     if (pConverter == NULL) {
51464         return MA_INVALID_ARGS;
51465     }
51466
51467     if (pConverter->hasResampler) {
51468         return ma_resampler_get_expected_output_frame_count(&pConverter->resampler, inputFrameCount, pOutputFrameCount);
51469     } else {
51470         *pOutputFrameCount = inputFrameCount;   /* 1:1 */
51471         return MA_SUCCESS;
51472     }
51473 }
51474
51475 MA_API ma_result ma_data_converter_get_input_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap)
51476 {
51477     if (pConverter == NULL || pChannelMap == NULL) {
51478         return MA_INVALID_ARGS;
51479     }
51480
51481     if (pConverter->hasChannelConverter) {
51482         ma_channel_converter_get_output_channel_map(&pConverter->channelConverter, pChannelMap, channelMapCap);
51483     } else {
51484         ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pConverter->channelsOut);
51485     }
51486
51487     return MA_SUCCESS;
51488 }
51489
51490 MA_API ma_result ma_data_converter_get_output_channel_map(const ma_data_converter* pConverter, ma_channel* pChannelMap, size_t channelMapCap)
51491 {
51492     if (pConverter == NULL || pChannelMap == NULL) {
51493         return MA_INVALID_ARGS;
51494     }
51495
51496     if (pConverter->hasChannelConverter) {
51497         ma_channel_converter_get_input_channel_map(&pConverter->channelConverter, pChannelMap, channelMapCap);
51498     } else {
51499         ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pConverter->channelsIn);
51500     }
51501
51502     return MA_SUCCESS;
51503 }
51504
51505
51506
51507 /**************************************************************************************************************************************************************
51508
51509 Channel Maps
51510
51511 **************************************************************************************************************************************************************/
51512 static ma_channel ma_channel_map_init_standard_channel(ma_standard_channel_map standardChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex);
51513
51514 MA_API ma_channel ma_channel_map_get_channel(const ma_channel* pChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex)
51515 {
51516     if (pChannelMap == NULL) {
51517         return ma_channel_map_init_standard_channel(ma_standard_channel_map_default, channelCount, channelIndex);
51518     } else {
51519         if (channelIndex >= channelCount) {
51520             return MA_CHANNEL_NONE;
51521         }
51522
51523         return pChannelMap[channelIndex];
51524     }
51525 }
51526
51527 MA_API void ma_channel_map_init_blank(ma_channel* pChannelMap, ma_uint32 channels)
51528 {
51529     if (pChannelMap == NULL) {
51530         return;
51531     }
51532
51533     MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channels);
51534 }
51535
51536
51537 static ma_channel ma_channel_map_init_standard_channel_microsoft(ma_uint32 channelCount, ma_uint32 channelIndex)
51538 {
51539     if (channelCount == 0 || channelIndex >= channelCount) {
51540         return MA_CHANNEL_NONE;
51541     }
51542
51543     /* This is the Microsoft channel map. Based off the speaker configurations mentioned here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-ksaudio_channel_config */
51544     switch (channelCount)
51545     {
51546         case 0: return MA_CHANNEL_NONE;
51547
51548         case 1:
51549         {
51550             return MA_CHANNEL_MONO;
51551         } break;
51552
51553         case 2:
51554         {
51555             switch (channelIndex) {
51556                 case 0: return MA_CHANNEL_FRONT_LEFT;
51557                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51558             }
51559         } break;
51560
51561         case 3: /* No defined, but best guess. */
51562         {
51563             switch (channelIndex) {
51564                 case 0: return MA_CHANNEL_FRONT_LEFT;
51565                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51566                 case 2: return MA_CHANNEL_FRONT_CENTER;
51567             }
51568         } break;
51569
51570         case 4:
51571         {
51572             switch (channelIndex) {
51573             #ifndef MA_USE_QUAD_MICROSOFT_CHANNEL_MAP
51574                 /* Surround. Using the Surround profile has the advantage of the 3rd channel (MA_CHANNEL_FRONT_CENTER) mapping nicely with higher channel counts. */
51575                 case 0: return MA_CHANNEL_FRONT_LEFT;
51576                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51577                 case 2: return MA_CHANNEL_FRONT_CENTER;
51578                 case 3: return MA_CHANNEL_BACK_CENTER;
51579             #else
51580                 /* Quad. */
51581                 case 0: return MA_CHANNEL_FRONT_LEFT;
51582                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51583                 case 2: return MA_CHANNEL_BACK_LEFT;
51584                 case 3: return MA_CHANNEL_BACK_RIGHT;
51585             #endif
51586             }
51587         } break;
51588
51589         case 5: /* Not defined, but best guess. */
51590         {
51591             switch (channelIndex) {
51592                 case 0: return MA_CHANNEL_FRONT_LEFT;
51593                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51594                 case 2: return MA_CHANNEL_FRONT_CENTER;
51595                 case 3: return MA_CHANNEL_BACK_LEFT;
51596                 case 4: return MA_CHANNEL_BACK_RIGHT;
51597             }
51598         } break;
51599
51600         case 6:
51601         {
51602             switch (channelIndex) {
51603                 case 0: return MA_CHANNEL_FRONT_LEFT;
51604                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51605                 case 2: return MA_CHANNEL_FRONT_CENTER;
51606                 case 3: return MA_CHANNEL_LFE;
51607                 case 4: return MA_CHANNEL_SIDE_LEFT;
51608                 case 5: return MA_CHANNEL_SIDE_RIGHT;
51609             }
51610         } break;
51611
51612         case 7: /* Not defined, but best guess. */
51613         {
51614             switch (channelIndex) {
51615                 case 0: return MA_CHANNEL_FRONT_LEFT;
51616                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51617                 case 2: return MA_CHANNEL_FRONT_CENTER;
51618                 case 3: return MA_CHANNEL_LFE;
51619                 case 4: return MA_CHANNEL_BACK_CENTER;
51620                 case 5: return MA_CHANNEL_SIDE_LEFT;
51621                 case 6: return MA_CHANNEL_SIDE_RIGHT;
51622             }
51623         } break;
51624
51625         case 8:
51626         default:
51627         {
51628             switch (channelIndex) {
51629                 case 0: return MA_CHANNEL_FRONT_LEFT;
51630                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51631                 case 2: return MA_CHANNEL_FRONT_CENTER;
51632                 case 3: return MA_CHANNEL_LFE;
51633                 case 4: return MA_CHANNEL_BACK_LEFT;
51634                 case 5: return MA_CHANNEL_BACK_RIGHT;
51635                 case 6: return MA_CHANNEL_SIDE_LEFT;
51636                 case 7: return MA_CHANNEL_SIDE_RIGHT;
51637             }
51638         } break;
51639     }
51640
51641     if (channelCount > 8) {
51642         if (channelIndex < 32) {    /* We have 32 AUX channels. */
51643             return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8));
51644         }
51645     }
51646
51647     /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */
51648     return MA_CHANNEL_NONE;
51649 }
51650
51651 static ma_channel ma_channel_map_init_standard_channel_alsa(ma_uint32 channelCount, ma_uint32 channelIndex)
51652 {
51653     switch (channelCount)
51654     {
51655         case 0: return MA_CHANNEL_NONE;
51656
51657         case 1:
51658         {
51659             return MA_CHANNEL_MONO;
51660         } break;
51661
51662         case 2:
51663         {
51664             switch (channelIndex) {
51665                 case 0: return MA_CHANNEL_FRONT_LEFT;
51666                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51667             }
51668         } break;
51669
51670         case 3:
51671         {
51672             switch (channelIndex) {
51673                 case 0: return MA_CHANNEL_FRONT_LEFT;
51674                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51675                 case 2: return MA_CHANNEL_FRONT_CENTER;
51676             }
51677         } break;
51678
51679         case 4:
51680         {
51681             switch (channelIndex) {
51682                 case 0: return MA_CHANNEL_FRONT_LEFT;
51683                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51684                 case 2: return MA_CHANNEL_BACK_LEFT;
51685                 case 3: return MA_CHANNEL_BACK_RIGHT;
51686             }
51687         } break;
51688
51689         case 5:
51690         {
51691             switch (channelIndex) {
51692                 case 0: return MA_CHANNEL_FRONT_LEFT;
51693                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51694                 case 2: return MA_CHANNEL_BACK_LEFT;
51695                 case 3: return MA_CHANNEL_BACK_RIGHT;
51696                 case 4: return MA_CHANNEL_FRONT_CENTER;
51697             }
51698         } break;
51699
51700         case 6:
51701         {
51702             switch (channelIndex) {
51703                 case 0: return MA_CHANNEL_FRONT_LEFT;
51704                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51705                 case 2: return MA_CHANNEL_BACK_LEFT;
51706                 case 3: return MA_CHANNEL_BACK_RIGHT;
51707                 case 4: return MA_CHANNEL_FRONT_CENTER;
51708                 case 5: return MA_CHANNEL_LFE;
51709             }
51710         } break;
51711
51712         case 7:
51713         {
51714             switch (channelIndex) {
51715                 case 0: return MA_CHANNEL_FRONT_LEFT;
51716                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51717                 case 2: return MA_CHANNEL_BACK_LEFT;
51718                 case 3: return MA_CHANNEL_BACK_RIGHT;
51719                 case 4: return MA_CHANNEL_FRONT_CENTER;
51720                 case 5: return MA_CHANNEL_LFE;
51721                 case 6: return MA_CHANNEL_BACK_CENTER;
51722             }
51723         } break;
51724
51725         case 8:
51726         default:
51727         {
51728             switch (channelIndex) {
51729                 case 0: return MA_CHANNEL_FRONT_LEFT;
51730                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51731                 case 2: return MA_CHANNEL_BACK_LEFT;
51732                 case 3: return MA_CHANNEL_BACK_RIGHT;
51733                 case 4: return MA_CHANNEL_FRONT_CENTER;
51734                 case 5: return MA_CHANNEL_LFE;
51735                 case 6: return MA_CHANNEL_SIDE_LEFT;
51736                 case 7: return MA_CHANNEL_SIDE_RIGHT;
51737             }
51738         } break;
51739     }
51740
51741     if (channelCount > 8) {
51742         if (channelIndex < 32) {    /* We have 32 AUX channels. */
51743             return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8));
51744         }
51745     }
51746
51747     /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */
51748     return MA_CHANNEL_NONE;
51749 }
51750
51751 static ma_channel ma_channel_map_init_standard_channel_rfc3551(ma_uint32 channelCount, ma_uint32 channelIndex)
51752 {
51753     switch (channelCount)
51754     {
51755         case 0: return MA_CHANNEL_NONE;
51756
51757         case 1:
51758         {
51759             return MA_CHANNEL_MONO;
51760         } break;
51761
51762         case 2:
51763         {
51764             switch (channelIndex) {
51765                 case 0: return MA_CHANNEL_FRONT_LEFT;
51766                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51767             }
51768         } break;
51769
51770         case 3:
51771         {
51772             switch (channelIndex) {
51773                 case 0: return MA_CHANNEL_FRONT_LEFT;
51774                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51775                 case 2: return MA_CHANNEL_FRONT_CENTER;
51776             }
51777         } break;
51778
51779         case 4:
51780         {
51781             switch (channelIndex) {
51782                 case 0: return MA_CHANNEL_FRONT_LEFT;
51783                 case 2: return MA_CHANNEL_FRONT_CENTER;
51784                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51785                 case 3: return MA_CHANNEL_BACK_CENTER;
51786             }
51787         } break;
51788
51789         case 5:
51790         {
51791             switch (channelIndex) {
51792                 case 0: return MA_CHANNEL_FRONT_LEFT;
51793                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51794                 case 2: return MA_CHANNEL_FRONT_CENTER;
51795                 case 3: return MA_CHANNEL_BACK_LEFT;
51796                 case 4: return MA_CHANNEL_BACK_RIGHT;
51797             }
51798         } break;
51799
51800         case 6:
51801         default:
51802         {
51803             switch (channelIndex) {
51804                 case 0: return MA_CHANNEL_FRONT_LEFT;
51805                 case 1: return MA_CHANNEL_SIDE_LEFT;
51806                 case 2: return MA_CHANNEL_FRONT_CENTER;
51807                 case 3: return MA_CHANNEL_FRONT_RIGHT;
51808                 case 4: return MA_CHANNEL_SIDE_RIGHT;
51809                 case 5: return MA_CHANNEL_BACK_CENTER;
51810             }
51811         } break;
51812     }
51813
51814     if (channelCount > 6) {
51815         if (channelIndex < 32) {    /* We have 32 AUX channels. */
51816             return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 6));
51817         }
51818     }
51819
51820     /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */
51821     return MA_CHANNEL_NONE;
51822 }
51823
51824 static ma_channel ma_channel_map_init_standard_channel_flac(ma_uint32 channelCount, ma_uint32 channelIndex)
51825 {
51826     switch (channelCount)
51827     {
51828         case 0: return MA_CHANNEL_NONE;
51829
51830         case 1:
51831         {
51832             return MA_CHANNEL_MONO;
51833         } break;
51834
51835         case 2:
51836         {
51837             switch (channelIndex) {
51838                 case 0: return MA_CHANNEL_FRONT_LEFT;
51839                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51840             }
51841         } break;
51842
51843         case 3:
51844         {
51845             switch (channelIndex) {
51846                 case 0: return MA_CHANNEL_FRONT_LEFT;
51847                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51848                 case 2: return MA_CHANNEL_FRONT_CENTER;
51849             }
51850         } break;
51851
51852         case 4:
51853         {
51854             switch (channelIndex) {
51855                 case 0: return MA_CHANNEL_FRONT_LEFT;
51856                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51857                 case 2: return MA_CHANNEL_BACK_LEFT;
51858                 case 3: return MA_CHANNEL_BACK_RIGHT;
51859             }
51860         } break;
51861
51862         case 5:
51863         {
51864             switch (channelIndex) {
51865                 case 0: return MA_CHANNEL_FRONT_LEFT;
51866                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51867                 case 2: return MA_CHANNEL_FRONT_CENTER;
51868                 case 3: return MA_CHANNEL_BACK_LEFT;
51869                 case 4: return MA_CHANNEL_BACK_RIGHT;
51870             }
51871         } break;
51872
51873         case 6:
51874         {
51875             switch (channelIndex) {
51876                 case 0: return MA_CHANNEL_FRONT_LEFT;
51877                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51878                 case 2: return MA_CHANNEL_FRONT_CENTER;
51879                 case 3: return MA_CHANNEL_LFE;
51880                 case 4: return MA_CHANNEL_BACK_LEFT;
51881                 case 5: return MA_CHANNEL_BACK_RIGHT;
51882             }
51883         } break;
51884
51885         case 7:
51886         {
51887             switch (channelIndex) {
51888                 case 0: return MA_CHANNEL_FRONT_LEFT;
51889                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51890                 case 2: return MA_CHANNEL_FRONT_CENTER;
51891                 case 3: return MA_CHANNEL_LFE;
51892                 case 4: return MA_CHANNEL_BACK_CENTER;
51893                 case 5: return MA_CHANNEL_SIDE_LEFT;
51894                 case 6: return MA_CHANNEL_SIDE_RIGHT;
51895             }
51896         } break;
51897
51898         case 8:
51899         default:
51900         {
51901             switch (channelIndex) {
51902                 case 0: return MA_CHANNEL_FRONT_LEFT;
51903                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51904                 case 2: return MA_CHANNEL_FRONT_CENTER;
51905                 case 3: return MA_CHANNEL_LFE;
51906                 case 4: return MA_CHANNEL_BACK_LEFT;
51907                 case 5: return MA_CHANNEL_BACK_RIGHT;
51908                 case 6: return MA_CHANNEL_SIDE_LEFT;
51909                 case 7: return MA_CHANNEL_SIDE_RIGHT;
51910             }
51911         } break;
51912     }
51913
51914     if (channelCount > 8) {
51915         if (channelIndex < 32) {    /* We have 32 AUX channels. */
51916             return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8));
51917         }
51918     }
51919
51920     /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */
51921     return MA_CHANNEL_NONE;
51922 }
51923
51924 static ma_channel ma_channel_map_init_standard_channel_vorbis(ma_uint32 channelCount, ma_uint32 channelIndex)
51925 {
51926     switch (channelCount)
51927     {
51928         case 0: return MA_CHANNEL_NONE;
51929
51930         case 1:
51931         {
51932             return MA_CHANNEL_MONO;
51933         } break;
51934
51935         case 2:
51936         {
51937             switch (channelIndex) {
51938                 case 0: return MA_CHANNEL_FRONT_LEFT;
51939                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51940             }
51941         } break;
51942
51943         case 3:
51944         {
51945             switch (channelIndex) {
51946                 case 0: return MA_CHANNEL_FRONT_LEFT;
51947                 case 1: return MA_CHANNEL_FRONT_CENTER;
51948                 case 2: return MA_CHANNEL_FRONT_RIGHT;
51949             }
51950         } break;
51951
51952         case 4:
51953         {
51954             switch (channelIndex) {
51955                 case 0: return MA_CHANNEL_FRONT_LEFT;
51956                 case 1: return MA_CHANNEL_FRONT_RIGHT;
51957                 case 2: return MA_CHANNEL_BACK_LEFT;
51958                 case 3: return MA_CHANNEL_BACK_RIGHT;
51959             }
51960         } break;
51961
51962         case 5:
51963         {
51964             switch (channelIndex) {
51965                 case 0: return MA_CHANNEL_FRONT_LEFT;
51966                 case 1: return MA_CHANNEL_FRONT_CENTER;
51967                 case 2: return MA_CHANNEL_FRONT_RIGHT;
51968                 case 3: return MA_CHANNEL_BACK_LEFT;
51969                 case 4: return MA_CHANNEL_BACK_RIGHT;
51970             }
51971         } break;
51972
51973         case 6:
51974         {
51975             switch (channelIndex) {
51976                 case 0: return MA_CHANNEL_FRONT_LEFT;
51977                 case 1: return MA_CHANNEL_FRONT_CENTER;
51978                 case 2: return MA_CHANNEL_FRONT_RIGHT;
51979                 case 3: return MA_CHANNEL_BACK_LEFT;
51980                 case 4: return MA_CHANNEL_BACK_RIGHT;
51981                 case 5: return MA_CHANNEL_LFE;
51982             }
51983         } break;
51984
51985         case 7:
51986         {
51987             switch (channelIndex) {
51988                 case 0: return MA_CHANNEL_FRONT_LEFT;
51989                 case 1: return MA_CHANNEL_FRONT_CENTER;
51990                 case 2: return MA_CHANNEL_FRONT_RIGHT;
51991                 case 3: return MA_CHANNEL_SIDE_LEFT;
51992                 case 4: return MA_CHANNEL_SIDE_RIGHT;
51993                 case 5: return MA_CHANNEL_BACK_CENTER;
51994                 case 6: return MA_CHANNEL_LFE;
51995             }
51996         } break;
51997
51998         case 8:
51999         default:
52000         {
52001             switch (channelIndex) {
52002                 case 0: return MA_CHANNEL_FRONT_LEFT;
52003                 case 1: return MA_CHANNEL_FRONT_CENTER;
52004                 case 2: return MA_CHANNEL_FRONT_RIGHT;
52005                 case 3: return MA_CHANNEL_SIDE_LEFT;
52006                 case 4: return MA_CHANNEL_SIDE_RIGHT;
52007                 case 5: return MA_CHANNEL_BACK_LEFT;
52008                 case 6: return MA_CHANNEL_BACK_RIGHT;
52009                 case 7: return MA_CHANNEL_LFE;
52010             }
52011         } break;
52012     }
52013
52014     if (channelCount > 8) {
52015         if (channelIndex < 32) {    /* We have 32 AUX channels. */
52016             return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8));
52017         }
52018     }
52019
52020     /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */
52021     return MA_CHANNEL_NONE;
52022 }
52023
52024 static ma_channel ma_channel_map_init_standard_channel_sound4(ma_uint32 channelCount, ma_uint32 channelIndex)
52025 {
52026     switch (channelCount)
52027     {
52028         case 0: return MA_CHANNEL_NONE;
52029
52030         case 1:
52031         {
52032             return MA_CHANNEL_MONO;
52033         } break;
52034
52035         case 2:
52036         {
52037             switch (channelIndex) {
52038                 case 0: return MA_CHANNEL_FRONT_LEFT;
52039                 case 1: return MA_CHANNEL_FRONT_RIGHT;
52040             }
52041         } break;
52042
52043         case 3:
52044         {
52045             switch (channelIndex) {
52046                 case 0: return MA_CHANNEL_FRONT_LEFT;
52047                 case 1: return MA_CHANNEL_FRONT_RIGHT;
52048                 case 2: return MA_CHANNEL_FRONT_CENTER;
52049             }
52050         } break;
52051
52052         case 4:
52053         {
52054             switch (channelIndex) {
52055                 case 0: return MA_CHANNEL_FRONT_LEFT;
52056                 case 1: return MA_CHANNEL_FRONT_RIGHT;
52057                 case 2: return MA_CHANNEL_BACK_LEFT;
52058                 case 3: return MA_CHANNEL_BACK_RIGHT;
52059             }
52060         } break;
52061
52062         case 5:
52063         {
52064             switch (channelIndex) {
52065                 case 0: return MA_CHANNEL_FRONT_LEFT;
52066                 case 1: return MA_CHANNEL_FRONT_RIGHT;
52067                 case 2: return MA_CHANNEL_FRONT_CENTER;
52068                 case 3: return MA_CHANNEL_BACK_LEFT;
52069                 case 4: return MA_CHANNEL_BACK_RIGHT;
52070             }
52071         } break;
52072
52073         case 6:
52074         {
52075             switch (channelIndex) {
52076                 case 0: return MA_CHANNEL_FRONT_LEFT;
52077                 case 1: return MA_CHANNEL_FRONT_CENTER;
52078                 case 2: return MA_CHANNEL_FRONT_RIGHT;
52079                 case 3: return MA_CHANNEL_BACK_LEFT;
52080                 case 4: return MA_CHANNEL_BACK_RIGHT;
52081                 case 5: return MA_CHANNEL_LFE;
52082             }
52083         } break;
52084
52085         case 7:
52086         {
52087             switch (channelIndex) {
52088                 case 0: return MA_CHANNEL_FRONT_LEFT;
52089                 case 1: return MA_CHANNEL_FRONT_CENTER;
52090                 case 2: return MA_CHANNEL_FRONT_RIGHT;
52091                 case 3: return MA_CHANNEL_SIDE_LEFT;
52092                 case 4: return MA_CHANNEL_SIDE_RIGHT;
52093                 case 5: return MA_CHANNEL_BACK_CENTER;
52094                 case 6: return MA_CHANNEL_LFE;
52095             }
52096         } break;
52097
52098         case 8:
52099         default:
52100         {
52101             switch (channelIndex) {
52102                 case 0: return MA_CHANNEL_FRONT_LEFT;
52103                 case 1: return MA_CHANNEL_FRONT_CENTER;
52104                 case 2: return MA_CHANNEL_FRONT_RIGHT;
52105                 case 3: return MA_CHANNEL_SIDE_LEFT;
52106                 case 4: return MA_CHANNEL_SIDE_RIGHT;
52107                 case 5: return MA_CHANNEL_BACK_LEFT;
52108                 case 6: return MA_CHANNEL_BACK_RIGHT;
52109                 case 7: return MA_CHANNEL_LFE;
52110             }
52111         } break;
52112     }
52113
52114     if (channelCount > 8) {
52115         if (channelIndex < 32) {    /* We have 32 AUX channels. */
52116             return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 8));
52117         }
52118     }
52119
52120     /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */
52121     return MA_CHANNEL_NONE;
52122 }
52123
52124 static ma_channel ma_channel_map_init_standard_channel_sndio(ma_uint32 channelCount, ma_uint32 channelIndex)
52125 {
52126     switch (channelCount)
52127     {
52128         case 0: return MA_CHANNEL_NONE;
52129
52130         case 1:
52131         {
52132             return MA_CHANNEL_MONO;
52133         } break;
52134
52135         case 2:
52136         {
52137             switch (channelIndex) {
52138                 case 0: return MA_CHANNEL_FRONT_LEFT;
52139                 case 1: return MA_CHANNEL_FRONT_RIGHT;
52140             }
52141         } break;
52142
52143         case 3: /* No defined, but best guess. */
52144         {
52145             switch (channelIndex) {
52146                 case 0: return MA_CHANNEL_FRONT_LEFT;
52147                 case 1: return MA_CHANNEL_FRONT_RIGHT;
52148                 case 2: return MA_CHANNEL_FRONT_CENTER;
52149             }
52150         } break;
52151
52152         case 4:
52153         {
52154             switch (channelIndex) {
52155                 case 0: return MA_CHANNEL_FRONT_LEFT;
52156                 case 1: return MA_CHANNEL_FRONT_RIGHT;
52157                 case 2: return MA_CHANNEL_BACK_LEFT;
52158                 case 3: return MA_CHANNEL_BACK_RIGHT;
52159             }
52160         } break;
52161
52162         case 5: /* Not defined, but best guess. */
52163         {
52164             switch (channelIndex) {
52165                 case 0: return MA_CHANNEL_FRONT_LEFT;
52166                 case 1: return MA_CHANNEL_FRONT_RIGHT;
52167                 case 2: return MA_CHANNEL_BACK_LEFT;
52168                 case 3: return MA_CHANNEL_BACK_RIGHT;
52169                 case 4: return MA_CHANNEL_FRONT_CENTER;
52170             }
52171         } break;
52172
52173         case 6:
52174         default:
52175         {
52176             switch (channelIndex) {
52177                 case 0: return MA_CHANNEL_FRONT_LEFT;
52178                 case 1: return MA_CHANNEL_FRONT_RIGHT;
52179                 case 2: return MA_CHANNEL_BACK_LEFT;
52180                 case 3: return MA_CHANNEL_BACK_RIGHT;
52181                 case 4: return MA_CHANNEL_FRONT_CENTER;
52182                 case 5: return MA_CHANNEL_LFE;
52183             }
52184         } break;
52185     }
52186
52187     if (channelCount > 6) {
52188         if (channelIndex < 32) {    /* We have 32 AUX channels. */
52189             return (ma_channel)(MA_CHANNEL_AUX_0 + (channelIndex - 6));
52190         }
52191     }
52192
52193     /* Getting here means we don't know how to map the channel position so just return MA_CHANNEL_NONE. */
52194     return MA_CHANNEL_NONE;
52195 }
52196
52197
52198 static ma_channel ma_channel_map_init_standard_channel(ma_standard_channel_map standardChannelMap, ma_uint32 channelCount, ma_uint32 channelIndex)
52199 {
52200     if (channelCount == 0 || channelIndex >= channelCount) {
52201         return MA_CHANNEL_NONE;
52202     }
52203
52204     switch (standardChannelMap)
52205     {
52206         case ma_standard_channel_map_alsa:
52207         {
52208             return ma_channel_map_init_standard_channel_alsa(channelCount, channelIndex);
52209         } break;
52210
52211         case ma_standard_channel_map_rfc3551:
52212         {
52213             return ma_channel_map_init_standard_channel_rfc3551(channelCount, channelIndex);
52214         } break;
52215
52216         case ma_standard_channel_map_flac:
52217         {
52218             return ma_channel_map_init_standard_channel_flac(channelCount, channelIndex);
52219         } break;
52220
52221         case ma_standard_channel_map_vorbis:
52222         {
52223             return ma_channel_map_init_standard_channel_vorbis(channelCount, channelIndex);
52224         } break;
52225
52226         case ma_standard_channel_map_sound4:
52227         {
52228             return ma_channel_map_init_standard_channel_sound4(channelCount, channelIndex);
52229         } break;
52230
52231         case ma_standard_channel_map_sndio:
52232         {
52233             return ma_channel_map_init_standard_channel_sndio(channelCount, channelIndex);
52234         } break;
52235
52236         case ma_standard_channel_map_microsoft: /* Also default. */
52237         /*case ma_standard_channel_map_default;*/
52238         default:
52239         {
52240             return ma_channel_map_init_standard_channel_microsoft(channelCount, channelIndex);
52241         } break;
52242     }
52243 }
52244
52245 MA_API void ma_channel_map_init_standard(ma_standard_channel_map standardChannelMap, ma_channel* pChannelMap, size_t channelMapCap, ma_uint32 channels)
52246 {
52247     ma_uint32 iChannel;
52248
52249     if (pChannelMap == NULL || channelMapCap == 0 || channels == 0) {
52250         return;
52251     }
52252
52253     for (iChannel = 0; iChannel < channels; iChannel += 1) {
52254         if (channelMapCap == 0) {
52255             break;  /* Ran out of room. */
52256         }
52257
52258         pChannelMap[0] = ma_channel_map_init_standard_channel(standardChannelMap, channels, iChannel);
52259         pChannelMap   += 1;
52260         channelMapCap -= 1;
52261     }
52262 }
52263
52264 MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels)
52265 {
52266     if (pOut != NULL && pIn != NULL && channels > 0) {
52267         MA_COPY_MEMORY(pOut, pIn, sizeof(*pOut) * channels);
52268     }
52269 }
52270
52271 MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, size_t channelMapCapOut, const ma_channel* pIn, ma_uint32 channels)
52272 {
52273     if (pOut == NULL || channels == 0) {
52274         return;
52275     }
52276
52277     if (pIn != NULL) {
52278         ma_channel_map_copy(pOut, pIn, channels);
52279     } else {
52280         ma_channel_map_init_standard(ma_standard_channel_map_default, pOut, channelMapCapOut, channels);
52281     }
52282 }
52283
52284 MA_API ma_bool32 ma_channel_map_is_valid(const ma_channel* pChannelMap, ma_uint32 channels)
52285 {
52286     /* A channel count of 0 is invalid. */
52287     if (channels == 0) {
52288         return MA_FALSE;
52289     }
52290
52291     /* It does not make sense to have a mono channel when there is more than 1 channel. */
52292     if (channels > 1) {
52293         ma_uint32 iChannel;
52294         for (iChannel = 0; iChannel < channels; ++iChannel) {
52295             if (ma_channel_map_get_channel(pChannelMap, channels, iChannel) == MA_CHANNEL_MONO) {
52296                 return MA_FALSE;
52297             }
52298         }
52299     }
52300
52301     return MA_TRUE;
52302 }
52303
52304 MA_API ma_bool32 ma_channel_map_is_equal(const ma_channel* pChannelMapA, const ma_channel* pChannelMapB, ma_uint32 channels)
52305 {
52306     ma_uint32 iChannel;
52307
52308     if (pChannelMapA == pChannelMapB) {
52309         return MA_TRUE;
52310     }
52311
52312     for (iChannel = 0; iChannel < channels; ++iChannel) {
52313         if (ma_channel_map_get_channel(pChannelMapA, channels, iChannel) != ma_channel_map_get_channel(pChannelMapB, channels, iChannel)) {
52314             return MA_FALSE;
52315         }
52316     }
52317
52318     return MA_TRUE;
52319 }
52320
52321 MA_API ma_bool32 ma_channel_map_is_blank(const ma_channel* pChannelMap, ma_uint32 channels)
52322 {
52323     ma_uint32 iChannel;
52324
52325     /* A null channel map is equivalent to the default channel map. */
52326     if (pChannelMap == NULL) {
52327         return MA_FALSE;
52328     }
52329
52330     for (iChannel = 0; iChannel < channels; ++iChannel) {
52331         if (pChannelMap[iChannel] != MA_CHANNEL_NONE) {
52332             return MA_FALSE;
52333         }
52334     }
52335
52336     return MA_TRUE;
52337 }
52338
52339 MA_API ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel* pChannelMap, ma_channel channelPosition)
52340 {
52341     ma_uint32 iChannel;
52342
52343     for (iChannel = 0; iChannel < channels; ++iChannel) {
52344         if (ma_channel_map_get_channel(pChannelMap, channels, iChannel) == channelPosition) {
52345             return MA_TRUE;
52346         }
52347     }
52348
52349     return MA_FALSE;
52350 }
52351
52352
52353
52354 /**************************************************************************************************************************************************************
52355
52356 Conversion Helpers
52357
52358 **************************************************************************************************************************************************************/
52359 MA_API 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)
52360 {
52361     ma_data_converter_config config;
52362
52363     config = ma_data_converter_config_init(formatIn, formatOut, channelsIn, channelsOut, sampleRateIn, sampleRateOut);
52364     config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
52365
52366     return ma_convert_frames_ex(pOut, frameCountOut, pIn, frameCountIn, &config);
52367 }
52368
52369 MA_API ma_uint64 ma_convert_frames_ex(void* pOut, ma_uint64 frameCountOut, const void* pIn, ma_uint64 frameCountIn, const ma_data_converter_config* pConfig)
52370 {
52371     ma_result result;
52372     ma_data_converter converter;
52373
52374     if (frameCountIn == 0 || pConfig == NULL) {
52375         return 0;
52376     }
52377
52378     result = ma_data_converter_init(pConfig, NULL, &converter);
52379     if (result != MA_SUCCESS) {
52380         return 0;   /* Failed to initialize the data converter. */
52381     }
52382
52383     if (pOut == NULL) {
52384         result = ma_data_converter_get_expected_output_frame_count(&converter, frameCountIn, &frameCountOut);
52385         if (result != MA_SUCCESS) {
52386             if (result == MA_NOT_IMPLEMENTED) {
52387                 /* No way to calculate the number of frames, so we'll need to brute force it and loop. */
52388                 frameCountOut = 0;
52389
52390                 while (frameCountIn > 0) {
52391                     ma_uint64 framesProcessedIn  = frameCountIn;
52392                     ma_uint64 framesProcessedOut = 0xFFFFFFFF;
52393
52394                     result = ma_data_converter_process_pcm_frames(&converter, pIn, &framesProcessedIn, NULL, &framesProcessedOut);
52395                     if (result != MA_SUCCESS) {
52396                         break;
52397                     }
52398
52399                     frameCountIn  -= framesProcessedIn;
52400                 }
52401             }
52402         }
52403     } else {
52404         result = ma_data_converter_process_pcm_frames(&converter, pIn, &frameCountIn, pOut, &frameCountOut);
52405         if (result != MA_SUCCESS) {
52406             frameCountOut = 0;
52407         }
52408     }
52409
52410     ma_data_converter_uninit(&converter, NULL);
52411     return frameCountOut;
52412 }
52413
52414
52415 /**************************************************************************************************************************************************************
52416
52417 Ring Buffer
52418
52419 **************************************************************************************************************************************************************/
52420 static MA_INLINE ma_uint32 ma_rb__extract_offset_in_bytes(ma_uint32 encodedOffset)
52421 {
52422     return encodedOffset & 0x7FFFFFFF;
52423 }
52424
52425 static MA_INLINE ma_uint32 ma_rb__extract_offset_loop_flag(ma_uint32 encodedOffset)
52426 {
52427     return encodedOffset & 0x80000000;
52428 }
52429
52430 static MA_INLINE void* ma_rb__get_read_ptr(ma_rb* pRB)
52431 {
52432     MA_ASSERT(pRB != NULL);
52433     return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(c89atomic_load_32(&pRB->encodedReadOffset)));
52434 }
52435
52436 static MA_INLINE void* ma_rb__get_write_ptr(ma_rb* pRB)
52437 {
52438     MA_ASSERT(pRB != NULL);
52439     return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(c89atomic_load_32(&pRB->encodedWriteOffset)));
52440 }
52441
52442 static MA_INLINE ma_uint32 ma_rb__construct_offset(ma_uint32 offsetInBytes, ma_uint32 offsetLoopFlag)
52443 {
52444     return offsetLoopFlag | offsetInBytes;
52445 }
52446
52447 static MA_INLINE void ma_rb__deconstruct_offset(ma_uint32 encodedOffset, ma_uint32* pOffsetInBytes, ma_uint32* pOffsetLoopFlag)
52448 {
52449     MA_ASSERT(pOffsetInBytes != NULL);
52450     MA_ASSERT(pOffsetLoopFlag != NULL);
52451
52452     *pOffsetInBytes  = ma_rb__extract_offset_in_bytes(encodedOffset);
52453     *pOffsetLoopFlag = ma_rb__extract_offset_loop_flag(encodedOffset);
52454 }
52455
52456
52457 MA_API 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)
52458 {
52459     ma_result result;
52460     const ma_uint32 maxSubBufferSize = 0x7FFFFFFF - (MA_SIMD_ALIGNMENT-1);
52461
52462     if (pRB == NULL) {
52463         return MA_INVALID_ARGS;
52464     }
52465
52466     if (subbufferSizeInBytes == 0 || subbufferCount == 0) {
52467         return MA_INVALID_ARGS;
52468     }
52469
52470     if (subbufferSizeInBytes > maxSubBufferSize) {
52471         return MA_INVALID_ARGS;    /* Maximum buffer size is ~2GB. The most significant bit is a flag for use internally. */
52472     }
52473
52474
52475     MA_ZERO_OBJECT(pRB);
52476
52477     result = ma_allocation_callbacks_init_copy(&pRB->allocationCallbacks, pAllocationCallbacks);
52478     if (result != MA_SUCCESS) {
52479         return result;
52480     }
52481
52482     pRB->subbufferSizeInBytes = (ma_uint32)subbufferSizeInBytes;
52483     pRB->subbufferCount = (ma_uint32)subbufferCount;
52484
52485     if (pOptionalPreallocatedBuffer != NULL) {
52486         pRB->subbufferStrideInBytes = (ma_uint32)subbufferStrideInBytes;
52487         pRB->pBuffer = pOptionalPreallocatedBuffer;
52488     } else {
52489         size_t bufferSizeInBytes;
52490
52491         /*
52492         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
52493         we need to make sure the stride is a multiple of MA_SIMD_ALIGNMENT.
52494         */
52495         pRB->subbufferStrideInBytes = (pRB->subbufferSizeInBytes + (MA_SIMD_ALIGNMENT-1)) & ~MA_SIMD_ALIGNMENT;
52496
52497         bufferSizeInBytes = (size_t)pRB->subbufferCount*pRB->subbufferStrideInBytes;
52498         pRB->pBuffer = ma_aligned_malloc(bufferSizeInBytes, MA_SIMD_ALIGNMENT, &pRB->allocationCallbacks);
52499         if (pRB->pBuffer == NULL) {
52500             return MA_OUT_OF_MEMORY;
52501         }
52502
52503         MA_ZERO_MEMORY(pRB->pBuffer, bufferSizeInBytes);
52504         pRB->ownsBuffer = MA_TRUE;
52505     }
52506
52507     return MA_SUCCESS;
52508 }
52509
52510 MA_API ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB)
52511 {
52512     return ma_rb_init_ex(bufferSizeInBytes, 1, 0, pOptionalPreallocatedBuffer, pAllocationCallbacks, pRB);
52513 }
52514
52515 MA_API void ma_rb_uninit(ma_rb* pRB)
52516 {
52517     if (pRB == NULL) {
52518         return;
52519     }
52520
52521     if (pRB->ownsBuffer) {
52522         ma_aligned_free(pRB->pBuffer, &pRB->allocationCallbacks);
52523     }
52524 }
52525
52526 MA_API void ma_rb_reset(ma_rb* pRB)
52527 {
52528     if (pRB == NULL) {
52529         return;
52530     }
52531
52532     c89atomic_exchange_32(&pRB->encodedReadOffset, 0);
52533     c89atomic_exchange_32(&pRB->encodedWriteOffset, 0);
52534 }
52535
52536 MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut)
52537 {
52538     ma_uint32 writeOffset;
52539     ma_uint32 writeOffsetInBytes;
52540     ma_uint32 writeOffsetLoopFlag;
52541     ma_uint32 readOffset;
52542     ma_uint32 readOffsetInBytes;
52543     ma_uint32 readOffsetLoopFlag;
52544     size_t bytesAvailable;
52545     size_t bytesRequested;
52546
52547     if (pRB == NULL || pSizeInBytes == NULL || ppBufferOut == NULL) {
52548         return MA_INVALID_ARGS;
52549     }
52550
52551     /* The returned buffer should never move ahead of the write pointer. */
52552     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
52553     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
52554
52555     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
52556     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
52557
52558     /*
52559     The number of bytes available depends on whether or not the read and write pointers are on the same loop iteration. If so, we
52560     can only read up to the write pointer. If not, we can only read up to the end of the buffer.
52561     */
52562     if (readOffsetLoopFlag == writeOffsetLoopFlag) {
52563         bytesAvailable = writeOffsetInBytes - readOffsetInBytes;
52564     } else {
52565         bytesAvailable = pRB->subbufferSizeInBytes - readOffsetInBytes;
52566     }
52567
52568     bytesRequested = *pSizeInBytes;
52569     if (bytesRequested > bytesAvailable) {
52570         bytesRequested = bytesAvailable;
52571     }
52572
52573     *pSizeInBytes = bytesRequested;
52574     (*ppBufferOut) = ma_rb__get_read_ptr(pRB);
52575
52576     return MA_SUCCESS;
52577 }
52578
52579 MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes)
52580 {
52581     ma_uint32 readOffset;
52582     ma_uint32 readOffsetInBytes;
52583     ma_uint32 readOffsetLoopFlag;
52584     ma_uint32 newReadOffsetInBytes;
52585     ma_uint32 newReadOffsetLoopFlag;
52586
52587     if (pRB == NULL) {
52588         return MA_INVALID_ARGS;
52589     }
52590
52591     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
52592     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
52593
52594     /* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */
52595     newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + sizeInBytes);
52596     if (newReadOffsetInBytes > pRB->subbufferSizeInBytes) {
52597         return MA_INVALID_ARGS;    /* <-- sizeInBytes will cause the read offset to overflow. */
52598     }
52599
52600     /* Move the read pointer back to the start if necessary. */
52601     newReadOffsetLoopFlag = readOffsetLoopFlag;
52602     if (newReadOffsetInBytes == pRB->subbufferSizeInBytes) {
52603         newReadOffsetInBytes = 0;
52604         newReadOffsetLoopFlag ^= 0x80000000;
52605     }
52606
52607     c89atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetLoopFlag, newReadOffsetInBytes));
52608
52609     if (ma_rb_pointer_distance(pRB) == 0) {
52610         return MA_AT_END;
52611     } else {
52612         return MA_SUCCESS;
52613     }
52614 }
52615
52616 MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut)
52617 {
52618     ma_uint32 readOffset;
52619     ma_uint32 readOffsetInBytes;
52620     ma_uint32 readOffsetLoopFlag;
52621     ma_uint32 writeOffset;
52622     ma_uint32 writeOffsetInBytes;
52623     ma_uint32 writeOffsetLoopFlag;
52624     size_t bytesAvailable;
52625     size_t bytesRequested;
52626
52627     if (pRB == NULL || pSizeInBytes == NULL || ppBufferOut == NULL) {
52628         return MA_INVALID_ARGS;
52629     }
52630
52631     /* The returned buffer should never overtake the read buffer. */
52632     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
52633     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
52634
52635     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
52636     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
52637
52638     /*
52639     In the case of writing, if the write pointer and the read pointer are on the same loop iteration we can only
52640     write up to the end of the buffer. Otherwise we can only write up to the read pointer. The write pointer should
52641     never overtake the read pointer.
52642     */
52643     if (writeOffsetLoopFlag == readOffsetLoopFlag) {
52644         bytesAvailable = pRB->subbufferSizeInBytes - writeOffsetInBytes;
52645     } else {
52646         bytesAvailable = readOffsetInBytes - writeOffsetInBytes;
52647     }
52648
52649     bytesRequested = *pSizeInBytes;
52650     if (bytesRequested > bytesAvailable) {
52651         bytesRequested = bytesAvailable;
52652     }
52653
52654     *pSizeInBytes = bytesRequested;
52655     *ppBufferOut  = ma_rb__get_write_ptr(pRB);
52656
52657     /* Clear the buffer if desired. */
52658     if (pRB->clearOnWriteAcquire) {
52659         MA_ZERO_MEMORY(*ppBufferOut, *pSizeInBytes);
52660     }
52661
52662     return MA_SUCCESS;
52663 }
52664
52665 MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes)
52666 {
52667     ma_uint32 writeOffset;
52668     ma_uint32 writeOffsetInBytes;
52669     ma_uint32 writeOffsetLoopFlag;
52670     ma_uint32 newWriteOffsetInBytes;
52671     ma_uint32 newWriteOffsetLoopFlag;
52672
52673     if (pRB == NULL) {
52674         return MA_INVALID_ARGS;
52675     }
52676
52677     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
52678     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
52679
52680     /* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */
52681     newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + sizeInBytes);
52682     if (newWriteOffsetInBytes > pRB->subbufferSizeInBytes) {
52683         return MA_INVALID_ARGS;    /* <-- sizeInBytes will cause the read offset to overflow. */
52684     }
52685
52686     /* Move the read pointer back to the start if necessary. */
52687     newWriteOffsetLoopFlag = writeOffsetLoopFlag;
52688     if (newWriteOffsetInBytes == pRB->subbufferSizeInBytes) {
52689         newWriteOffsetInBytes = 0;
52690         newWriteOffsetLoopFlag ^= 0x80000000;
52691     }
52692
52693     c89atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetLoopFlag, newWriteOffsetInBytes));
52694
52695     if (ma_rb_pointer_distance(pRB) == 0) {
52696         return MA_AT_END;
52697     } else {
52698         return MA_SUCCESS;
52699     }
52700 }
52701
52702 MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes)
52703 {
52704     ma_uint32 readOffset;
52705     ma_uint32 readOffsetInBytes;
52706     ma_uint32 readOffsetLoopFlag;
52707     ma_uint32 writeOffset;
52708     ma_uint32 writeOffsetInBytes;
52709     ma_uint32 writeOffsetLoopFlag;
52710     ma_uint32 newReadOffsetInBytes;
52711     ma_uint32 newReadOffsetLoopFlag;
52712
52713     if (pRB == NULL || offsetInBytes > pRB->subbufferSizeInBytes) {
52714         return MA_INVALID_ARGS;
52715     }
52716
52717     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
52718     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
52719
52720     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
52721     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
52722
52723     newReadOffsetLoopFlag = readOffsetLoopFlag;
52724
52725     /* We cannot go past the write buffer. */
52726     if (readOffsetLoopFlag == writeOffsetLoopFlag) {
52727         if ((readOffsetInBytes + offsetInBytes) > writeOffsetInBytes) {
52728             newReadOffsetInBytes = writeOffsetInBytes;
52729         } else {
52730             newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes);
52731         }
52732     } else {
52733         /* May end up looping. */
52734         if ((readOffsetInBytes + offsetInBytes) >= pRB->subbufferSizeInBytes) {
52735             newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes) - pRB->subbufferSizeInBytes;
52736             newReadOffsetLoopFlag ^= 0x80000000;    /* <-- Looped. */
52737         } else {
52738             newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes);
52739         }
52740     }
52741
52742     c89atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetInBytes, newReadOffsetLoopFlag));
52743     return MA_SUCCESS;
52744 }
52745
52746 MA_API ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes)
52747 {
52748     ma_uint32 readOffset;
52749     ma_uint32 readOffsetInBytes;
52750     ma_uint32 readOffsetLoopFlag;
52751     ma_uint32 writeOffset;
52752     ma_uint32 writeOffsetInBytes;
52753     ma_uint32 writeOffsetLoopFlag;
52754     ma_uint32 newWriteOffsetInBytes;
52755     ma_uint32 newWriteOffsetLoopFlag;
52756
52757     if (pRB == NULL) {
52758         return MA_INVALID_ARGS;
52759     }
52760
52761     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
52762     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
52763
52764     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
52765     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
52766
52767     newWriteOffsetLoopFlag = writeOffsetLoopFlag;
52768
52769     /* We cannot go past the write buffer. */
52770     if (readOffsetLoopFlag == writeOffsetLoopFlag) {
52771         /* May end up looping. */
52772         if ((writeOffsetInBytes + offsetInBytes) >= pRB->subbufferSizeInBytes) {
52773             newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes) - pRB->subbufferSizeInBytes;
52774             newWriteOffsetLoopFlag ^= 0x80000000;    /* <-- Looped. */
52775         } else {
52776             newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes);
52777         }
52778     } else {
52779         if ((writeOffsetInBytes + offsetInBytes) > readOffsetInBytes) {
52780             newWriteOffsetInBytes = readOffsetInBytes;
52781         } else {
52782             newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes);
52783         }
52784     }
52785
52786     c89atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetInBytes, newWriteOffsetLoopFlag));
52787     return MA_SUCCESS;
52788 }
52789
52790 MA_API ma_int32 ma_rb_pointer_distance(ma_rb* pRB)
52791 {
52792     ma_uint32 readOffset;
52793     ma_uint32 readOffsetInBytes;
52794     ma_uint32 readOffsetLoopFlag;
52795     ma_uint32 writeOffset;
52796     ma_uint32 writeOffsetInBytes;
52797     ma_uint32 writeOffsetLoopFlag;
52798
52799     if (pRB == NULL) {
52800         return 0;
52801     }
52802
52803     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
52804     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
52805
52806     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
52807     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
52808
52809     if (readOffsetLoopFlag == writeOffsetLoopFlag) {
52810         return writeOffsetInBytes - readOffsetInBytes;
52811     } else {
52812         return writeOffsetInBytes + (pRB->subbufferSizeInBytes - readOffsetInBytes);
52813     }
52814 }
52815
52816 MA_API ma_uint32 ma_rb_available_read(ma_rb* pRB)
52817 {
52818     ma_int32 dist;
52819
52820     if (pRB == NULL) {
52821         return 0;
52822     }
52823
52824     dist = ma_rb_pointer_distance(pRB);
52825     if (dist < 0) {
52826         return 0;
52827     }
52828
52829     return dist;
52830 }
52831
52832 MA_API ma_uint32 ma_rb_available_write(ma_rb* pRB)
52833 {
52834     if (pRB == NULL) {
52835         return 0;
52836     }
52837
52838     return (ma_uint32)(ma_rb_get_subbuffer_size(pRB) - ma_rb_pointer_distance(pRB));
52839 }
52840
52841 MA_API size_t ma_rb_get_subbuffer_size(ma_rb* pRB)
52842 {
52843     if (pRB == NULL) {
52844         return 0;
52845     }
52846
52847     return pRB->subbufferSizeInBytes;
52848 }
52849
52850 MA_API size_t ma_rb_get_subbuffer_stride(ma_rb* pRB)
52851 {
52852     if (pRB == NULL) {
52853         return 0;
52854     }
52855
52856     if (pRB->subbufferStrideInBytes == 0) {
52857         return (size_t)pRB->subbufferSizeInBytes;
52858     }
52859
52860     return (size_t)pRB->subbufferStrideInBytes;
52861 }
52862
52863 MA_API size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex)
52864 {
52865     if (pRB == NULL) {
52866         return 0;
52867     }
52868
52869     return subbufferIndex * ma_rb_get_subbuffer_stride(pRB);
52870 }
52871
52872 MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer)
52873 {
52874     if (pRB == NULL) {
52875         return NULL;
52876     }
52877
52878     return ma_offset_ptr(pBuffer, ma_rb_get_subbuffer_offset(pRB, subbufferIndex));
52879 }
52880
52881
52882
52883 static MA_INLINE ma_uint32 ma_pcm_rb_get_bpf(ma_pcm_rb* pRB)
52884 {
52885     MA_ASSERT(pRB != NULL);
52886
52887     return ma_get_bytes_per_frame(pRB->format, pRB->channels);
52888 }
52889
52890 MA_API 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)
52891 {
52892     ma_uint32 bpf;
52893     ma_result result;
52894
52895     if (pRB == NULL) {
52896         return MA_INVALID_ARGS;
52897     }
52898
52899     MA_ZERO_OBJECT(pRB);
52900
52901     bpf = ma_get_bytes_per_frame(format, channels);
52902     if (bpf == 0) {
52903         return MA_INVALID_ARGS;
52904     }
52905
52906     result = ma_rb_init_ex(subbufferSizeInFrames*bpf, subbufferCount, subbufferStrideInFrames*bpf, pOptionalPreallocatedBuffer, pAllocationCallbacks, &pRB->rb);
52907     if (result != MA_SUCCESS) {
52908         return result;
52909     }
52910
52911     pRB->format   = format;
52912     pRB->channels = channels;
52913
52914     return MA_SUCCESS;
52915 }
52916
52917 MA_API 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)
52918 {
52919     return ma_pcm_rb_init_ex(format, channels, bufferSizeInFrames, 1, 0, pOptionalPreallocatedBuffer, pAllocationCallbacks, pRB);
52920 }
52921
52922 MA_API void ma_pcm_rb_uninit(ma_pcm_rb* pRB)
52923 {
52924     if (pRB == NULL) {
52925         return;
52926     }
52927
52928     ma_rb_uninit(&pRB->rb);
52929 }
52930
52931 MA_API void ma_pcm_rb_reset(ma_pcm_rb* pRB)
52932 {
52933     if (pRB == NULL) {
52934         return;
52935     }
52936
52937     ma_rb_reset(&pRB->rb);
52938 }
52939
52940 MA_API ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut)
52941 {
52942     size_t sizeInBytes;
52943     ma_result result;
52944
52945     if (pRB == NULL || pSizeInFrames == NULL) {
52946         return MA_INVALID_ARGS;
52947     }
52948
52949     sizeInBytes = *pSizeInFrames * ma_pcm_rb_get_bpf(pRB);
52950
52951     result = ma_rb_acquire_read(&pRB->rb, &sizeInBytes, ppBufferOut);
52952     if (result != MA_SUCCESS) {
52953         return result;
52954     }
52955
52956     *pSizeInFrames = (ma_uint32)(sizeInBytes / (size_t)ma_pcm_rb_get_bpf(pRB));
52957     return MA_SUCCESS;
52958 }
52959
52960 MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames)
52961 {
52962     if (pRB == NULL) {
52963         return MA_INVALID_ARGS;
52964     }
52965
52966     return ma_rb_commit_read(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB));
52967 }
52968
52969 MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut)
52970 {
52971     size_t sizeInBytes;
52972     ma_result result;
52973
52974     if (pRB == NULL) {
52975         return MA_INVALID_ARGS;
52976     }
52977
52978     sizeInBytes = *pSizeInFrames * ma_pcm_rb_get_bpf(pRB);
52979
52980     result = ma_rb_acquire_write(&pRB->rb, &sizeInBytes, ppBufferOut);
52981     if (result != MA_SUCCESS) {
52982         return result;
52983     }
52984
52985     *pSizeInFrames = (ma_uint32)(sizeInBytes / ma_pcm_rb_get_bpf(pRB));
52986     return MA_SUCCESS;
52987 }
52988
52989 MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames)
52990 {
52991     if (pRB == NULL) {
52992         return MA_INVALID_ARGS;
52993     }
52994
52995     return ma_rb_commit_write(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB));
52996 }
52997
52998 MA_API ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames)
52999 {
53000     if (pRB == NULL) {
53001         return MA_INVALID_ARGS;
53002     }
53003
53004     return ma_rb_seek_read(&pRB->rb, offsetInFrames * ma_pcm_rb_get_bpf(pRB));
53005 }
53006
53007 MA_API ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames)
53008 {
53009     if (pRB == NULL) {
53010         return MA_INVALID_ARGS;
53011     }
53012
53013     return ma_rb_seek_write(&pRB->rb, offsetInFrames * ma_pcm_rb_get_bpf(pRB));
53014 }
53015
53016 MA_API ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb* pRB)
53017 {
53018     if (pRB == NULL) {
53019         return 0;
53020     }
53021
53022     return ma_rb_pointer_distance(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
53023 }
53024
53025 MA_API ma_uint32 ma_pcm_rb_available_read(ma_pcm_rb* pRB)
53026 {
53027     if (pRB == NULL) {
53028         return 0;
53029     }
53030
53031     return ma_rb_available_read(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
53032 }
53033
53034 MA_API ma_uint32 ma_pcm_rb_available_write(ma_pcm_rb* pRB)
53035 {
53036     if (pRB == NULL) {
53037         return 0;
53038     }
53039
53040     return ma_rb_available_write(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
53041 }
53042
53043 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb* pRB)
53044 {
53045     if (pRB == NULL) {
53046         return 0;
53047     }
53048
53049     return (ma_uint32)(ma_rb_get_subbuffer_size(&pRB->rb) / ma_pcm_rb_get_bpf(pRB));
53050 }
53051
53052 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb* pRB)
53053 {
53054     if (pRB == NULL) {
53055         return 0;
53056     }
53057
53058     return (ma_uint32)(ma_rb_get_subbuffer_stride(&pRB->rb) / ma_pcm_rb_get_bpf(pRB));
53059 }
53060
53061 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbufferIndex)
53062 {
53063     if (pRB == NULL) {
53064         return 0;
53065     }
53066
53067     return (ma_uint32)(ma_rb_get_subbuffer_offset(&pRB->rb, subbufferIndex) / ma_pcm_rb_get_bpf(pRB));
53068 }
53069
53070 MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer)
53071 {
53072     if (pRB == NULL) {
53073         return NULL;
53074     }
53075
53076     return ma_rb_get_subbuffer_ptr(&pRB->rb, subbufferIndex, pBuffer);
53077 }
53078
53079
53080
53081 MA_API ma_result ma_duplex_rb_init(ma_format captureFormat, ma_uint32 captureChannels, ma_uint32 sampleRate, ma_uint32 captureInternalSampleRate, ma_uint32 captureInternalPeriodSizeInFrames, const ma_allocation_callbacks* pAllocationCallbacks, ma_duplex_rb* pRB)
53082 {
53083     ma_result result;
53084     ma_uint32 sizeInFrames;
53085
53086     sizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(sampleRate, captureInternalSampleRate, captureInternalPeriodSizeInFrames * 5);
53087     if (sizeInFrames == 0) {
53088         return MA_INVALID_ARGS;
53089     }
53090
53091     result = ma_pcm_rb_init(captureFormat, captureChannels, sizeInFrames, NULL, pAllocationCallbacks, &pRB->rb);
53092     if (result != MA_SUCCESS) {
53093         return result;
53094     }
53095
53096     /* Seek forward a bit so we have a bit of a buffer in case of desyncs. */
53097     ma_pcm_rb_seek_write((ma_pcm_rb*)pRB, captureInternalPeriodSizeInFrames * 2);
53098
53099     return MA_SUCCESS;
53100 }
53101
53102 MA_API ma_result ma_duplex_rb_uninit(ma_duplex_rb* pRB)
53103 {
53104     ma_pcm_rb_uninit((ma_pcm_rb*)pRB);
53105     return MA_SUCCESS;
53106 }
53107
53108
53109
53110 /**************************************************************************************************************************************************************
53111
53112 Miscellaneous Helpers
53113
53114 **************************************************************************************************************************************************************/
53115 MA_API const char* ma_result_description(ma_result result)
53116 {
53117     switch (result)
53118     {
53119         case MA_SUCCESS:                       return "No error";
53120         case MA_ERROR:                         return "Unknown error";
53121         case MA_INVALID_ARGS:                  return "Invalid argument";
53122         case MA_INVALID_OPERATION:             return "Invalid operation";
53123         case MA_OUT_OF_MEMORY:                 return "Out of memory";
53124         case MA_OUT_OF_RANGE:                  return "Out of range";
53125         case MA_ACCESS_DENIED:                 return "Permission denied";
53126         case MA_DOES_NOT_EXIST:                return "Resource does not exist";
53127         case MA_ALREADY_EXISTS:                return "Resource already exists";
53128         case MA_TOO_MANY_OPEN_FILES:           return "Too many open files";
53129         case MA_INVALID_FILE:                  return "Invalid file";
53130         case MA_TOO_BIG:                       return "Too large";
53131         case MA_PATH_TOO_LONG:                 return "Path too long";
53132         case MA_NAME_TOO_LONG:                 return "Name too long";
53133         case MA_NOT_DIRECTORY:                 return "Not a directory";
53134         case MA_IS_DIRECTORY:                  return "Is a directory";
53135         case MA_DIRECTORY_NOT_EMPTY:           return "Directory not empty";
53136         case MA_AT_END:                        return "At end";
53137         case MA_NO_SPACE:                      return "No space available";
53138         case MA_BUSY:                          return "Device or resource busy";
53139         case MA_IO_ERROR:                      return "Input/output error";
53140         case MA_INTERRUPT:                     return "Interrupted";
53141         case MA_UNAVAILABLE:                   return "Resource unavailable";
53142         case MA_ALREADY_IN_USE:                return "Resource already in use";
53143         case MA_BAD_ADDRESS:                   return "Bad address";
53144         case MA_BAD_SEEK:                      return "Illegal seek";
53145         case MA_BAD_PIPE:                      return "Broken pipe";
53146         case MA_DEADLOCK:                      return "Deadlock";
53147         case MA_TOO_MANY_LINKS:                return "Too many links";
53148         case MA_NOT_IMPLEMENTED:               return "Not implemented";
53149         case MA_NO_MESSAGE:                    return "No message of desired type";
53150         case MA_BAD_MESSAGE:                   return "Invalid message";
53151         case MA_NO_DATA_AVAILABLE:             return "No data available";
53152         case MA_INVALID_DATA:                  return "Invalid data";
53153         case MA_TIMEOUT:                       return "Timeout";
53154         case MA_NO_NETWORK:                    return "Network unavailable";
53155         case MA_NOT_UNIQUE:                    return "Not unique";
53156         case MA_NOT_SOCKET:                    return "Socket operation on non-socket";
53157         case MA_NO_ADDRESS:                    return "Destination address required";
53158         case MA_BAD_PROTOCOL:                  return "Protocol wrong type for socket";
53159         case MA_PROTOCOL_UNAVAILABLE:          return "Protocol not available";
53160         case MA_PROTOCOL_NOT_SUPPORTED:        return "Protocol not supported";
53161         case MA_PROTOCOL_FAMILY_NOT_SUPPORTED: return "Protocol family not supported";
53162         case MA_ADDRESS_FAMILY_NOT_SUPPORTED:  return "Address family not supported";
53163         case MA_SOCKET_NOT_SUPPORTED:          return "Socket type not supported";
53164         case MA_CONNECTION_RESET:              return "Connection reset";
53165         case MA_ALREADY_CONNECTED:             return "Already connected";
53166         case MA_NOT_CONNECTED:                 return "Not connected";
53167         case MA_CONNECTION_REFUSED:            return "Connection refused";
53168         case MA_NO_HOST:                       return "No host";
53169         case MA_IN_PROGRESS:                   return "Operation in progress";
53170         case MA_CANCELLED:                     return "Operation cancelled";
53171         case MA_MEMORY_ALREADY_MAPPED:         return "Memory already mapped";
53172
53173         case MA_FORMAT_NOT_SUPPORTED:          return "Format not supported";
53174         case MA_DEVICE_TYPE_NOT_SUPPORTED:     return "Device type not supported";
53175         case MA_SHARE_MODE_NOT_SUPPORTED:      return "Share mode not supported";
53176         case MA_NO_BACKEND:                    return "No backend";
53177         case MA_NO_DEVICE:                     return "No device";
53178         case MA_API_NOT_FOUND:                 return "API not found";
53179         case MA_INVALID_DEVICE_CONFIG:         return "Invalid device config";
53180
53181         case MA_DEVICE_NOT_INITIALIZED:        return "Device not initialized";
53182         case MA_DEVICE_NOT_STARTED:            return "Device not started";
53183
53184         case MA_FAILED_TO_INIT_BACKEND:        return "Failed to initialize backend";
53185         case MA_FAILED_TO_OPEN_BACKEND_DEVICE: return "Failed to open backend device";
53186         case MA_FAILED_TO_START_BACKEND_DEVICE: return "Failed to start backend device";
53187         case MA_FAILED_TO_STOP_BACKEND_DEVICE: return "Failed to stop backend device";
53188
53189         default:                               return "Unknown error";
53190     }
53191 }
53192
53193 MA_API void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
53194 {
53195     if (pAllocationCallbacks != NULL) {
53196         if (pAllocationCallbacks->onMalloc != NULL) {
53197             return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
53198         } else {
53199             return NULL;    /* Do not fall back to the default implementation. */
53200         }
53201     } else {
53202         return ma__malloc_default(sz, NULL);
53203     }
53204 }
53205
53206 MA_API void* ma_calloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
53207 {
53208     void* p = ma_malloc(sz, pAllocationCallbacks);
53209     if (p != NULL) {
53210         MA_ZERO_MEMORY(p, sz);
53211     }
53212
53213     return p;
53214 }
53215
53216 MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
53217 {
53218     if (pAllocationCallbacks != NULL) {
53219         if (pAllocationCallbacks->onRealloc != NULL) {
53220             return pAllocationCallbacks->onRealloc(p, sz, pAllocationCallbacks->pUserData);
53221         } else {
53222             return NULL;    /* Do not fall back to the default implementation. */
53223         }
53224     } else {
53225         return ma__realloc_default(p, sz, NULL);
53226     }
53227 }
53228
53229 MA_API void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks)
53230 {
53231     if (p == NULL) {
53232         return;
53233     }
53234
53235     if (pAllocationCallbacks != NULL) {
53236         if (pAllocationCallbacks->onFree != NULL) {
53237             pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
53238         } else {
53239             return; /* Do no fall back to the default implementation. */
53240         }
53241     } else {
53242         ma__free_default(p, NULL);
53243     }
53244 }
53245
53246 MA_API void* ma_aligned_malloc(size_t sz, size_t alignment, const ma_allocation_callbacks* pAllocationCallbacks)
53247 {
53248     size_t extraBytes;
53249     void* pUnaligned;
53250     void* pAligned;
53251
53252     if (alignment == 0) {
53253         return 0;
53254     }
53255
53256     extraBytes = alignment-1 + sizeof(void*);
53257
53258     pUnaligned = ma_malloc(sz + extraBytes, pAllocationCallbacks);
53259     if (pUnaligned == NULL) {
53260         return NULL;
53261     }
53262
53263     pAligned = (void*)(((ma_uintptr)pUnaligned + extraBytes) & ~((ma_uintptr)(alignment-1)));
53264     ((void**)pAligned)[-1] = pUnaligned;
53265
53266     return pAligned;
53267 }
53268
53269 MA_API void ma_aligned_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks)
53270 {
53271     ma_free(((void**)p)[-1], pAllocationCallbacks);
53272 }
53273
53274 MA_API const char* ma_get_format_name(ma_format format)
53275 {
53276     switch (format)
53277     {
53278         case ma_format_unknown: return "Unknown";
53279         case ma_format_u8:      return "8-bit Unsigned Integer";
53280         case ma_format_s16:     return "16-bit Signed Integer";
53281         case ma_format_s24:     return "24-bit Signed Integer (Tightly Packed)";
53282         case ma_format_s32:     return "32-bit Signed Integer";
53283         case ma_format_f32:     return "32-bit IEEE Floating Point";
53284         default:                return "Invalid";
53285     }
53286 }
53287
53288 MA_API void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels)
53289 {
53290     ma_uint32 i;
53291     for (i = 0; i < channels; ++i) {
53292         pOut[i] = ma_mix_f32(pInA[i], pInB[i], factor);
53293     }
53294 }
53295
53296
53297 MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format)
53298 {
53299     ma_uint32 sizes[] = {
53300         0,  /* unknown */
53301         1,  /* u8 */
53302         2,  /* s16 */
53303         3,  /* s24 */
53304         4,  /* s32 */
53305         4,  /* f32 */
53306     };
53307     return sizes[format];
53308 }
53309
53310
53311
53312 MA_API ma_data_source_config ma_data_source_config_init(void)
53313 {
53314     ma_data_source_config config;
53315
53316     MA_ZERO_OBJECT(&config);
53317
53318     return config;
53319 }
53320
53321
53322 MA_API ma_result ma_data_source_init(const ma_data_source_config* pConfig, ma_data_source* pDataSource)
53323 {
53324     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53325
53326     if (pDataSource == NULL) {
53327         return MA_INVALID_ARGS;
53328     }
53329
53330     MA_ZERO_OBJECT(pDataSourceBase);
53331
53332     if (pConfig == NULL) {
53333         return MA_INVALID_ARGS;
53334     }
53335
53336     pDataSourceBase->vtable           = pConfig->vtable;
53337     pDataSourceBase->rangeBegInFrames = 0;
53338     pDataSourceBase->rangeEndInFrames = ~((ma_uint64)0);
53339     pDataSourceBase->loopBegInFrames  = 0;
53340     pDataSourceBase->loopEndInFrames  = ~((ma_uint64)0);
53341     pDataSourceBase->pCurrent         = pDataSource;    /* Always read from ourself by default. */
53342     pDataSourceBase->pNext            = NULL;
53343     pDataSourceBase->onGetNext        = NULL;
53344
53345     return MA_SUCCESS;
53346 }
53347
53348 MA_API void ma_data_source_uninit(ma_data_source* pDataSource)
53349 {
53350     if (pDataSource == NULL) {
53351         return;
53352     }
53353
53354     /*
53355     This is placeholder in case we need this later. Data sources need to call this in their
53356     uninitialization routine to ensure things work later on if something is added here.
53357     */
53358 }
53359
53360 static ma_result ma_data_source_resolve_current(ma_data_source* pDataSource, ma_data_source** ppCurrentDataSource)
53361 {
53362     ma_data_source_base* pCurrentDataSource = (ma_data_source_base*)pDataSource;
53363
53364     MA_ASSERT(pDataSource         != NULL);
53365     MA_ASSERT(ppCurrentDataSource != NULL);
53366
53367     if (pCurrentDataSource->pCurrent == NULL) {
53368         /*
53369         The current data source is NULL. If we're using this in the context of a chain we need to return NULL
53370         here so that we don't end up looping. Otherwise we just return the data source itself.
53371         */
53372         if (pCurrentDataSource->pNext != NULL || pCurrentDataSource->onGetNext != NULL) {
53373             pCurrentDataSource = NULL;
53374         } else {
53375             pCurrentDataSource = (ma_data_source_base*)pDataSource; /* Not being used in a chain. Make sure we just always read from the data source itself at all times. */
53376         }
53377     } else {
53378         pCurrentDataSource = (ma_data_source_base*)pCurrentDataSource->pCurrent;
53379     }
53380
53381     *ppCurrentDataSource = pCurrentDataSource;
53382
53383     return MA_SUCCESS;
53384 }
53385
53386 static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
53387 {
53388     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53389     ma_result result;
53390     ma_uint64 framesRead = 0;
53391     ma_bool32 loop = ma_data_source_is_looping(pDataSource);
53392
53393     if (pDataSourceBase == NULL) {
53394         return MA_AT_END;
53395     }
53396
53397     if (frameCount == 0) {
53398         return MA_INVALID_ARGS;
53399     }
53400
53401     if ((pDataSourceBase->vtable->flags & MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT) != 0 || (pDataSourceBase->rangeEndInFrames == ~((ma_uint64)0) && (pDataSourceBase->loopEndInFrames == ~((ma_uint64)0) || loop == MA_FALSE))) {
53402         /* Either the data source is self-managing the range, or no range is set - just read like normal. The data source itself will tell us when the end is reached. */
53403         result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead);
53404     } else {
53405         /* Need to clamp to within the range. */
53406         ma_uint64 cursor;
53407
53408         result = ma_data_source_get_cursor_in_pcm_frames(pDataSourceBase, &cursor);
53409         if (result != MA_SUCCESS) {
53410             /* Failed to retrieve the cursor. Cannot read within a range or loop points. Just read like normal - this may happen for things like noise data sources where it doesn't really matter. */
53411             result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead);
53412         } else {
53413             ma_uint64 rangeEnd;
53414
53415             /* We have the cursor. We need to make sure we don't read beyond our range. */
53416             rangeEnd = pDataSourceBase->rangeEndInFrames;
53417
53418             /* If looping, make sure we're within range. */
53419             if (loop) {
53420                 if (pDataSourceBase->loopEndInFrames != ~((ma_uint64)0)) {
53421                     rangeEnd = ma_min(rangeEnd, pDataSourceBase->rangeBegInFrames + pDataSourceBase->loopEndInFrames);
53422                 }
53423             }
53424
53425             if (frameCount > (rangeEnd - cursor) && rangeEnd != ~((ma_uint64)0)) {
53426                 frameCount = (rangeEnd - cursor);
53427             }
53428
53429             /*
53430             If the cursor is sitting on the end of the range the frame count will be set to 0 which can
53431             result in MA_INVALID_ARGS. In this case, we don't want to try reading, but instead return
53432             MA_AT_END so the higher level function can know about it.
53433             */
53434             if (frameCount > 0) {
53435                 result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead);
53436             } else {
53437                 result = MA_AT_END; /* The cursor is sitting on the end of the range which means we're at the end. */
53438             }
53439         }
53440     }
53441
53442     if (pFramesRead != NULL) {
53443         *pFramesRead = framesRead;
53444     }
53445
53446     /* We need to make sure MA_AT_END is returned if we hit the end of the range. */
53447     if (result == MA_SUCCESS && framesRead == 0) {
53448         result  = MA_AT_END;
53449     }
53450
53451     return result;
53452 }
53453
53454 MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
53455 {
53456     ma_result result = MA_SUCCESS;
53457     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53458     ma_data_source_base* pCurrentDataSource;
53459     void* pRunningFramesOut = pFramesOut;
53460     ma_uint64 totalFramesProcessed = 0;
53461     ma_format format;
53462     ma_uint32 channels;
53463     ma_uint32 emptyLoopCounter = 0; /* Keeps track of how many times 0 frames have been read. For infinite loop detection of sounds with no audio data. */
53464     ma_bool32 loop;
53465
53466     if (pFramesRead != NULL) {
53467         *pFramesRead = 0;
53468     }
53469
53470     if (frameCount == 0) {
53471         return MA_INVALID_ARGS;
53472     }
53473
53474     if (pDataSourceBase == NULL) {
53475         return MA_INVALID_ARGS;
53476     }
53477
53478     loop = ma_data_source_is_looping(pDataSource);
53479
53480     /*
53481     We need to know the data format so we can advance the output buffer as we read frames. If this
53482     fails, chaining will not work and we'll just read as much as we can from the current source.
53483     */
53484     if (ma_data_source_get_data_format(pDataSource, &format, &channels, NULL, NULL, 0) != MA_SUCCESS) {
53485         result = ma_data_source_resolve_current(pDataSource, (ma_data_source**)&pCurrentDataSource);
53486         if (result != MA_SUCCESS) {
53487             return result;
53488         }
53489
53490         return ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pFramesOut, frameCount, pFramesRead);
53491     }
53492
53493     /*
53494     Looping is a bit of a special case. When the `loop` argument is true, chaining will not work and
53495     only the current data source will be read from.
53496     */
53497
53498     /* Keep reading until we've read as many frames as possible. */
53499     while (totalFramesProcessed < frameCount) {
53500         ma_uint64 framesProcessed;
53501         ma_uint64 framesRemaining = frameCount - totalFramesProcessed;
53502
53503         /* We need to resolve the data source that we'll actually be reading from. */
53504         result = ma_data_source_resolve_current(pDataSource, (ma_data_source**)&pCurrentDataSource);
53505         if (result != MA_SUCCESS) {
53506             break;
53507         }
53508
53509         if (pCurrentDataSource == NULL) {
53510             break;
53511         }
53512
53513         result = ma_data_source_read_pcm_frames_within_range(pCurrentDataSource, pRunningFramesOut, framesRemaining, &framesProcessed);
53514         totalFramesProcessed += framesProcessed;
53515
53516         /*
53517         If we encounted an error from the read callback, make sure it's propagated to the caller. The caller may need to know whether or not MA_BUSY is returned which is
53518         not necessarily considered an error.
53519         */
53520         if (result != MA_SUCCESS && result != MA_AT_END) {
53521             break;
53522         }
53523
53524         /*
53525         We can determine if we've reached the end by checking if ma_data_source_read_pcm_frames_within_range() returned
53526         MA_AT_END. To loop back to the start, all we need to do is seek back to the first frame.
53527         */
53528         if (result == MA_AT_END) {
53529             /*
53530             We reached the end. If we're looping, we just loop back to the start of the current
53531             data source. If we're not looping we need to check if we have another in the chain, and
53532             if so, switch to it.
53533             */
53534             if (loop) {
53535                 if (framesProcessed == 0) {
53536                     emptyLoopCounter += 1;
53537                     if (emptyLoopCounter > 1) {
53538                         break;  /* Infinite loop detected. Get out. */
53539                     }
53540                 } else {
53541                     emptyLoopCounter = 0;
53542                 }
53543
53544                 result = ma_data_source_seek_to_pcm_frame(pCurrentDataSource, pCurrentDataSource->loopBegInFrames);
53545                 if (result != MA_SUCCESS) {
53546                     break;  /* Failed to loop. Abort. */
53547                 }
53548
53549                 /* Don't return MA_AT_END for looping sounds. */
53550                 result = MA_SUCCESS;
53551             } else {
53552                 if (pCurrentDataSource->pNext != NULL) {
53553                     pDataSourceBase->pCurrent = pCurrentDataSource->pNext;
53554                 } else if (pCurrentDataSource->onGetNext != NULL) {
53555                     pDataSourceBase->pCurrent = pCurrentDataSource->onGetNext(pCurrentDataSource);
53556                     if (pDataSourceBase->pCurrent == NULL) {
53557                         break;  /* Our callback did not return a next data source. We're done. */
53558                     }
53559                 } else {
53560                     /* Reached the end of the chain. We're done. */
53561                     break;
53562                 }
53563
53564                 /* The next data source needs to be rewound to ensure data is read in looping scenarios. */
53565                 result = ma_data_source_seek_to_pcm_frame(pDataSourceBase->pCurrent, 0);
53566                 if (result != MA_SUCCESS) {
53567                     break;
53568                 }
53569
53570                 /*
53571                 We need to make sure we clear the MA_AT_END result so we don't accidentally return
53572                 it in the event that we coincidentally ended reading at the exact transition point
53573                 of two data sources in a chain.
53574                 */
53575                 result = MA_SUCCESS;
53576             }
53577         }
53578
53579         if (pRunningFramesOut != NULL) {
53580             pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesProcessed * ma_get_bytes_per_frame(format, channels));
53581         }
53582     }
53583
53584     if (pFramesRead != NULL) {
53585         *pFramesRead = totalFramesProcessed;
53586     }
53587
53588     if (result == MA_SUCCESS && totalFramesProcessed == 0) {
53589         result  = MA_AT_END;
53590     }
53591
53592     return result;
53593 }
53594
53595 MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked)
53596 {
53597     return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, pFramesSeeked);
53598 }
53599
53600 MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex)
53601 {
53602     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53603
53604     if (pDataSourceBase == NULL) {
53605         return MA_SUCCESS;
53606     }
53607
53608     if (pDataSourceBase->vtable->onSeek == NULL) {
53609         return MA_NOT_IMPLEMENTED;
53610     }
53611
53612     if (frameIndex > pDataSourceBase->rangeEndInFrames) {
53613         return MA_INVALID_OPERATION;    /* Trying to seek to far forward. */
53614     }
53615
53616     return pDataSourceBase->vtable->onSeek(pDataSource, pDataSourceBase->rangeBegInFrames + frameIndex);
53617 }
53618
53619 MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
53620 {
53621     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53622     ma_result result;
53623     ma_format format;
53624     ma_uint32 channels;
53625     ma_uint32 sampleRate;
53626
53627     /* Initialize to defaults for safety just in case the data source does not implement this callback. */
53628     if (pFormat != NULL) {
53629         *pFormat = ma_format_unknown;
53630     }
53631     if (pChannels != NULL) {
53632         *pChannels = 0;
53633     }
53634     if (pSampleRate != NULL) {
53635         *pSampleRate = 0;
53636     }
53637     if (pChannelMap != NULL) {
53638         MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
53639     }
53640
53641     if (pDataSourceBase == NULL) {
53642         return MA_INVALID_ARGS;
53643     }
53644
53645     if (pDataSourceBase->vtable->onGetDataFormat == NULL) {
53646         return MA_NOT_IMPLEMENTED;
53647     }
53648
53649     result = pDataSourceBase->vtable->onGetDataFormat(pDataSource, &format, &channels, &sampleRate, pChannelMap, channelMapCap);
53650     if (result != MA_SUCCESS) {
53651         return result;
53652     }
53653
53654     if (pFormat != NULL) {
53655         *pFormat = format;
53656     }
53657     if (pChannels != NULL) {
53658         *pChannels = channels;
53659     }
53660     if (pSampleRate != NULL) {
53661         *pSampleRate = sampleRate;
53662     }
53663
53664     /* Channel map was passed in directly to the callback. This is safe due to the channelMapCap parameter. */
53665
53666     return MA_SUCCESS;
53667 }
53668
53669 MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor)
53670 {
53671     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53672     ma_result result;
53673     ma_uint64 cursor;
53674
53675     if (pCursor == NULL) {
53676         return MA_INVALID_ARGS;
53677     }
53678
53679     *pCursor = 0;
53680
53681     if (pDataSourceBase == NULL) {
53682         return MA_SUCCESS;
53683     }
53684
53685     if (pDataSourceBase->vtable->onGetCursor == NULL) {
53686         return MA_NOT_IMPLEMENTED;
53687     }
53688
53689     result = pDataSourceBase->vtable->onGetCursor(pDataSourceBase, &cursor);
53690     if (result != MA_SUCCESS) {
53691         return result;
53692     }
53693
53694     /* The cursor needs to be made relative to the start of the range. */
53695     if (cursor < pDataSourceBase->rangeBegInFrames) {   /* Safety check so we don't return some huge number. */
53696         *pCursor = 0;
53697     } else {
53698         *pCursor = cursor - pDataSourceBase->rangeBegInFrames;
53699     }
53700
53701     return MA_SUCCESS;
53702 }
53703
53704 MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength)
53705 {
53706     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53707
53708     if (pLength == NULL) {
53709         return MA_INVALID_ARGS;
53710     }
53711
53712     *pLength = 0;
53713
53714     if (pDataSourceBase == NULL) {
53715         return MA_INVALID_ARGS;
53716     }
53717
53718     /*
53719     If we have a range defined we'll use that to determine the length. This is one of rare times
53720     where we'll actually trust the caller. If they've set the range, I think it's mostly safe to
53721     assume they've set it based on some higher level knowledge of the structure of the sound bank.
53722     */
53723     if (pDataSourceBase->rangeEndInFrames != ~((ma_uint64)0)) {
53724         *pLength = pDataSourceBase->rangeEndInFrames - pDataSourceBase->rangeBegInFrames;
53725         return MA_SUCCESS;
53726     }
53727
53728     /*
53729     Getting here means a range is not defined so we'll need to get the data source itself to tell
53730     us the length.
53731     */
53732     if (pDataSourceBase->vtable->onGetLength == NULL) {
53733         return MA_NOT_IMPLEMENTED;
53734     }
53735
53736     return pDataSourceBase->vtable->onGetLength(pDataSource, pLength);
53737 }
53738
53739 MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool32 isLooping)
53740 {
53741     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53742
53743     if (pDataSource == NULL) {
53744         return MA_INVALID_ARGS;
53745     }
53746
53747     c89atomic_exchange_32(&pDataSourceBase->isLooping, isLooping);
53748
53749     /* If there's no callback for this just treat it as a successful no-op. */
53750     if (pDataSourceBase->vtable->onSetLooping == NULL) {
53751         return MA_SUCCESS;
53752     }
53753
53754     return pDataSourceBase->vtable->onSetLooping(pDataSource, isLooping);
53755 }
53756
53757 MA_API ma_bool32 ma_data_source_is_looping(ma_data_source* pDataSource)
53758 {
53759     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53760
53761     if (pDataSource == NULL) {
53762         return MA_FALSE;
53763     }
53764
53765     return c89atomic_load_32(&pDataSourceBase->isLooping);
53766 }
53767
53768 MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames)
53769 {
53770     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53771     ma_result result;
53772     ma_uint64 cursor;
53773     ma_uint64 loopBegAbsolute;
53774     ma_uint64 loopEndAbsolute;
53775
53776     if (pDataSource == NULL) {
53777         return MA_INVALID_ARGS;
53778     }
53779
53780     if (rangeEndInFrames < rangeBegInFrames) {
53781         return MA_INVALID_ARGS; /* The end of the range must come after the beginning. */
53782     }
53783
53784     /*
53785     The loop points need to be updated. We'll be storing the loop points relative to the range. We'll update
53786     these so that they maintain their absolute positioning. The loop points will then be clamped to the range.
53787     */
53788     loopBegAbsolute = pDataSourceBase->loopBegInFrames + pDataSourceBase->rangeBegInFrames;
53789     loopEndAbsolute = pDataSourceBase->loopEndInFrames + ((pDataSourceBase->loopEndInFrames != ~((ma_uint64)0)) ? pDataSourceBase->rangeBegInFrames : 0);
53790
53791     pDataSourceBase->rangeBegInFrames = rangeBegInFrames;
53792     pDataSourceBase->rangeEndInFrames = rangeEndInFrames;
53793
53794     /* Make the loop points relative again, and make sure they're clamped to within the range. */
53795     if (loopBegAbsolute > pDataSourceBase->rangeBegInFrames) {
53796         pDataSourceBase->loopBegInFrames = loopBegAbsolute - pDataSourceBase->rangeBegInFrames;
53797     } else {
53798         pDataSourceBase->loopBegInFrames = 0;
53799     }
53800
53801     if (pDataSourceBase->loopBegInFrames > pDataSourceBase->rangeEndInFrames) {
53802         pDataSourceBase->loopBegInFrames = pDataSourceBase->rangeEndInFrames;
53803     }
53804
53805     /* Only need to update the loop end point if it's not -1. */
53806     if (loopEndAbsolute != ~((ma_uint64)0)) {
53807         if (loopEndAbsolute > pDataSourceBase->rangeBegInFrames) {
53808             pDataSourceBase->loopEndInFrames = loopEndAbsolute - pDataSourceBase->rangeBegInFrames;
53809         } else {
53810             pDataSourceBase->loopEndInFrames = 0;
53811         }
53812
53813         if (pDataSourceBase->loopEndInFrames > pDataSourceBase->rangeEndInFrames && pDataSourceBase->loopEndInFrames) {
53814             pDataSourceBase->loopEndInFrames = pDataSourceBase->rangeEndInFrames;
53815         }
53816     }
53817
53818
53819     /* If the new range is past the current cursor position we need to seek to it. */
53820     result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &cursor);
53821     if (result == MA_SUCCESS) {
53822         /* Seek to within range. Note that our seek positions here are relative to the new range. */
53823         if (cursor < rangeBegInFrames) {
53824             ma_data_source_seek_to_pcm_frame(pDataSource, 0);
53825         } else if (cursor > rangeEndInFrames) {
53826             ma_data_source_seek_to_pcm_frame(pDataSource, rangeEndInFrames - rangeBegInFrames);
53827         }
53828     } else {
53829         /* We failed to get the cursor position. Probably means the data source has no notion of a cursor such a noise data source. Just pretend the seeking worked. */
53830     }
53831
53832     return MA_SUCCESS;
53833 }
53834
53835 MA_API void ma_data_source_get_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames)
53836 {
53837     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53838
53839     if (pDataSource == NULL) {
53840         return;
53841     }
53842
53843     if (pRangeBegInFrames != NULL) {
53844         *pRangeBegInFrames = pDataSourceBase->rangeBegInFrames;
53845     }
53846
53847     if (pRangeEndInFrames != NULL) {
53848         *pRangeEndInFrames = pDataSourceBase->rangeEndInFrames;
53849     }
53850 }
53851
53852 MA_API ma_result ma_data_source_set_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 loopBegInFrames, ma_uint64 loopEndInFrames)
53853 {
53854     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53855
53856     if (pDataSource == NULL) {
53857         return MA_INVALID_ARGS;
53858     }
53859
53860     if (loopEndInFrames < loopBegInFrames) {
53861         return MA_INVALID_ARGS; /* The end of the loop point must come after the beginning. */
53862     }
53863
53864     if (loopEndInFrames > pDataSourceBase->rangeEndInFrames && loopEndInFrames != ~((ma_uint64)0)) {
53865         return MA_INVALID_ARGS; /* The end of the loop point must not go beyond the range. */
53866     }
53867
53868     pDataSourceBase->loopBegInFrames = loopBegInFrames;
53869     pDataSourceBase->loopEndInFrames = loopEndInFrames;
53870
53871     /* The end cannot exceed the range. */
53872     if (pDataSourceBase->loopEndInFrames > (pDataSourceBase->rangeEndInFrames - pDataSourceBase->rangeBegInFrames) && pDataSourceBase->loopEndInFrames != ~((ma_uint64)0)) {
53873         pDataSourceBase->loopEndInFrames = (pDataSourceBase->rangeEndInFrames - pDataSourceBase->rangeBegInFrames);
53874     }
53875
53876     return MA_SUCCESS;
53877 }
53878
53879 MA_API void ma_data_source_get_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames)
53880 {
53881     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53882
53883     if (pDataSource == NULL) {
53884         return;
53885     }
53886
53887     if (pLoopBegInFrames != NULL) {
53888         *pLoopBegInFrames = pDataSourceBase->loopBegInFrames;
53889     }
53890
53891     if (pLoopEndInFrames != NULL) {
53892         *pLoopEndInFrames = pDataSourceBase->loopEndInFrames;
53893     }
53894 }
53895
53896 MA_API ma_result ma_data_source_set_current(ma_data_source* pDataSource, ma_data_source* pCurrentDataSource)
53897 {
53898     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53899
53900     if (pDataSource == NULL) {
53901         return MA_INVALID_ARGS;
53902     }
53903
53904     pDataSourceBase->pCurrent = pCurrentDataSource;
53905
53906     return MA_SUCCESS;
53907 }
53908
53909 MA_API ma_data_source* ma_data_source_get_current(ma_data_source* pDataSource)
53910 {
53911     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53912
53913     if (pDataSource == NULL) {
53914         return NULL;
53915     }
53916
53917     return pDataSourceBase->pCurrent;
53918 }
53919
53920 MA_API ma_result ma_data_source_set_next(ma_data_source* pDataSource, ma_data_source* pNextDataSource)
53921 {
53922     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53923
53924     if (pDataSource == NULL) {
53925         return MA_INVALID_ARGS;
53926     }
53927
53928     pDataSourceBase->pNext = pNextDataSource;
53929
53930     return MA_SUCCESS;
53931 }
53932
53933 MA_API ma_data_source* ma_data_source_get_next(ma_data_source* pDataSource)
53934 {
53935     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53936
53937     if (pDataSource == NULL) {
53938         return NULL;
53939     }
53940
53941     return pDataSourceBase->pNext;
53942 }
53943
53944 MA_API ma_result ma_data_source_set_next_callback(ma_data_source* pDataSource, ma_data_source_get_next_proc onGetNext)
53945 {
53946     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53947
53948     if (pDataSource == NULL) {
53949         return MA_INVALID_ARGS;
53950     }
53951
53952     pDataSourceBase->onGetNext = onGetNext;
53953
53954     return MA_SUCCESS;
53955 }
53956
53957 MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(ma_data_source* pDataSource)
53958 {
53959     ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
53960
53961     if (pDataSource == NULL) {
53962         return NULL;
53963     }
53964
53965     return pDataSourceBase->onGetNext;
53966 }
53967
53968
53969 static ma_result ma_audio_buffer_ref__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
53970 {
53971     ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource;
53972     ma_uint64 framesRead = ma_audio_buffer_ref_read_pcm_frames(pAudioBufferRef, pFramesOut, frameCount, MA_FALSE);
53973
53974     if (pFramesRead != NULL) {
53975         *pFramesRead = framesRead;
53976     }
53977
53978     if (framesRead < frameCount || framesRead == 0) {
53979         return MA_AT_END;
53980     }
53981
53982     return MA_SUCCESS;
53983 }
53984
53985 static ma_result ma_audio_buffer_ref__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
53986 {
53987     return ma_audio_buffer_ref_seek_to_pcm_frame((ma_audio_buffer_ref*)pDataSource, frameIndex);
53988 }
53989
53990 static ma_result ma_audio_buffer_ref__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
53991 {
53992     ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource;
53993
53994     *pFormat     = pAudioBufferRef->format;
53995     *pChannels   = pAudioBufferRef->channels;
53996     *pSampleRate = 0;   /* There is no notion of a sample rate with audio buffers. */
53997     ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pAudioBufferRef->channels);
53998
53999     return MA_SUCCESS;
54000 }
54001
54002 static ma_result ma_audio_buffer_ref__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
54003 {
54004     ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource;
54005
54006     *pCursor = pAudioBufferRef->cursor;
54007
54008     return MA_SUCCESS;
54009 }
54010
54011 static ma_result ma_audio_buffer_ref__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
54012 {
54013     ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource;
54014
54015     *pLength = pAudioBufferRef->sizeInFrames;
54016
54017     return MA_SUCCESS;
54018 }
54019
54020 static ma_data_source_vtable g_ma_audio_buffer_ref_data_source_vtable =
54021 {
54022     ma_audio_buffer_ref__data_source_on_read,
54023     ma_audio_buffer_ref__data_source_on_seek,
54024     ma_audio_buffer_ref__data_source_on_get_data_format,
54025     ma_audio_buffer_ref__data_source_on_get_cursor,
54026     ma_audio_buffer_ref__data_source_on_get_length,
54027     NULL,   /* onSetLooping */
54028     0
54029 };
54030
54031 MA_API ma_result ma_audio_buffer_ref_init(ma_format format, ma_uint32 channels, const void* pData, ma_uint64 sizeInFrames, ma_audio_buffer_ref* pAudioBufferRef)
54032 {
54033     ma_result result;
54034     ma_data_source_config dataSourceConfig;
54035
54036     if (pAudioBufferRef == NULL) {
54037         return MA_INVALID_ARGS;
54038     }
54039
54040     MA_ZERO_OBJECT(pAudioBufferRef);
54041
54042     dataSourceConfig = ma_data_source_config_init();
54043     dataSourceConfig.vtable = &g_ma_audio_buffer_ref_data_source_vtable;
54044
54045     result = ma_data_source_init(&dataSourceConfig, &pAudioBufferRef->ds);
54046     if (result != MA_SUCCESS) {
54047         return result;
54048     }
54049
54050     pAudioBufferRef->format       = format;
54051     pAudioBufferRef->channels     = channels;
54052     pAudioBufferRef->cursor       = 0;
54053     pAudioBufferRef->sizeInFrames = sizeInFrames;
54054     pAudioBufferRef->pData        = pData;
54055
54056     return MA_SUCCESS;
54057 }
54058
54059 MA_API void ma_audio_buffer_ref_uninit(ma_audio_buffer_ref* pAudioBufferRef)
54060 {
54061     if (pAudioBufferRef == NULL) {
54062         return;
54063     }
54064
54065     ma_data_source_uninit(&pAudioBufferRef->ds);
54066 }
54067
54068 MA_API ma_result ma_audio_buffer_ref_set_data(ma_audio_buffer_ref* pAudioBufferRef, const void* pData, ma_uint64 sizeInFrames)
54069 {
54070     if (pAudioBufferRef == NULL) {
54071         return MA_INVALID_ARGS;
54072     }
54073
54074     pAudioBufferRef->cursor       = 0;
54075     pAudioBufferRef->sizeInFrames = sizeInFrames;
54076     pAudioBufferRef->pData        = pData;
54077
54078     return MA_SUCCESS;
54079 }
54080
54081 MA_API ma_uint64 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref* pAudioBufferRef, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop)
54082 {
54083     ma_uint64 totalFramesRead = 0;
54084
54085     if (pAudioBufferRef == NULL) {
54086         return 0;
54087     }
54088
54089     if (frameCount == 0) {
54090         return 0;
54091     }
54092
54093     while (totalFramesRead < frameCount) {
54094         ma_uint64 framesAvailable = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor;
54095         ma_uint64 framesRemaining = frameCount - totalFramesRead;
54096         ma_uint64 framesToRead;
54097
54098         framesToRead = framesRemaining;
54099         if (framesToRead > framesAvailable) {
54100             framesToRead = framesAvailable;
54101         }
54102
54103         if (pFramesOut != NULL) {
54104             ma_copy_pcm_frames(pFramesOut, ma_offset_ptr(pAudioBufferRef->pData, pAudioBufferRef->cursor * ma_get_bytes_per_frame(pAudioBufferRef->format, pAudioBufferRef->channels)), framesToRead, pAudioBufferRef->format, pAudioBufferRef->channels);
54105         }
54106
54107         totalFramesRead += framesToRead;
54108
54109         pAudioBufferRef->cursor += framesToRead;
54110         if (pAudioBufferRef->cursor == pAudioBufferRef->sizeInFrames) {
54111             if (loop) {
54112                 pAudioBufferRef->cursor = 0;
54113             } else {
54114                 break;  /* We've reached the end and we're not looping. Done. */
54115             }
54116         }
54117
54118         MA_ASSERT(pAudioBufferRef->cursor < pAudioBufferRef->sizeInFrames);
54119     }
54120
54121     return totalFramesRead;
54122 }
54123
54124 MA_API ma_result ma_audio_buffer_ref_seek_to_pcm_frame(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameIndex)
54125 {
54126     if (pAudioBufferRef == NULL) {
54127         return MA_INVALID_ARGS;
54128     }
54129
54130     if (frameIndex > pAudioBufferRef->sizeInFrames) {
54131         return MA_INVALID_ARGS;
54132     }
54133
54134     pAudioBufferRef->cursor = (size_t)frameIndex;
54135
54136     return MA_SUCCESS;
54137 }
54138
54139 MA_API ma_result ma_audio_buffer_ref_map(ma_audio_buffer_ref* pAudioBufferRef, void** ppFramesOut, ma_uint64* pFrameCount)
54140 {
54141     ma_uint64 framesAvailable;
54142     ma_uint64 frameCount = 0;
54143
54144     if (ppFramesOut != NULL) {
54145         *ppFramesOut = NULL;    /* Safety. */
54146     }
54147
54148     if (pFrameCount != NULL) {
54149         frameCount = *pFrameCount;
54150         *pFrameCount = 0;       /* Safety. */
54151     }
54152
54153     if (pAudioBufferRef == NULL || ppFramesOut == NULL || pFrameCount == NULL) {
54154         return MA_INVALID_ARGS;
54155     }
54156
54157     framesAvailable = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor;
54158     if (frameCount > framesAvailable) {
54159         frameCount = framesAvailable;
54160     }
54161
54162     *ppFramesOut = ma_offset_ptr(pAudioBufferRef->pData, pAudioBufferRef->cursor * ma_get_bytes_per_frame(pAudioBufferRef->format, pAudioBufferRef->channels));
54163     *pFrameCount = frameCount;
54164
54165     return MA_SUCCESS;
54166 }
54167
54168 MA_API ma_result ma_audio_buffer_ref_unmap(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameCount)
54169 {
54170     ma_uint64 framesAvailable;
54171
54172     if (pAudioBufferRef == NULL) {
54173         return MA_INVALID_ARGS;
54174     }
54175
54176     framesAvailable = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor;
54177     if (frameCount > framesAvailable) {
54178         return MA_INVALID_ARGS;   /* The frame count was too big. This should never happen in an unmapping. Need to make sure the caller is aware of this. */
54179     }
54180
54181     pAudioBufferRef->cursor += frameCount;
54182
54183     if (pAudioBufferRef->cursor == pAudioBufferRef->sizeInFrames) {
54184         return MA_AT_END;   /* Successful. Need to tell the caller that the end has been reached so that it can loop if desired. */
54185     } else {
54186         return MA_SUCCESS;
54187     }
54188 }
54189
54190 MA_API ma_bool32 ma_audio_buffer_ref_at_end(const ma_audio_buffer_ref* pAudioBufferRef)
54191 {
54192     if (pAudioBufferRef == NULL) {
54193         return MA_FALSE;
54194     }
54195
54196     return pAudioBufferRef->cursor == pAudioBufferRef->sizeInFrames;
54197 }
54198
54199 MA_API ma_result ma_audio_buffer_ref_get_cursor_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pCursor)
54200 {
54201     if (pCursor == NULL) {
54202         return MA_INVALID_ARGS;
54203     }
54204
54205     *pCursor = 0;
54206
54207     if (pAudioBufferRef == NULL) {
54208         return MA_INVALID_ARGS;
54209     }
54210
54211     *pCursor = pAudioBufferRef->cursor;
54212
54213     return MA_SUCCESS;
54214 }
54215
54216 MA_API ma_result ma_audio_buffer_ref_get_length_in_pcm_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pLength)
54217 {
54218     if (pLength == NULL) {
54219         return MA_INVALID_ARGS;
54220     }
54221
54222     *pLength = 0;
54223
54224     if (pAudioBufferRef == NULL) {
54225         return MA_INVALID_ARGS;
54226     }
54227
54228     *pLength = pAudioBufferRef->sizeInFrames;
54229
54230     return MA_SUCCESS;
54231 }
54232
54233 MA_API ma_result ma_audio_buffer_ref_get_available_frames(const ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pAvailableFrames)
54234 {
54235     if (pAvailableFrames == NULL) {
54236         return MA_INVALID_ARGS;
54237     }
54238
54239     *pAvailableFrames = 0;
54240
54241     if (pAudioBufferRef == NULL) {
54242         return MA_INVALID_ARGS;
54243     }
54244
54245     if (pAudioBufferRef->sizeInFrames <= pAudioBufferRef->cursor) {
54246         *pAvailableFrames = 0;
54247     } else {
54248         *pAvailableFrames = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor;
54249     }
54250
54251     return MA_SUCCESS;
54252 }
54253
54254
54255
54256
54257 MA_API ma_audio_buffer_config ma_audio_buffer_config_init(ma_format format, ma_uint32 channels, ma_uint64 sizeInFrames, const void* pData, const ma_allocation_callbacks* pAllocationCallbacks)
54258 {
54259     ma_audio_buffer_config config;
54260
54261     MA_ZERO_OBJECT(&config);
54262     config.format = format;
54263     config.channels = channels;
54264     config.sizeInFrames = sizeInFrames;
54265     config.pData = pData;
54266     ma_allocation_callbacks_init_copy(&config.allocationCallbacks, pAllocationCallbacks);
54267
54268     return config;
54269 }
54270
54271 static ma_result ma_audio_buffer_init_ex(const ma_audio_buffer_config* pConfig, ma_bool32 doCopy, ma_audio_buffer* pAudioBuffer)
54272 {
54273     ma_result result;
54274
54275     if (pAudioBuffer == NULL) {
54276         return MA_INVALID_ARGS;
54277     }
54278
54279     MA_ZERO_MEMORY(pAudioBuffer, sizeof(*pAudioBuffer) - sizeof(pAudioBuffer->_pExtraData));   /* Safety. Don't overwrite the extra data. */
54280
54281     if (pConfig == NULL) {
54282         return MA_INVALID_ARGS;
54283     }
54284
54285     if (pConfig->sizeInFrames == 0) {
54286         return MA_INVALID_ARGS; /* Not allowing buffer sizes of 0 frames. */
54287     }
54288
54289     result = ma_audio_buffer_ref_init(pConfig->format, pConfig->channels, NULL, 0, &pAudioBuffer->ref);
54290     if (result != MA_SUCCESS) {
54291         return result;
54292     }
54293
54294     ma_allocation_callbacks_init_copy(&pAudioBuffer->allocationCallbacks, &pConfig->allocationCallbacks);
54295
54296     if (doCopy) {
54297         ma_uint64 allocationSizeInBytes;
54298         void* pData;
54299
54300         allocationSizeInBytes = pConfig->sizeInFrames * ma_get_bytes_per_frame(pConfig->format, pConfig->channels);
54301         if (allocationSizeInBytes > MA_SIZE_MAX) {
54302             return MA_OUT_OF_MEMORY;    /* Too big. */
54303         }
54304
54305         pData = ma_malloc((size_t)allocationSizeInBytes, &pAudioBuffer->allocationCallbacks);   /* Safe cast to size_t. */
54306         if (pData == NULL) {
54307             return MA_OUT_OF_MEMORY;
54308         }
54309
54310         if (pConfig->pData != NULL) {
54311             ma_copy_pcm_frames(pData, pConfig->pData, pConfig->sizeInFrames, pConfig->format, pConfig->channels);
54312         } else {
54313             ma_silence_pcm_frames(pData, pConfig->sizeInFrames, pConfig->format, pConfig->channels);
54314         }
54315
54316         ma_audio_buffer_ref_set_data(&pAudioBuffer->ref, pData, pConfig->sizeInFrames);
54317         pAudioBuffer->ownsData = MA_TRUE;
54318     } else {
54319         ma_audio_buffer_ref_set_data(&pAudioBuffer->ref, pConfig->pData, pConfig->sizeInFrames);
54320         pAudioBuffer->ownsData = MA_FALSE;
54321     }
54322
54323     return MA_SUCCESS;
54324 }
54325
54326 static void ma_audio_buffer_uninit_ex(ma_audio_buffer* pAudioBuffer, ma_bool32 doFree)
54327 {
54328     if (pAudioBuffer == NULL) {
54329         return;
54330     }
54331
54332     if (pAudioBuffer->ownsData && pAudioBuffer->ref.pData != &pAudioBuffer->_pExtraData[0]) {
54333         ma_free((void*)pAudioBuffer->ref.pData, &pAudioBuffer->allocationCallbacks);    /* Naugty const cast, but OK in this case since we've guarded it with the ownsData check. */
54334     }
54335
54336     if (doFree) {
54337         ma_free(pAudioBuffer, &pAudioBuffer->allocationCallbacks);
54338     }
54339
54340     ma_audio_buffer_ref_uninit(&pAudioBuffer->ref);
54341 }
54342
54343 MA_API ma_result ma_audio_buffer_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer)
54344 {
54345     return ma_audio_buffer_init_ex(pConfig, MA_FALSE, pAudioBuffer);
54346 }
54347
54348 MA_API ma_result ma_audio_buffer_init_copy(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer)
54349 {
54350     return ma_audio_buffer_init_ex(pConfig, MA_TRUE, pAudioBuffer);
54351 }
54352
54353 MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer** ppAudioBuffer)
54354 {
54355     ma_result result;
54356     ma_audio_buffer* pAudioBuffer;
54357     ma_audio_buffer_config innerConfig; /* We'll be making some changes to the config, so need to make a copy. */
54358     ma_uint64 allocationSizeInBytes;
54359
54360     if (ppAudioBuffer == NULL) {
54361         return MA_INVALID_ARGS;
54362     }
54363
54364     *ppAudioBuffer = NULL;  /* Safety. */
54365
54366     if (pConfig == NULL) {
54367         return MA_INVALID_ARGS;
54368     }
54369
54370     innerConfig = *pConfig;
54371     ma_allocation_callbacks_init_copy(&innerConfig.allocationCallbacks, &pConfig->allocationCallbacks);
54372
54373     allocationSizeInBytes = sizeof(*pAudioBuffer) - sizeof(pAudioBuffer->_pExtraData) + (pConfig->sizeInFrames * ma_get_bytes_per_frame(pConfig->format, pConfig->channels));
54374     if (allocationSizeInBytes > MA_SIZE_MAX) {
54375         return MA_OUT_OF_MEMORY;    /* Too big. */
54376     }
54377
54378     pAudioBuffer = (ma_audio_buffer*)ma_malloc((size_t)allocationSizeInBytes, &innerConfig.allocationCallbacks);  /* Safe cast to size_t. */
54379     if (pAudioBuffer == NULL) {
54380         return MA_OUT_OF_MEMORY;
54381     }
54382
54383     if (pConfig->pData != NULL) {
54384         ma_copy_pcm_frames(&pAudioBuffer->_pExtraData[0], pConfig->pData, pConfig->sizeInFrames, pConfig->format, pConfig->channels);
54385     } else {
54386         ma_silence_pcm_frames(&pAudioBuffer->_pExtraData[0], pConfig->sizeInFrames, pConfig->format, pConfig->channels);
54387     }
54388
54389     innerConfig.pData = &pAudioBuffer->_pExtraData[0];
54390
54391     result = ma_audio_buffer_init_ex(&innerConfig, MA_FALSE, pAudioBuffer);
54392     if (result != MA_SUCCESS) {
54393         ma_free(pAudioBuffer, &innerConfig.allocationCallbacks);
54394         return result;
54395     }
54396
54397     *ppAudioBuffer = pAudioBuffer;
54398
54399     return MA_SUCCESS;
54400 }
54401
54402 MA_API void ma_audio_buffer_uninit(ma_audio_buffer* pAudioBuffer)
54403 {
54404     ma_audio_buffer_uninit_ex(pAudioBuffer, MA_FALSE);
54405 }
54406
54407 MA_API void ma_audio_buffer_uninit_and_free(ma_audio_buffer* pAudioBuffer)
54408 {
54409     ma_audio_buffer_uninit_ex(pAudioBuffer, MA_TRUE);
54410 }
54411
54412 MA_API ma_uint64 ma_audio_buffer_read_pcm_frames(ma_audio_buffer* pAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop)
54413 {
54414     if (pAudioBuffer == NULL) {
54415         return 0;
54416     }
54417
54418     return ma_audio_buffer_ref_read_pcm_frames(&pAudioBuffer->ref, pFramesOut, frameCount, loop);
54419 }
54420
54421 MA_API ma_result ma_audio_buffer_seek_to_pcm_frame(ma_audio_buffer* pAudioBuffer, ma_uint64 frameIndex)
54422 {
54423     if (pAudioBuffer == NULL) {
54424         return MA_INVALID_ARGS;
54425     }
54426
54427     return ma_audio_buffer_ref_seek_to_pcm_frame(&pAudioBuffer->ref, frameIndex);
54428 }
54429
54430 MA_API ma_result ma_audio_buffer_map(ma_audio_buffer* pAudioBuffer, void** ppFramesOut, ma_uint64* pFrameCount)
54431 {
54432     if (ppFramesOut != NULL) {
54433         *ppFramesOut = NULL;    /* Safety. */
54434     }
54435
54436     if (pAudioBuffer == NULL) {
54437         if (pFrameCount != NULL) {
54438             *pFrameCount = 0;
54439         }
54440
54441         return MA_INVALID_ARGS;
54442     }
54443
54444     return ma_audio_buffer_ref_map(&pAudioBuffer->ref, ppFramesOut, pFrameCount);
54445 }
54446
54447 MA_API ma_result ma_audio_buffer_unmap(ma_audio_buffer* pAudioBuffer, ma_uint64 frameCount)
54448 {
54449     if (pAudioBuffer == NULL) {
54450         return MA_INVALID_ARGS;
54451     }
54452
54453     return ma_audio_buffer_ref_unmap(&pAudioBuffer->ref, frameCount);
54454 }
54455
54456 MA_API ma_bool32 ma_audio_buffer_at_end(const ma_audio_buffer* pAudioBuffer)
54457 {
54458     if (pAudioBuffer == NULL) {
54459         return MA_FALSE;
54460     }
54461
54462     return ma_audio_buffer_ref_at_end(&pAudioBuffer->ref);
54463 }
54464
54465 MA_API ma_result ma_audio_buffer_get_cursor_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pCursor)
54466 {
54467     if (pAudioBuffer == NULL) {
54468         return MA_INVALID_ARGS;
54469     }
54470
54471     return ma_audio_buffer_ref_get_cursor_in_pcm_frames(&pAudioBuffer->ref, pCursor);
54472 }
54473
54474 MA_API ma_result ma_audio_buffer_get_length_in_pcm_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pLength)
54475 {
54476     if (pAudioBuffer == NULL) {
54477         return MA_INVALID_ARGS;
54478     }
54479
54480     return ma_audio_buffer_ref_get_length_in_pcm_frames(&pAudioBuffer->ref, pLength);
54481 }
54482
54483 MA_API ma_result ma_audio_buffer_get_available_frames(const ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames)
54484 {
54485     if (pAvailableFrames == NULL) {
54486         return MA_INVALID_ARGS;
54487     }
54488
54489     *pAvailableFrames = 0;
54490
54491     if (pAudioBuffer == NULL) {
54492         return MA_INVALID_ARGS;
54493     }
54494
54495     return ma_audio_buffer_ref_get_available_frames(&pAudioBuffer->ref, pAvailableFrames);
54496 }
54497
54498
54499
54500
54501
54502 MA_API ma_result ma_paged_audio_buffer_data_init(ma_format format, ma_uint32 channels, ma_paged_audio_buffer_data* pData)
54503 {
54504     if (pData == NULL) {
54505         return MA_INVALID_ARGS;
54506     }
54507
54508     MA_ZERO_OBJECT(pData);
54509
54510     pData->format   = format;
54511     pData->channels = channels;
54512     pData->pTail    = &pData->head;
54513
54514     return MA_SUCCESS;
54515 }
54516
54517 MA_API void ma_paged_audio_buffer_data_uninit(ma_paged_audio_buffer_data* pData, const ma_allocation_callbacks* pAllocationCallbacks)
54518 {
54519     ma_paged_audio_buffer_page* pPage;
54520
54521     if (pData == NULL) {
54522         return;
54523     }
54524
54525     /* All pages need to be freed. */
54526     pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pData->head.pNext);
54527     while (pPage != NULL) {
54528         ma_paged_audio_buffer_page* pNext = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPage->pNext);
54529
54530         ma_free(pPage, pAllocationCallbacks);
54531         pPage = pNext;
54532     }
54533 }
54534
54535 MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_head(ma_paged_audio_buffer_data* pData)
54536 {
54537     if (pData == NULL) {
54538         return NULL;
54539     }
54540
54541     return &pData->head;
54542 }
54543
54544 MA_API ma_paged_audio_buffer_page* ma_paged_audio_buffer_data_get_tail(ma_paged_audio_buffer_data* pData)
54545 {
54546     if (pData == NULL) {
54547         return NULL;
54548     }
54549
54550     return pData->pTail;
54551 }
54552
54553 MA_API ma_result ma_paged_audio_buffer_data_get_length_in_pcm_frames(ma_paged_audio_buffer_data* pData, ma_uint64* pLength)
54554 {
54555     ma_paged_audio_buffer_page* pPage;
54556
54557     if (pLength == NULL) {
54558         return MA_INVALID_ARGS;
54559     }
54560
54561     *pLength = 0;
54562
54563     if (pData == NULL) {
54564         return MA_INVALID_ARGS;
54565     }
54566
54567     /* Calculate the length from the linked list. */
54568     for (pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pData->head.pNext); pPage != NULL; pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPage->pNext)) {
54569         *pLength += pPage->sizeInFrames;
54570     }
54571
54572     return MA_SUCCESS;
54573 }
54574
54575 MA_API ma_result ma_paged_audio_buffer_data_allocate_page(ma_paged_audio_buffer_data* pData, ma_uint64 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks, ma_paged_audio_buffer_page** ppPage)
54576 {
54577     ma_paged_audio_buffer_page* pPage;
54578     ma_uint64 allocationSize;
54579
54580     if (ppPage == NULL) {
54581         return MA_INVALID_ARGS;
54582     }
54583
54584     *ppPage = NULL;
54585
54586     if (pData == NULL) {
54587         return MA_INVALID_ARGS;
54588     }
54589
54590     allocationSize = sizeof(*pPage) + (pageSizeInFrames * ma_get_bytes_per_frame(pData->format, pData->channels));
54591     if (allocationSize > MA_SIZE_MAX) {
54592         return MA_OUT_OF_MEMORY;    /* Too big. */
54593     }
54594
54595     pPage = (ma_paged_audio_buffer_page*)ma_malloc((size_t)allocationSize, pAllocationCallbacks);   /* Safe cast to size_t. */
54596     if (pPage == NULL) {
54597         return MA_OUT_OF_MEMORY;
54598     }
54599
54600     pPage->pNext = NULL;
54601     pPage->sizeInFrames = pageSizeInFrames;
54602
54603     if (pInitialData != NULL) {
54604         ma_copy_pcm_frames(pPage->pAudioData, pInitialData, pageSizeInFrames, pData->format, pData->channels);
54605     }
54606
54607     *ppPage = pPage;
54608
54609     return MA_SUCCESS;
54610 }
54611
54612 MA_API ma_result ma_paged_audio_buffer_data_free_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage, const ma_allocation_callbacks* pAllocationCallbacks)
54613 {
54614     if (pData == NULL || pPage == NULL) {
54615         return MA_INVALID_ARGS;
54616     }
54617
54618     /* It's assumed the page is not attached to the list. */
54619     ma_free(pPage, pAllocationCallbacks);
54620
54621     return MA_SUCCESS;
54622 }
54623
54624 MA_API ma_result ma_paged_audio_buffer_data_append_page(ma_paged_audio_buffer_data* pData, ma_paged_audio_buffer_page* pPage)
54625 {
54626     if (pData == NULL || pPage == NULL) {
54627         return MA_INVALID_ARGS;
54628     }
54629
54630     /* This function assumes the page has been filled with audio data by this point. As soon as we append, the page will be available for reading. */
54631
54632     /* First thing to do is update the tail. */
54633     for (;;) {
54634         ma_paged_audio_buffer_page* pOldTail = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pData->pTail);
54635         ma_paged_audio_buffer_page* pNewTail = pPage;
54636
54637         if (c89atomic_compare_exchange_weak_ptr((volatile void**)&pData->pTail, (void**)&pOldTail, pNewTail)) {
54638             /* Here is where we append the page to the list. After this, the page is attached to the list and ready to be read from. */
54639             c89atomic_exchange_ptr(&pOldTail->pNext, pPage);
54640             break;  /* Done. */
54641         }
54642     }
54643
54644     return MA_SUCCESS;
54645 }
54646
54647 MA_API ma_result ma_paged_audio_buffer_data_allocate_and_append_page(ma_paged_audio_buffer_data* pData, ma_uint32 pageSizeInFrames, const void* pInitialData, const ma_allocation_callbacks* pAllocationCallbacks)
54648 {
54649     ma_result result;
54650     ma_paged_audio_buffer_page* pPage;
54651
54652     result = ma_paged_audio_buffer_data_allocate_page(pData, pageSizeInFrames, pInitialData, pAllocationCallbacks, &pPage);
54653     if (result != MA_SUCCESS) {
54654         return result;
54655     }
54656
54657     return ma_paged_audio_buffer_data_append_page(pData, pPage);    /* <-- Should never fail. */
54658 }
54659
54660
54661 MA_API ma_paged_audio_buffer_config ma_paged_audio_buffer_config_init(ma_paged_audio_buffer_data* pData)
54662 {
54663     ma_paged_audio_buffer_config config;
54664
54665     MA_ZERO_OBJECT(&config);
54666     config.pData = pData;
54667
54668     return config;
54669 }
54670
54671
54672 static ma_result ma_paged_audio_buffer__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
54673 {
54674     return ma_paged_audio_buffer_read_pcm_frames((ma_paged_audio_buffer*)pDataSource, pFramesOut, frameCount, pFramesRead);
54675 }
54676
54677 static ma_result ma_paged_audio_buffer__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
54678 {
54679     return ma_paged_audio_buffer_seek_to_pcm_frame((ma_paged_audio_buffer*)pDataSource, frameIndex);
54680 }
54681
54682 static ma_result ma_paged_audio_buffer__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
54683 {
54684     ma_paged_audio_buffer* pPagedAudioBuffer = (ma_paged_audio_buffer*)pDataSource;
54685
54686     *pFormat     = pPagedAudioBuffer->pData->format;
54687     *pChannels   = pPagedAudioBuffer->pData->channels;
54688     *pSampleRate = 0;   /* There is no notion of a sample rate with audio buffers. */
54689     ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pPagedAudioBuffer->pData->channels);
54690
54691     return MA_SUCCESS;
54692 }
54693
54694 static ma_result ma_paged_audio_buffer__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
54695 {
54696     return ma_paged_audio_buffer_get_cursor_in_pcm_frames((ma_paged_audio_buffer*)pDataSource, pCursor);
54697 }
54698
54699 static ma_result ma_paged_audio_buffer__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
54700 {
54701     return ma_paged_audio_buffer_get_length_in_pcm_frames((ma_paged_audio_buffer*)pDataSource, pLength);
54702 }
54703
54704 static ma_data_source_vtable g_ma_paged_audio_buffer_data_source_vtable =
54705 {
54706     ma_paged_audio_buffer__data_source_on_read,
54707     ma_paged_audio_buffer__data_source_on_seek,
54708     ma_paged_audio_buffer__data_source_on_get_data_format,
54709     ma_paged_audio_buffer__data_source_on_get_cursor,
54710     ma_paged_audio_buffer__data_source_on_get_length,
54711     NULL,   /* onSetLooping */
54712     0
54713 };
54714
54715 MA_API ma_result ma_paged_audio_buffer_init(const ma_paged_audio_buffer_config* pConfig, ma_paged_audio_buffer* pPagedAudioBuffer)
54716 {
54717     ma_result result;
54718     ma_data_source_config dataSourceConfig;
54719
54720     if (pPagedAudioBuffer == NULL) {
54721         return MA_INVALID_ARGS;
54722     }
54723
54724     MA_ZERO_OBJECT(pPagedAudioBuffer);
54725
54726     /* A config is required for the format and channel count. */
54727     if (pConfig == NULL) {
54728         return MA_INVALID_ARGS;
54729     }
54730
54731     if (pConfig->pData == NULL) {
54732         return MA_INVALID_ARGS; /* No underlying data specified. */
54733     }
54734
54735     dataSourceConfig = ma_data_source_config_init();
54736     dataSourceConfig.vtable = &g_ma_paged_audio_buffer_data_source_vtable;
54737
54738     result = ma_data_source_init(&dataSourceConfig, &pPagedAudioBuffer->ds);
54739     if (result != MA_SUCCESS) {
54740         return result;
54741     }
54742
54743     pPagedAudioBuffer->pData          = pConfig->pData;
54744     pPagedAudioBuffer->pCurrent       = ma_paged_audio_buffer_data_get_head(pConfig->pData);
54745     pPagedAudioBuffer->relativeCursor = 0;
54746     pPagedAudioBuffer->absoluteCursor = 0;
54747
54748     return MA_SUCCESS;
54749 }
54750
54751 MA_API void ma_paged_audio_buffer_uninit(ma_paged_audio_buffer* pPagedAudioBuffer)
54752 {
54753     if (pPagedAudioBuffer == NULL) {
54754         return;
54755     }
54756
54757     /* Nothing to do. The data needs to be deleted separately. */
54758 }
54759
54760 MA_API ma_result ma_paged_audio_buffer_read_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
54761 {
54762     ma_result result = MA_SUCCESS;
54763     ma_uint64 totalFramesRead = 0;
54764     ma_format format;
54765     ma_uint32 channels;
54766
54767     if (pPagedAudioBuffer == NULL) {
54768         return MA_INVALID_ARGS;
54769     }
54770
54771     format   = pPagedAudioBuffer->pData->format;
54772     channels = pPagedAudioBuffer->pData->channels;
54773
54774     while (totalFramesRead < frameCount) {
54775         /* Read from the current page. The buffer should never be in a state where this is NULL. */
54776         ma_uint64 framesRemainingInCurrentPage;
54777         ma_uint64 framesRemainingToRead = frameCount - totalFramesRead;
54778         ma_uint64 framesToReadThisIteration;
54779
54780         MA_ASSERT(pPagedAudioBuffer->pCurrent != NULL);
54781
54782         framesRemainingInCurrentPage = pPagedAudioBuffer->pCurrent->sizeInFrames - pPagedAudioBuffer->relativeCursor;
54783
54784         framesToReadThisIteration = ma_min(framesRemainingInCurrentPage, framesRemainingToRead);
54785         ma_copy_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels), ma_offset_pcm_frames_ptr(pPagedAudioBuffer->pCurrent->pAudioData, pPagedAudioBuffer->relativeCursor, format, channels), framesToReadThisIteration, format, channels);
54786         totalFramesRead += framesToReadThisIteration;
54787
54788         pPagedAudioBuffer->absoluteCursor += framesToReadThisIteration;
54789         pPagedAudioBuffer->relativeCursor += framesToReadThisIteration;
54790
54791         /* Move to the next page if necessary. If there's no more pages, we need to return MA_AT_END. */
54792         MA_ASSERT(pPagedAudioBuffer->relativeCursor <= pPagedAudioBuffer->pCurrent->sizeInFrames);
54793
54794         if (pPagedAudioBuffer->relativeCursor == pPagedAudioBuffer->pCurrent->sizeInFrames) {
54795             /* We reached the end of the page. Need to move to the next. If there's no more pages, we're done. */
54796             ma_paged_audio_buffer_page* pNext = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPagedAudioBuffer->pCurrent->pNext);
54797             if (pNext == NULL) {
54798                 result = MA_AT_END;
54799                 break;  /* We've reached the end. */
54800             } else {
54801                 pPagedAudioBuffer->pCurrent       = pNext;
54802                 pPagedAudioBuffer->relativeCursor = 0;
54803             }
54804         }
54805     }
54806
54807     if (pFramesRead != NULL) {
54808         *pFramesRead = totalFramesRead;
54809     }
54810
54811     return result;
54812 }
54813
54814 MA_API ma_result ma_paged_audio_buffer_seek_to_pcm_frame(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64 frameIndex)
54815 {
54816     if (pPagedAudioBuffer == NULL) {
54817         return MA_INVALID_ARGS;
54818     }
54819
54820     if (frameIndex == pPagedAudioBuffer->absoluteCursor) {
54821         return MA_SUCCESS;  /* Nothing to do. */
54822     }
54823
54824     if (frameIndex < pPagedAudioBuffer->absoluteCursor) {
54825         /* Moving backwards. Need to move the cursor back to the start, and then move forward. */
54826         pPagedAudioBuffer->pCurrent       = ma_paged_audio_buffer_data_get_head(pPagedAudioBuffer->pData);
54827         pPagedAudioBuffer->absoluteCursor = 0;
54828         pPagedAudioBuffer->relativeCursor = 0;
54829
54830         /* Fall through to the forward seeking section below. */
54831     }
54832
54833     if (frameIndex > pPagedAudioBuffer->absoluteCursor) {
54834         /* Moving forward. */
54835         ma_paged_audio_buffer_page* pPage;
54836         ma_uint64 runningCursor = 0;
54837
54838         for (pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&ma_paged_audio_buffer_data_get_head(pPagedAudioBuffer->pData)->pNext); pPage != NULL; pPage = (ma_paged_audio_buffer_page*)c89atomic_load_ptr(&pPage->pNext)) {
54839             ma_uint64 pageRangeBeg = runningCursor;
54840             ma_uint64 pageRangeEnd = pageRangeBeg + pPage->sizeInFrames;
54841
54842             if (frameIndex >= pageRangeBeg) {
54843                 if (frameIndex < pageRangeEnd || (frameIndex == pageRangeEnd && pPage == (ma_paged_audio_buffer_page*)c89atomic_load_ptr(ma_paged_audio_buffer_data_get_tail(pPagedAudioBuffer->pData)))) {  /* A small edge case - allow seeking to the very end of the buffer. */
54844                     /* We found the page. */
54845                     pPagedAudioBuffer->pCurrent       = pPage;
54846                     pPagedAudioBuffer->absoluteCursor = frameIndex;
54847                     pPagedAudioBuffer->relativeCursor = frameIndex - pageRangeBeg;
54848                     return MA_SUCCESS;
54849                 }
54850             }
54851
54852             runningCursor = pageRangeEnd;
54853         }
54854
54855         /* Getting here means we tried seeking too far forward. Don't change any state. */
54856         return MA_BAD_SEEK;
54857     }
54858
54859     return MA_SUCCESS;
54860 }
54861
54862 MA_API ma_result ma_paged_audio_buffer_get_cursor_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pCursor)
54863 {
54864     if (pCursor == NULL) {
54865         return MA_INVALID_ARGS;
54866     }
54867
54868     *pCursor = 0;   /* Safety. */
54869
54870     if (pPagedAudioBuffer == NULL) {
54871         return MA_INVALID_ARGS;
54872     }
54873
54874     *pCursor = pPagedAudioBuffer->absoluteCursor;
54875
54876     return MA_SUCCESS;
54877 }
54878
54879 MA_API ma_result ma_paged_audio_buffer_get_length_in_pcm_frames(ma_paged_audio_buffer* pPagedAudioBuffer, ma_uint64* pLength)
54880 {
54881     return ma_paged_audio_buffer_data_get_length_in_pcm_frames(pPagedAudioBuffer->pData, pLength);
54882 }
54883
54884
54885
54886 /**************************************************************************************************************************************************************
54887
54888 VFS
54889
54890 **************************************************************************************************************************************************************/
54891 MA_API ma_result ma_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
54892 {
54893     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
54894
54895     if (pFile == NULL) {
54896         return MA_INVALID_ARGS;
54897     }
54898
54899     *pFile = NULL;
54900
54901     if (pVFS == NULL || pFilePath == NULL || openMode == 0) {
54902         return MA_INVALID_ARGS;
54903     }
54904
54905     if (pCallbacks->onOpen == NULL) {
54906         return MA_NOT_IMPLEMENTED;
54907     }
54908
54909     return pCallbacks->onOpen(pVFS, pFilePath, openMode, pFile);
54910 }
54911
54912 MA_API ma_result ma_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
54913 {
54914     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
54915
54916     if (pFile == NULL) {
54917         return MA_INVALID_ARGS;
54918     }
54919
54920     *pFile = NULL;
54921
54922     if (pVFS == NULL || pFilePath == NULL || openMode == 0) {
54923         return MA_INVALID_ARGS;
54924     }
54925
54926     if (pCallbacks->onOpenW == NULL) {
54927         return MA_NOT_IMPLEMENTED;
54928     }
54929
54930     return pCallbacks->onOpenW(pVFS, pFilePath, openMode, pFile);
54931 }
54932
54933 MA_API ma_result ma_vfs_close(ma_vfs* pVFS, ma_vfs_file file)
54934 {
54935     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
54936
54937     if (pVFS == NULL || file == NULL) {
54938         return MA_INVALID_ARGS;
54939     }
54940
54941     if (pCallbacks->onClose == NULL) {
54942         return MA_NOT_IMPLEMENTED;
54943     }
54944
54945     return pCallbacks->onClose(pVFS, file);
54946 }
54947
54948 MA_API ma_result ma_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead)
54949 {
54950     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
54951     ma_result result;
54952     size_t bytesRead;
54953
54954     if (pBytesRead != NULL) {
54955         *pBytesRead = 0;
54956     }
54957
54958     if (pVFS == NULL || file == NULL || pDst == NULL) {
54959         return MA_INVALID_ARGS;
54960     }
54961
54962     if (pCallbacks->onRead == NULL) {
54963         return MA_NOT_IMPLEMENTED;
54964     }
54965
54966     result = pCallbacks->onRead(pVFS, file, pDst, sizeInBytes, &bytesRead);
54967
54968     if (pBytesRead != NULL) {
54969         *pBytesRead = bytesRead;
54970     }
54971
54972     if (result == MA_SUCCESS && bytesRead == 0 && sizeInBytes > 0) {
54973         result  = MA_AT_END;
54974     }
54975
54976     return result;
54977 }
54978
54979 MA_API ma_result ma_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten)
54980 {
54981     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
54982
54983     if (pBytesWritten != NULL) {
54984         *pBytesWritten = 0;
54985     }
54986
54987     if (pVFS == NULL || file == NULL || pSrc == NULL) {
54988         return MA_INVALID_ARGS;
54989     }
54990
54991     if (pCallbacks->onWrite == NULL) {
54992         return MA_NOT_IMPLEMENTED;
54993     }
54994
54995     return pCallbacks->onWrite(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
54996 }
54997
54998 MA_API ma_result ma_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
54999 {
55000     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
55001
55002     if (pVFS == NULL || file == NULL) {
55003         return MA_INVALID_ARGS;
55004     }
55005
55006     if (pCallbacks->onSeek == NULL) {
55007         return MA_NOT_IMPLEMENTED;
55008     }
55009
55010     return pCallbacks->onSeek(pVFS, file, offset, origin);
55011 }
55012
55013 MA_API ma_result ma_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
55014 {
55015     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
55016
55017     if (pCursor == NULL) {
55018         return MA_INVALID_ARGS;
55019     }
55020
55021     *pCursor = 0;
55022
55023     if (pVFS == NULL || file == NULL) {
55024         return MA_INVALID_ARGS;
55025     }
55026
55027     if (pCallbacks->onTell == NULL) {
55028         return MA_NOT_IMPLEMENTED;
55029     }
55030
55031     return pCallbacks->onTell(pVFS, file, pCursor);
55032 }
55033
55034 MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
55035 {
55036     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
55037
55038     if (pInfo == NULL) {
55039         return MA_INVALID_ARGS;
55040     }
55041
55042     MA_ZERO_OBJECT(pInfo);
55043
55044     if (pVFS == NULL || file == NULL) {
55045         return MA_INVALID_ARGS;
55046     }
55047
55048     if (pCallbacks->onInfo == NULL) {
55049         return MA_NOT_IMPLEMENTED;
55050     }
55051
55052     return pCallbacks->onInfo(pVFS, file, pInfo);
55053 }
55054
55055
55056 static ma_result ma_vfs_open_and_read_file_ex(ma_vfs* pVFS, const char* pFilePath, const wchar_t* pFilePathW, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks)
55057 {
55058     ma_result result;
55059     ma_vfs_file file;
55060     ma_file_info info;
55061     void* pData;
55062     size_t bytesRead;
55063
55064     if (ppData != NULL) {
55065         *ppData = NULL;
55066     }
55067     if (pSize != NULL) {
55068         *pSize = 0;
55069     }
55070
55071     if (ppData == NULL) {
55072         return MA_INVALID_ARGS;
55073     }
55074
55075     if (pFilePath != NULL) {
55076         result = ma_vfs_open(pVFS, pFilePath, MA_OPEN_MODE_READ, &file);
55077     } else {
55078         result = ma_vfs_open_w(pVFS, pFilePathW, MA_OPEN_MODE_READ, &file);
55079     }
55080     if (result != MA_SUCCESS) {
55081         return result;
55082     }
55083
55084     result = ma_vfs_info(pVFS, file, &info);
55085     if (result != MA_SUCCESS) {
55086         ma_vfs_close(pVFS, file);
55087         return result;
55088     }
55089
55090     if (info.sizeInBytes > MA_SIZE_MAX) {
55091         ma_vfs_close(pVFS, file);
55092         return MA_TOO_BIG;
55093     }
55094
55095     pData = ma_malloc((size_t)info.sizeInBytes, pAllocationCallbacks);  /* Safe cast. */
55096     if (pData == NULL) {
55097         ma_vfs_close(pVFS, file);
55098         return result;
55099     }
55100
55101     result = ma_vfs_read(pVFS, file, pData, (size_t)info.sizeInBytes, &bytesRead);  /* Safe cast. */
55102     ma_vfs_close(pVFS, file);
55103
55104     if (result != MA_SUCCESS) {
55105         ma_free(pData, pAllocationCallbacks);
55106         return result;
55107     }
55108
55109     if (pSize != NULL) {
55110         *pSize = bytesRead;
55111     }
55112
55113     MA_ASSERT(ppData != NULL);
55114     *ppData = pData;
55115
55116     return MA_SUCCESS;
55117 }
55118
55119 MA_API ma_result ma_vfs_open_and_read_file(ma_vfs* pVFS, const char* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks)
55120 {
55121     return ma_vfs_open_and_read_file_ex(pVFS, pFilePath, NULL, ppData, pSize, pAllocationCallbacks);
55122 }
55123
55124 MA_API ma_result ma_vfs_open_and_read_file_w(ma_vfs* pVFS, const wchar_t* pFilePath, void** ppData, size_t* pSize, const ma_allocation_callbacks* pAllocationCallbacks)
55125 {
55126     return ma_vfs_open_and_read_file_ex(pVFS, NULL, pFilePath, ppData, pSize, pAllocationCallbacks);
55127 }
55128
55129
55130 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO)
55131 static void ma_default_vfs__get_open_settings_win32(ma_uint32 openMode, DWORD* pDesiredAccess, DWORD* pShareMode, DWORD* pCreationDisposition)
55132 {
55133     *pDesiredAccess = 0;
55134     if ((openMode & MA_OPEN_MODE_READ) != 0) {
55135         *pDesiredAccess |= GENERIC_READ;
55136     }
55137     if ((openMode & MA_OPEN_MODE_WRITE) != 0) {
55138         *pDesiredAccess |= GENERIC_WRITE;
55139     }
55140
55141     *pShareMode = 0;
55142     if ((openMode & MA_OPEN_MODE_READ) != 0) {
55143         *pShareMode |= FILE_SHARE_READ;
55144     }
55145
55146     if ((openMode & MA_OPEN_MODE_WRITE) != 0) {
55147         *pCreationDisposition = CREATE_ALWAYS;  /* Opening in write mode. Truncate. */
55148     } else {
55149         *pCreationDisposition = OPEN_EXISTING;  /* Opening in read mode. File must exist. */
55150     }
55151 }
55152
55153 static ma_result ma_default_vfs_open__win32(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
55154 {
55155     HANDLE hFile;
55156     DWORD dwDesiredAccess;
55157     DWORD dwShareMode;
55158     DWORD dwCreationDisposition;
55159
55160     (void)pVFS;
55161
55162     ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition);
55163
55164     hFile = CreateFileA(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
55165     if (hFile == INVALID_HANDLE_VALUE) {
55166         return ma_result_from_GetLastError(GetLastError());
55167     }
55168
55169     *pFile = hFile;
55170     return MA_SUCCESS;
55171 }
55172
55173 static ma_result ma_default_vfs_open_w__win32(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
55174 {
55175     HANDLE hFile;
55176     DWORD dwDesiredAccess;
55177     DWORD dwShareMode;
55178     DWORD dwCreationDisposition;
55179
55180     (void)pVFS;
55181
55182     ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition);
55183
55184     hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
55185     if (hFile == INVALID_HANDLE_VALUE) {
55186         return ma_result_from_GetLastError(GetLastError());
55187     }
55188
55189     *pFile = hFile;
55190     return MA_SUCCESS;
55191 }
55192
55193 static ma_result ma_default_vfs_close__win32(ma_vfs* pVFS, ma_vfs_file file)
55194 {
55195     (void)pVFS;
55196
55197     if (CloseHandle((HANDLE)file) == 0) {
55198         return ma_result_from_GetLastError(GetLastError());
55199     }
55200
55201     return MA_SUCCESS;
55202 }
55203
55204
55205 static ma_result ma_default_vfs_read__win32(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead)
55206 {
55207     ma_result result = MA_SUCCESS;
55208     size_t totalBytesRead;
55209
55210     (void)pVFS;
55211
55212     totalBytesRead = 0;
55213     while (totalBytesRead < sizeInBytes) {
55214         size_t bytesRemaining;
55215         DWORD bytesToRead;
55216         DWORD bytesRead;
55217         BOOL readResult;
55218
55219         bytesRemaining = sizeInBytes - totalBytesRead;
55220         if (bytesRemaining >= 0xFFFFFFFF) {
55221             bytesToRead = 0xFFFFFFFF;
55222         } else {
55223             bytesToRead = (DWORD)bytesRemaining;
55224         }
55225
55226         readResult = ReadFile((HANDLE)file, ma_offset_ptr(pDst, totalBytesRead), bytesToRead, &bytesRead, NULL);
55227         if (readResult == 1 && bytesRead == 0) {
55228             result = MA_AT_END;
55229             break;  /* EOF */
55230         }
55231
55232         totalBytesRead += bytesRead;
55233
55234         if (bytesRead < bytesToRead) {
55235             break;  /* EOF */
55236         }
55237
55238         if (readResult == 0) {
55239             result = ma_result_from_GetLastError(GetLastError());
55240             break;
55241         }
55242     }
55243
55244     if (pBytesRead != NULL) {
55245         *pBytesRead = totalBytesRead;
55246     }
55247
55248     return result;
55249 }
55250
55251 static ma_result ma_default_vfs_write__win32(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten)
55252 {
55253     ma_result result = MA_SUCCESS;
55254     size_t totalBytesWritten;
55255
55256     (void)pVFS;
55257
55258     totalBytesWritten = 0;
55259     while (totalBytesWritten < sizeInBytes) {
55260         size_t bytesRemaining;
55261         DWORD bytesToWrite;
55262         DWORD bytesWritten;
55263         BOOL writeResult;
55264
55265         bytesRemaining = sizeInBytes - totalBytesWritten;
55266         if (bytesRemaining >= 0xFFFFFFFF) {
55267             bytesToWrite = 0xFFFFFFFF;
55268         } else {
55269             bytesToWrite = (DWORD)bytesRemaining;
55270         }
55271
55272         writeResult = WriteFile((HANDLE)file, ma_offset_ptr(pSrc, totalBytesWritten), bytesToWrite, &bytesWritten, NULL);
55273         totalBytesWritten += bytesWritten;
55274
55275         if (writeResult == 0) {
55276             result = ma_result_from_GetLastError(GetLastError());
55277             break;
55278         }
55279     }
55280
55281     if (pBytesWritten != NULL) {
55282         *pBytesWritten = totalBytesWritten;
55283     }
55284
55285     return result;
55286 }
55287
55288
55289 static ma_result ma_default_vfs_seek__win32(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
55290 {
55291     LARGE_INTEGER liDistanceToMove;
55292     DWORD dwMoveMethod;
55293     BOOL result;
55294
55295     (void)pVFS;
55296
55297     liDistanceToMove.QuadPart = offset;
55298
55299     /*  */ if (origin == ma_seek_origin_current) {
55300         dwMoveMethod = FILE_CURRENT;
55301     } else if (origin == ma_seek_origin_end) {
55302         dwMoveMethod = FILE_END;
55303     } else {
55304         dwMoveMethod = FILE_BEGIN;
55305     }
55306
55307 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__DMC__)
55308     /* No SetFilePointerEx() so restrict to 31 bits. */
55309     if (origin > 0x7FFFFFFF) {
55310         return MA_OUT_OF_RANGE;
55311     }
55312
55313     result = SetFilePointer((HANDLE)file, (LONG)liDistanceToMove.QuadPart, NULL, dwMoveMethod);
55314 #else
55315     result = SetFilePointerEx((HANDLE)file, liDistanceToMove, NULL, dwMoveMethod);
55316 #endif
55317     if (result == 0) {
55318         return ma_result_from_GetLastError(GetLastError());
55319     }
55320
55321     return MA_SUCCESS;
55322 }
55323
55324 static ma_result ma_default_vfs_tell__win32(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
55325 {
55326     LARGE_INTEGER liZero;
55327     LARGE_INTEGER liTell;
55328     BOOL result;
55329 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__DMC__)
55330     LONG tell;
55331 #endif
55332
55333     (void)pVFS;
55334
55335     liZero.QuadPart = 0;
55336
55337 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__DMC__)
55338     result = SetFilePointer((HANDLE)file, (LONG)liZero.QuadPart, &tell, FILE_CURRENT);
55339     liTell.QuadPart = tell;
55340 #else
55341     result = SetFilePointerEx((HANDLE)file, liZero, &liTell, FILE_CURRENT);
55342 #endif
55343     if (result == 0) {
55344         return ma_result_from_GetLastError(GetLastError());
55345     }
55346
55347     if (pCursor != NULL) {
55348         *pCursor = liTell.QuadPart;
55349     }
55350
55351     return MA_SUCCESS;
55352 }
55353
55354 static ma_result ma_default_vfs_info__win32(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
55355 {
55356     BY_HANDLE_FILE_INFORMATION fi;
55357     BOOL result;
55358
55359     (void)pVFS;
55360
55361     result = GetFileInformationByHandle((HANDLE)file, &fi);
55362     if (result == 0) {
55363         return ma_result_from_GetLastError(GetLastError());
55364     }
55365
55366     pInfo->sizeInBytes = ((ma_uint64)fi.nFileSizeHigh << 32) | ((ma_uint64)fi.nFileSizeLow);
55367
55368     return MA_SUCCESS;
55369 }
55370 #else
55371 static ma_result ma_default_vfs_open__stdio(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
55372 {
55373     ma_result result;
55374     FILE* pFileStd;
55375     const char* pOpenModeStr;
55376
55377     MA_ASSERT(pFilePath != NULL);
55378     MA_ASSERT(openMode  != 0);
55379     MA_ASSERT(pFile     != NULL);
55380
55381     (void)pVFS;
55382
55383     if ((openMode & MA_OPEN_MODE_READ) != 0) {
55384         if ((openMode & MA_OPEN_MODE_WRITE) != 0) {
55385             pOpenModeStr = "r+";
55386         } else {
55387             pOpenModeStr = "rb";
55388         }
55389     } else {
55390         pOpenModeStr = "wb";
55391     }
55392
55393     result = ma_fopen(&pFileStd, pFilePath, pOpenModeStr);
55394     if (result != MA_SUCCESS) {
55395         return result;
55396     }
55397
55398     *pFile = pFileStd;
55399
55400     return MA_SUCCESS;
55401 }
55402
55403 static ma_result ma_default_vfs_open_w__stdio(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
55404 {
55405     ma_result result;
55406     FILE* pFileStd;
55407     const wchar_t* pOpenModeStr;
55408
55409     MA_ASSERT(pFilePath != NULL);
55410     MA_ASSERT(openMode  != 0);
55411     MA_ASSERT(pFile     != NULL);
55412
55413     (void)pVFS;
55414
55415     if ((openMode & MA_OPEN_MODE_READ) != 0) {
55416         if ((openMode & MA_OPEN_MODE_WRITE) != 0) {
55417             pOpenModeStr = L"r+";
55418         } else {
55419             pOpenModeStr = L"rb";
55420         }
55421     } else {
55422         pOpenModeStr = L"wb";
55423     }
55424
55425     result = ma_wfopen(&pFileStd, pFilePath, pOpenModeStr, (pVFS != NULL) ? &((ma_default_vfs*)pVFS)->allocationCallbacks : NULL);
55426     if (result != MA_SUCCESS) {
55427         return result;
55428     }
55429
55430     *pFile = pFileStd;
55431
55432     return MA_SUCCESS;
55433 }
55434
55435 static ma_result ma_default_vfs_close__stdio(ma_vfs* pVFS, ma_vfs_file file)
55436 {
55437     MA_ASSERT(file != NULL);
55438
55439     (void)pVFS;
55440
55441     fclose((FILE*)file);
55442
55443     return MA_SUCCESS;
55444 }
55445
55446 static ma_result ma_default_vfs_read__stdio(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead)
55447 {
55448     size_t result;
55449
55450     MA_ASSERT(file != NULL);
55451     MA_ASSERT(pDst != NULL);
55452
55453     (void)pVFS;
55454
55455     result = fread(pDst, 1, sizeInBytes, (FILE*)file);
55456
55457     if (pBytesRead != NULL) {
55458         *pBytesRead = result;
55459     }
55460
55461     if (result != sizeInBytes) {
55462         if (result == 0 && feof((FILE*)file)) {
55463             return MA_AT_END;
55464         } else {
55465             return ma_result_from_errno(ferror((FILE*)file));
55466         }
55467     }
55468
55469     return MA_SUCCESS;
55470 }
55471
55472 static ma_result ma_default_vfs_write__stdio(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten)
55473 {
55474     size_t result;
55475
55476     MA_ASSERT(file != NULL);
55477     MA_ASSERT(pSrc != NULL);
55478
55479     (void)pVFS;
55480
55481     result = fwrite(pSrc, 1, sizeInBytes, (FILE*)file);
55482
55483     if (pBytesWritten != NULL) {
55484         *pBytesWritten = result;
55485     }
55486
55487     if (result != sizeInBytes) {
55488         return ma_result_from_errno(ferror((FILE*)file));
55489     }
55490
55491     return MA_SUCCESS;
55492 }
55493
55494 static ma_result ma_default_vfs_seek__stdio(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
55495 {
55496     int result;
55497     int whence;
55498
55499     MA_ASSERT(file != NULL);
55500
55501     (void)pVFS;
55502
55503     if (origin == ma_seek_origin_start) {
55504         whence = SEEK_SET;
55505     } else if (origin == ma_seek_origin_end) {
55506         whence = SEEK_END;
55507     } else {
55508         whence = SEEK_CUR;
55509     }
55510
55511 #if defined(_WIN32)
55512     #if defined(_MSC_VER) && _MSC_VER > 1200
55513         result = _fseeki64((FILE*)file, offset, whence);
55514     #else
55515         /* No _fseeki64() so restrict to 31 bits. */
55516         if (origin > 0x7FFFFFFF) {
55517             return MA_OUT_OF_RANGE;
55518         }
55519
55520         result = fseek((FILE*)file, (int)offset, whence);
55521     #endif
55522 #else
55523     result = fseek((FILE*)file, (long int)offset, whence);
55524 #endif
55525     if (result != 0) {
55526         return MA_ERROR;
55527     }
55528
55529     return MA_SUCCESS;
55530 }
55531
55532 static ma_result ma_default_vfs_tell__stdio(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
55533 {
55534     ma_int64 result;
55535
55536     MA_ASSERT(file    != NULL);
55537     MA_ASSERT(pCursor != NULL);
55538
55539     (void)pVFS;
55540
55541 #if defined(_WIN32)
55542     #if defined(_MSC_VER) && _MSC_VER > 1200
55543         result = _ftelli64((FILE*)file);
55544     #else
55545         result = ftell((FILE*)file);
55546     #endif
55547 #else
55548     result = ftell((FILE*)file);
55549 #endif
55550
55551     *pCursor = result;
55552
55553     return MA_SUCCESS;
55554 }
55555
55556 #if !defined(_MSC_VER) && !((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)) && !defined(MA_BSD)
55557 int fileno(FILE *stream);
55558 #endif
55559
55560 static ma_result ma_default_vfs_info__stdio(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
55561 {
55562     int fd;
55563     struct stat info;
55564
55565     MA_ASSERT(file  != NULL);
55566     MA_ASSERT(pInfo != NULL);
55567
55568     (void)pVFS;
55569
55570 #if defined(_MSC_VER)
55571     fd = _fileno((FILE*)file);
55572 #else
55573     fd =  fileno((FILE*)file);
55574 #endif
55575
55576     if (fstat(fd, &info) != 0) {
55577         return ma_result_from_errno(errno);
55578     }
55579
55580     pInfo->sizeInBytes = info.st_size;
55581
55582     return MA_SUCCESS;
55583 }
55584 #endif
55585
55586
55587 static ma_result ma_default_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
55588 {
55589     if (pFile == NULL) {
55590         return MA_INVALID_ARGS;
55591     }
55592
55593     *pFile = NULL;
55594
55595     if (pFilePath == NULL || openMode == 0) {
55596         return MA_INVALID_ARGS;
55597     }
55598
55599 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO)
55600     return ma_default_vfs_open__win32(pVFS, pFilePath, openMode, pFile);
55601 #else
55602     return ma_default_vfs_open__stdio(pVFS, pFilePath, openMode, pFile);
55603 #endif
55604 }
55605
55606 static ma_result ma_default_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
55607 {
55608     if (pFile == NULL) {
55609         return MA_INVALID_ARGS;
55610     }
55611
55612     *pFile = NULL;
55613
55614     if (pFilePath == NULL || openMode == 0) {
55615         return MA_INVALID_ARGS;
55616     }
55617
55618 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO)
55619     return ma_default_vfs_open_w__win32(pVFS, pFilePath, openMode, pFile);
55620 #else
55621     return ma_default_vfs_open_w__stdio(pVFS, pFilePath, openMode, pFile);
55622 #endif
55623 }
55624
55625 static ma_result ma_default_vfs_close(ma_vfs* pVFS, ma_vfs_file file)
55626 {
55627     if (file == NULL) {
55628         return MA_INVALID_ARGS;
55629     }
55630
55631 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO)
55632     return ma_default_vfs_close__win32(pVFS, file);
55633 #else
55634     return ma_default_vfs_close__stdio(pVFS, file);
55635 #endif
55636 }
55637
55638 static ma_result ma_default_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead)
55639 {
55640     if (pBytesRead != NULL) {
55641         *pBytesRead = 0;
55642     }
55643
55644     if (file == NULL || pDst == NULL) {
55645         return MA_INVALID_ARGS;
55646     }
55647
55648 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO)
55649     return ma_default_vfs_read__win32(pVFS, file, pDst, sizeInBytes, pBytesRead);
55650 #else
55651     return ma_default_vfs_read__stdio(pVFS, file, pDst, sizeInBytes, pBytesRead);
55652 #endif
55653 }
55654
55655 static ma_result ma_default_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten)
55656 {
55657     if (pBytesWritten != NULL) {
55658         *pBytesWritten = 0;
55659     }
55660
55661     if (file == NULL || pSrc == NULL) {
55662         return MA_INVALID_ARGS;
55663     }
55664
55665 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO)
55666     return ma_default_vfs_write__win32(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
55667 #else
55668     return ma_default_vfs_write__stdio(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
55669 #endif
55670 }
55671
55672 static ma_result ma_default_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
55673 {
55674     if (file == NULL) {
55675         return MA_INVALID_ARGS;
55676     }
55677
55678 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO)
55679     return ma_default_vfs_seek__win32(pVFS, file, offset, origin);
55680 #else
55681     return ma_default_vfs_seek__stdio(pVFS, file, offset, origin);
55682 #endif
55683 }
55684
55685 static ma_result ma_default_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
55686 {
55687     if (pCursor == NULL) {
55688         return MA_INVALID_ARGS;
55689     }
55690
55691     *pCursor = 0;
55692
55693     if (file == NULL) {
55694         return MA_INVALID_ARGS;
55695     }
55696
55697 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO)
55698     return ma_default_vfs_tell__win32(pVFS, file, pCursor);
55699 #else
55700     return ma_default_vfs_tell__stdio(pVFS, file, pCursor);
55701 #endif
55702 }
55703
55704 static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
55705 {
55706     if (pInfo == NULL) {
55707         return MA_INVALID_ARGS;
55708     }
55709
55710     MA_ZERO_OBJECT(pInfo);
55711
55712     if (file == NULL) {
55713         return MA_INVALID_ARGS;
55714     }
55715
55716 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP) && !defined(MA_NO_WIN32_FILEIO)
55717     return ma_default_vfs_info__win32(pVFS, file, pInfo);
55718 #else
55719     return ma_default_vfs_info__stdio(pVFS, file, pInfo);
55720 #endif
55721 }
55722
55723
55724 MA_API ma_result ma_default_vfs_init(ma_default_vfs* pVFS, const ma_allocation_callbacks* pAllocationCallbacks)
55725 {
55726     if (pVFS == NULL) {
55727         return MA_INVALID_ARGS;
55728     }
55729
55730     pVFS->cb.onOpen  = ma_default_vfs_open;
55731     pVFS->cb.onOpenW = ma_default_vfs_open_w;
55732     pVFS->cb.onClose = ma_default_vfs_close;
55733     pVFS->cb.onRead  = ma_default_vfs_read;
55734     pVFS->cb.onWrite = ma_default_vfs_write;
55735     pVFS->cb.onSeek  = ma_default_vfs_seek;
55736     pVFS->cb.onTell  = ma_default_vfs_tell;
55737     pVFS->cb.onInfo  = ma_default_vfs_info;
55738     ma_allocation_callbacks_init_copy(&pVFS->allocationCallbacks, pAllocationCallbacks);
55739
55740     return MA_SUCCESS;
55741 }
55742
55743
55744 MA_API ma_result ma_vfs_or_default_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
55745 {
55746     if (pVFS != NULL) {
55747         return ma_vfs_open(pVFS, pFilePath, openMode, pFile);
55748     } else {
55749         return ma_default_vfs_open(pVFS, pFilePath, openMode, pFile);
55750     }
55751 }
55752
55753 MA_API ma_result ma_vfs_or_default_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
55754 {
55755     if (pVFS != NULL) {
55756         return ma_vfs_open_w(pVFS, pFilePath, openMode, pFile);
55757     } else {
55758         return ma_default_vfs_open_w(pVFS, pFilePath, openMode, pFile);
55759     }
55760 }
55761
55762 MA_API ma_result ma_vfs_or_default_close(ma_vfs* pVFS, ma_vfs_file file)
55763 {
55764     if (pVFS != NULL) {
55765         return ma_vfs_close(pVFS, file);
55766     } else {
55767         return ma_default_vfs_close(pVFS, file);
55768     }
55769 }
55770
55771 MA_API ma_result ma_vfs_or_default_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead)
55772 {
55773     if (pVFS != NULL) {
55774         return ma_vfs_read(pVFS, file, pDst, sizeInBytes, pBytesRead);
55775     } else {
55776         return ma_default_vfs_read(pVFS, file, pDst, sizeInBytes, pBytesRead);
55777     }
55778 }
55779
55780 MA_API ma_result ma_vfs_or_default_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten)
55781 {
55782     if (pVFS != NULL) {
55783         return ma_vfs_write(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
55784     } else {
55785         return ma_default_vfs_write(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
55786     }
55787 }
55788
55789 MA_API ma_result ma_vfs_or_default_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
55790 {
55791     if (pVFS != NULL) {
55792         return ma_vfs_seek(pVFS, file, offset, origin);
55793     } else {
55794         return ma_default_vfs_seek(pVFS, file, offset, origin);
55795     }
55796 }
55797
55798 MA_API ma_result ma_vfs_or_default_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
55799 {
55800     if (pVFS != NULL) {
55801         return ma_vfs_tell(pVFS, file, pCursor);
55802     } else {
55803         return ma_default_vfs_tell(pVFS, file, pCursor);
55804     }
55805 }
55806
55807 MA_API ma_result ma_vfs_or_default_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
55808 {
55809     if (pVFS != NULL) {
55810         return ma_vfs_info(pVFS, file, pInfo);
55811     } else {
55812         return ma_default_vfs_info(pVFS, file, pInfo);
55813     }
55814 }
55815
55816
55817
55818 /**************************************************************************************************************************************************************
55819
55820 Decoding and Encoding Headers. These are auto-generated from a tool.
55821
55822 **************************************************************************************************************************************************************/
55823 #if !defined(MA_NO_WAV) && (!defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING))
55824 /* dr_wav_h begin */
55825 #ifndef dr_wav_h
55826 #define dr_wav_h
55827 #ifdef __cplusplus
55828 extern "C" {
55829 #endif
55830 #define DRWAV_STRINGIFY(x)      #x
55831 #define DRWAV_XSTRINGIFY(x)     DRWAV_STRINGIFY(x)
55832 #define DRWAV_VERSION_MAJOR     0
55833 #define DRWAV_VERSION_MINOR     13
55834 #define DRWAV_VERSION_REVISION  4
55835 #define DRWAV_VERSION_STRING    DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
55836 #include <stddef.h>
55837 typedef   signed char           drwav_int8;
55838 typedef unsigned char           drwav_uint8;
55839 typedef   signed short          drwav_int16;
55840 typedef unsigned short          drwav_uint16;
55841 typedef   signed int            drwav_int32;
55842 typedef unsigned int            drwav_uint32;
55843 #if defined(_MSC_VER) && !defined(__clang__)
55844     typedef   signed __int64    drwav_int64;
55845     typedef unsigned __int64    drwav_uint64;
55846 #else
55847     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
55848         #pragma GCC diagnostic push
55849         #pragma GCC diagnostic ignored "-Wlong-long"
55850         #if defined(__clang__)
55851             #pragma GCC diagnostic ignored "-Wc++11-long-long"
55852         #endif
55853     #endif
55854     typedef   signed long long  drwav_int64;
55855     typedef unsigned long long  drwav_uint64;
55856     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
55857         #pragma GCC diagnostic pop
55858     #endif
55859 #endif
55860 #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
55861     typedef drwav_uint64        drwav_uintptr;
55862 #else
55863     typedef drwav_uint32        drwav_uintptr;
55864 #endif
55865 typedef drwav_uint8             drwav_bool8;
55866 typedef drwav_uint32            drwav_bool32;
55867 #define DRWAV_TRUE              1
55868 #define DRWAV_FALSE             0
55869 #if !defined(DRWAV_API)
55870     #if defined(DRWAV_DLL)
55871         #if defined(_WIN32)
55872             #define DRWAV_DLL_IMPORT  __declspec(dllimport)
55873             #define DRWAV_DLL_EXPORT  __declspec(dllexport)
55874             #define DRWAV_DLL_PRIVATE static
55875         #else
55876             #if defined(__GNUC__) && __GNUC__ >= 4
55877                 #define DRWAV_DLL_IMPORT  __attribute__((visibility("default")))
55878                 #define DRWAV_DLL_EXPORT  __attribute__((visibility("default")))
55879                 #define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden")))
55880             #else
55881                 #define DRWAV_DLL_IMPORT
55882                 #define DRWAV_DLL_EXPORT
55883                 #define DRWAV_DLL_PRIVATE static
55884             #endif
55885         #endif
55886         #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
55887             #define DRWAV_API  DRWAV_DLL_EXPORT
55888         #else
55889             #define DRWAV_API  DRWAV_DLL_IMPORT
55890         #endif
55891         #define DRWAV_PRIVATE DRWAV_DLL_PRIVATE
55892     #else
55893         #define DRWAV_API extern
55894         #define DRWAV_PRIVATE static
55895     #endif
55896 #endif
55897 typedef drwav_int32 drwav_result;
55898 #define DRWAV_SUCCESS                        0
55899 #define DRWAV_ERROR                         -1
55900 #define DRWAV_INVALID_ARGS                  -2
55901 #define DRWAV_INVALID_OPERATION             -3
55902 #define DRWAV_OUT_OF_MEMORY                 -4
55903 #define DRWAV_OUT_OF_RANGE                  -5
55904 #define DRWAV_ACCESS_DENIED                 -6
55905 #define DRWAV_DOES_NOT_EXIST                -7
55906 #define DRWAV_ALREADY_EXISTS                -8
55907 #define DRWAV_TOO_MANY_OPEN_FILES           -9
55908 #define DRWAV_INVALID_FILE                  -10
55909 #define DRWAV_TOO_BIG                       -11
55910 #define DRWAV_PATH_TOO_LONG                 -12
55911 #define DRWAV_NAME_TOO_LONG                 -13
55912 #define DRWAV_NOT_DIRECTORY                 -14
55913 #define DRWAV_IS_DIRECTORY                  -15
55914 #define DRWAV_DIRECTORY_NOT_EMPTY           -16
55915 #define DRWAV_END_OF_FILE                   -17
55916 #define DRWAV_NO_SPACE                      -18
55917 #define DRWAV_BUSY                          -19
55918 #define DRWAV_IO_ERROR                      -20
55919 #define DRWAV_INTERRUPT                     -21
55920 #define DRWAV_UNAVAILABLE                   -22
55921 #define DRWAV_ALREADY_IN_USE                -23
55922 #define DRWAV_BAD_ADDRESS                   -24
55923 #define DRWAV_BAD_SEEK                      -25
55924 #define DRWAV_BAD_PIPE                      -26
55925 #define DRWAV_DEADLOCK                      -27
55926 #define DRWAV_TOO_MANY_LINKS                -28
55927 #define DRWAV_NOT_IMPLEMENTED               -29
55928 #define DRWAV_NO_MESSAGE                    -30
55929 #define DRWAV_BAD_MESSAGE                   -31
55930 #define DRWAV_NO_DATA_AVAILABLE             -32
55931 #define DRWAV_INVALID_DATA                  -33
55932 #define DRWAV_TIMEOUT                       -34
55933 #define DRWAV_NO_NETWORK                    -35
55934 #define DRWAV_NOT_UNIQUE                    -36
55935 #define DRWAV_NOT_SOCKET                    -37
55936 #define DRWAV_NO_ADDRESS                    -38
55937 #define DRWAV_BAD_PROTOCOL                  -39
55938 #define DRWAV_PROTOCOL_UNAVAILABLE          -40
55939 #define DRWAV_PROTOCOL_NOT_SUPPORTED        -41
55940 #define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42
55941 #define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED  -43
55942 #define DRWAV_SOCKET_NOT_SUPPORTED          -44
55943 #define DRWAV_CONNECTION_RESET              -45
55944 #define DRWAV_ALREADY_CONNECTED             -46
55945 #define DRWAV_NOT_CONNECTED                 -47
55946 #define DRWAV_CONNECTION_REFUSED            -48
55947 #define DRWAV_NO_HOST                       -49
55948 #define DRWAV_IN_PROGRESS                   -50
55949 #define DRWAV_CANCELLED                     -51
55950 #define DRWAV_MEMORY_ALREADY_MAPPED         -52
55951 #define DRWAV_AT_END                        -53
55952 #define DR_WAVE_FORMAT_PCM          0x1
55953 #define DR_WAVE_FORMAT_ADPCM        0x2
55954 #define DR_WAVE_FORMAT_IEEE_FLOAT   0x3
55955 #define DR_WAVE_FORMAT_ALAW         0x6
55956 #define DR_WAVE_FORMAT_MULAW        0x7
55957 #define DR_WAVE_FORMAT_DVI_ADPCM    0x11
55958 #define DR_WAVE_FORMAT_EXTENSIBLE   0xFFFE
55959 #define DRWAV_SEQUENTIAL            0x00000001
55960 DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision);
55961 DRWAV_API const char* drwav_version_string(void);
55962 typedef enum
55963 {
55964     drwav_seek_origin_start,
55965     drwav_seek_origin_current
55966 } drwav_seek_origin;
55967 typedef enum
55968 {
55969     drwav_container_riff,
55970     drwav_container_w64,
55971     drwav_container_rf64
55972 } drwav_container;
55973 typedef struct
55974 {
55975     union
55976     {
55977         drwav_uint8 fourcc[4];
55978         drwav_uint8 guid[16];
55979     } id;
55980     drwav_uint64 sizeInBytes;
55981     unsigned int paddingSize;
55982 } drwav_chunk_header;
55983 typedef struct
55984 {
55985     drwav_uint16 formatTag;
55986     drwav_uint16 channels;
55987     drwav_uint32 sampleRate;
55988     drwav_uint32 avgBytesPerSec;
55989     drwav_uint16 blockAlign;
55990     drwav_uint16 bitsPerSample;
55991     drwav_uint16 extendedSize;
55992     drwav_uint16 validBitsPerSample;
55993     drwav_uint32 channelMask;
55994     drwav_uint8 subFormat[16];
55995 } drwav_fmt;
55996 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT);
55997 typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
55998 typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite);
55999 typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
56000 typedef drwav_uint64 (* drwav_chunk_proc)(void* pChunkUserData, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_chunk_header* pChunkHeader, drwav_container container, const drwav_fmt* pFMT);
56001 typedef struct
56002 {
56003     void* pUserData;
56004     void* (* onMalloc)(size_t sz, void* pUserData);
56005     void* (* onRealloc)(void* p, size_t sz, void* pUserData);
56006     void  (* onFree)(void* p, void* pUserData);
56007 } drwav_allocation_callbacks;
56008 typedef struct
56009 {
56010     const drwav_uint8* data;
56011     size_t dataSize;
56012     size_t currentReadPos;
56013 } drwav__memory_stream;
56014 typedef struct
56015 {
56016     void** ppData;
56017     size_t* pDataSize;
56018     size_t dataSize;
56019     size_t dataCapacity;
56020     size_t currentWritePos;
56021 } drwav__memory_stream_write;
56022 typedef struct
56023 {
56024     drwav_container container;
56025     drwav_uint32 format;
56026     drwav_uint32 channels;
56027     drwav_uint32 sampleRate;
56028     drwav_uint32 bitsPerSample;
56029 } drwav_data_format;
56030 typedef enum
56031 {
56032     drwav_metadata_type_none                        = 0,
56033     drwav_metadata_type_unknown                     = 1 << 0,
56034     drwav_metadata_type_smpl                        = 1 << 1,
56035     drwav_metadata_type_inst                        = 1 << 2,
56036     drwav_metadata_type_cue                         = 1 << 3,
56037     drwav_metadata_type_acid                        = 1 << 4,
56038     drwav_metadata_type_bext                        = 1 << 5,
56039     drwav_metadata_type_list_label                  = 1 << 6,
56040     drwav_metadata_type_list_note                   = 1 << 7,
56041     drwav_metadata_type_list_labelled_cue_region    = 1 << 8,
56042     drwav_metadata_type_list_info_software          = 1 << 9,
56043     drwav_metadata_type_list_info_copyright         = 1 << 10,
56044     drwav_metadata_type_list_info_title             = 1 << 11,
56045     drwav_metadata_type_list_info_artist            = 1 << 12,
56046     drwav_metadata_type_list_info_comment           = 1 << 13,
56047     drwav_metadata_type_list_info_date              = 1 << 14,
56048     drwav_metadata_type_list_info_genre             = 1 << 15,
56049     drwav_metadata_type_list_info_album             = 1 << 16,
56050     drwav_metadata_type_list_info_tracknumber       = 1 << 17,
56051     drwav_metadata_type_list_all_info_strings       = drwav_metadata_type_list_info_software
56052                                                     | drwav_metadata_type_list_info_copyright
56053                                                     | drwav_metadata_type_list_info_title
56054                                                     | drwav_metadata_type_list_info_artist
56055                                                     | drwav_metadata_type_list_info_comment
56056                                                     | drwav_metadata_type_list_info_date
56057                                                     | drwav_metadata_type_list_info_genre
56058                                                     | drwav_metadata_type_list_info_album
56059                                                     | drwav_metadata_type_list_info_tracknumber,
56060     drwav_metadata_type_list_all_adtl               = drwav_metadata_type_list_label
56061                                                     | drwav_metadata_type_list_note
56062                                                     | drwav_metadata_type_list_labelled_cue_region,
56063     drwav_metadata_type_all                         = -2,
56064     drwav_metadata_type_all_including_unknown       = -1
56065 } drwav_metadata_type;
56066 typedef enum
56067 {
56068     drwav_smpl_loop_type_forward  = 0,
56069     drwav_smpl_loop_type_pingpong = 1,
56070     drwav_smpl_loop_type_backward = 2
56071 } drwav_smpl_loop_type;
56072 typedef struct
56073 {
56074     drwav_uint32 cuePointId;
56075     drwav_uint32 type;
56076     drwav_uint32 firstSampleByteOffset;
56077     drwav_uint32 lastSampleByteOffset;
56078     drwav_uint32 sampleFraction;
56079     drwav_uint32 playCount;
56080 } drwav_smpl_loop;
56081 typedef struct
56082 {
56083     drwav_uint32 manufacturerId;
56084     drwav_uint32 productId;
56085     drwav_uint32 samplePeriodNanoseconds;
56086     drwav_uint32 midiUnityNote;
56087     drwav_uint32 midiPitchFraction;
56088     drwav_uint32 smpteFormat;
56089     drwav_uint32 smpteOffset;
56090     drwav_uint32 sampleLoopCount;
56091     drwav_uint32 samplerSpecificDataSizeInBytes;
56092     drwav_smpl_loop* pLoops;
56093     drwav_uint8* pSamplerSpecificData;
56094 } drwav_smpl;
56095 typedef struct
56096 {
56097     drwav_int8 midiUnityNote;
56098     drwav_int8 fineTuneCents;
56099     drwav_int8 gainDecibels;
56100     drwav_int8 lowNote;
56101     drwav_int8 highNote;
56102     drwav_int8 lowVelocity;
56103     drwav_int8 highVelocity;
56104 } drwav_inst;
56105 typedef struct
56106 {
56107     drwav_uint32 id;
56108     drwav_uint32 playOrderPosition;
56109     drwav_uint8 dataChunkId[4];
56110     drwav_uint32 chunkStart;
56111     drwav_uint32 blockStart;
56112     drwav_uint32 sampleByteOffset;
56113 } drwav_cue_point;
56114 typedef struct
56115 {
56116     drwav_uint32 cuePointCount;
56117     drwav_cue_point *pCuePoints;
56118 } drwav_cue;
56119 typedef enum
56120 {
56121     drwav_acid_flag_one_shot      = 1,
56122     drwav_acid_flag_root_note_set = 2,
56123     drwav_acid_flag_stretch       = 4,
56124     drwav_acid_flag_disk_based    = 8,
56125     drwav_acid_flag_acidizer      = 16
56126 } drwav_acid_flag;
56127 typedef struct
56128 {
56129     drwav_uint32 flags;
56130     drwav_uint16 midiUnityNote;
56131     drwav_uint16 reserved1;
56132     float reserved2;
56133     drwav_uint32 numBeats;
56134     drwav_uint16 meterDenominator;
56135     drwav_uint16 meterNumerator;
56136     float tempo;
56137 } drwav_acid;
56138 typedef struct
56139 {
56140     drwav_uint32 cuePointId;
56141     drwav_uint32 stringLength;
56142     char* pString;
56143 } drwav_list_label_or_note;
56144 typedef struct
56145 {
56146     char* pDescription;
56147     char* pOriginatorName;
56148     char* pOriginatorReference;
56149     char  pOriginationDate[10];
56150     char  pOriginationTime[8];
56151     drwav_uint64 timeReference;
56152     drwav_uint16 version;
56153     char* pCodingHistory;
56154     drwav_uint32 codingHistorySize;
56155     drwav_uint8* pUMID;
56156     drwav_uint16 loudnessValue;
56157     drwav_uint16 loudnessRange;
56158     drwav_uint16 maxTruePeakLevel;
56159     drwav_uint16 maxMomentaryLoudness;
56160     drwav_uint16 maxShortTermLoudness;
56161 } drwav_bext;
56162 typedef struct
56163 {
56164     drwav_uint32 stringLength;
56165     char* pString;
56166 } drwav_list_info_text;
56167 typedef struct
56168 {
56169     drwav_uint32 cuePointId;
56170     drwav_uint32 sampleLength;
56171     drwav_uint8 purposeId[4];
56172     drwav_uint16 country;
56173     drwav_uint16 language;
56174     drwav_uint16 dialect;
56175     drwav_uint16 codePage;
56176     drwav_uint32 stringLength;
56177     char* pString;
56178 } drwav_list_labelled_cue_region;
56179 typedef enum
56180 {
56181     drwav_metadata_location_invalid,
56182     drwav_metadata_location_top_level,
56183     drwav_metadata_location_inside_info_list,
56184     drwav_metadata_location_inside_adtl_list
56185 } drwav_metadata_location;
56186 typedef struct
56187 {
56188     drwav_uint8 id[4];
56189     drwav_metadata_location chunkLocation;
56190     drwav_uint32 dataSizeInBytes;
56191     drwav_uint8* pData;
56192 } drwav_unknown_metadata;
56193 typedef struct
56194 {
56195     drwav_metadata_type type;
56196     union
56197     {
56198         drwav_cue cue;
56199         drwav_smpl smpl;
56200         drwav_acid acid;
56201         drwav_inst inst;
56202         drwav_bext bext;
56203         drwav_list_label_or_note labelOrNote;
56204         drwav_list_labelled_cue_region labelledCueRegion;
56205         drwav_list_info_text infoText;
56206         drwav_unknown_metadata unknown;
56207     } data;
56208 } drwav_metadata;
56209 typedef struct
56210 {
56211     drwav_read_proc onRead;
56212     drwav_write_proc onWrite;
56213     drwav_seek_proc onSeek;
56214     void* pUserData;
56215     drwav_allocation_callbacks allocationCallbacks;
56216     drwav_container container;
56217     drwav_fmt fmt;
56218     drwav_uint32 sampleRate;
56219     drwav_uint16 channels;
56220     drwav_uint16 bitsPerSample;
56221     drwav_uint16 translatedFormatTag;
56222     drwav_uint64 totalPCMFrameCount;
56223     drwav_uint64 dataChunkDataSize;
56224     drwav_uint64 dataChunkDataPos;
56225     drwav_uint64 bytesRemaining;
56226     drwav_uint64 readCursorInPCMFrames;
56227     drwav_uint64 dataChunkDataSizeTargetWrite;
56228     drwav_bool32 isSequentialWrite;
56229     drwav_metadata_type allowedMetadataTypes;
56230     drwav_metadata* pMetadata;
56231     drwav_uint32 metadataCount;
56232     drwav__memory_stream memoryStream;
56233     drwav__memory_stream_write memoryStreamWrite;
56234     struct
56235     {
56236         drwav_uint32 bytesRemainingInBlock;
56237         drwav_uint16 predictor[2];
56238         drwav_int32  delta[2];
56239         drwav_int32  cachedFrames[4];
56240         drwav_uint32 cachedFrameCount;
56241         drwav_int32  prevFrames[2][2];
56242     } msadpcm;
56243     struct
56244     {
56245         drwav_uint32 bytesRemainingInBlock;
56246         drwav_int32  predictor[2];
56247         drwav_int32  stepIndex[2];
56248         drwav_int32  cachedFrames[16];
56249         drwav_uint32 cachedFrameCount;
56250     } ima;
56251 } drwav;
56252 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
56253 DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
56254 DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
56255 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);
56256 DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
56257 DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
56258 DRWAV_API drwav_bool32 drwav_init_write_with_metadata(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks, drwav_metadata* pMetadata, drwav_uint32 metadataCount);
56259 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalFrameCount, drwav_metadata* pMetadata, drwav_uint32 metadataCount);
56260 DRWAV_API drwav_metadata* drwav_take_ownership_of_metadata(drwav* pWav);
56261 DRWAV_API drwav_result drwav_uninit(drwav* pWav);
56262 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut);
56263 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
56264 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
56265 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
56266 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex);
56267 DRWAV_API drwav_result drwav_get_cursor_in_pcm_frames(drwav* pWav, drwav_uint64* pCursor);
56268 DRWAV_API drwav_result drwav_get_length_in_pcm_frames(drwav* pWav, drwav_uint64* pLength);
56269 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData);
56270 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
56271 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
56272 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
56273 #ifndef DR_WAV_NO_CONVERSION_API
56274 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
56275 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
56276 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
56277 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
56278 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
56279 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount);
56280 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount);
56281 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount);
56282 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
56283 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
56284 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
56285 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
56286 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
56287 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
56288 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount);
56289 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
56290 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount);
56291 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount);
56292 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
56293 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
56294 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
56295 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
56296 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
56297 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
56298 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount);
56299 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
56300 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount);
56301 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount);
56302 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
56303 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
56304 #endif
56305 #ifndef DR_WAV_NO_STDIO
56306 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
56307 DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
56308 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
56309 DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
56310 DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
56311 DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
56312 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
56313 DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
56314 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
56315 DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
56316 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
56317 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
56318 #endif
56319 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks);
56320 DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
56321 DRWAV_API drwav_bool32 drwav_init_memory_with_metadata(drwav* pWav, const void* data, size_t dataSize, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
56322 DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
56323 DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
56324 DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
56325 #ifndef DR_WAV_NO_CONVERSION_API
56326 DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56327 DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56328 DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56329 #ifndef DR_WAV_NO_STDIO
56330 DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56331 DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56332 DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56333 DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56334 DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56335 DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56336 #endif
56337 DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56338 DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56339 DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
56340 #endif
56341 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks);
56342 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data);
56343 DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data);
56344 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data);
56345 DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data);
56346 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data);
56347 DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data);
56348 DRWAV_API float drwav_bytes_to_f32(const drwav_uint8* data);
56349 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]);
56350 DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b);
56351 #ifdef __cplusplus
56352 }
56353 #endif
56354 #endif
56355 /* dr_wav_h end */
56356 #endif  /* MA_NO_WAV */
56357
56358 #if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING)
56359 /* dr_flac_h begin */
56360 #ifndef dr_flac_h
56361 #define dr_flac_h
56362 #ifdef __cplusplus
56363 extern "C" {
56364 #endif
56365 #define DRFLAC_STRINGIFY(x)      #x
56366 #define DRFLAC_XSTRINGIFY(x)     DRFLAC_STRINGIFY(x)
56367 #define DRFLAC_VERSION_MAJOR     0
56368 #define DRFLAC_VERSION_MINOR     12
56369 #define DRFLAC_VERSION_REVISION  33
56370 #define DRFLAC_VERSION_STRING    DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
56371 #include <stddef.h>
56372 typedef   signed char           drflac_int8;
56373 typedef unsigned char           drflac_uint8;
56374 typedef   signed short          drflac_int16;
56375 typedef unsigned short          drflac_uint16;
56376 typedef   signed int            drflac_int32;
56377 typedef unsigned int            drflac_uint32;
56378 #if defined(_MSC_VER) && !defined(__clang__)
56379     typedef   signed __int64    drflac_int64;
56380     typedef unsigned __int64    drflac_uint64;
56381 #else
56382     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
56383         #pragma GCC diagnostic push
56384         #pragma GCC diagnostic ignored "-Wlong-long"
56385         #if defined(__clang__)
56386             #pragma GCC diagnostic ignored "-Wc++11-long-long"
56387         #endif
56388     #endif
56389     typedef   signed long long  drflac_int64;
56390     typedef unsigned long long  drflac_uint64;
56391     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
56392         #pragma GCC diagnostic pop
56393     #endif
56394 #endif
56395 #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
56396     typedef drflac_uint64       drflac_uintptr;
56397 #else
56398     typedef drflac_uint32       drflac_uintptr;
56399 #endif
56400 typedef drflac_uint8            drflac_bool8;
56401 typedef drflac_uint32           drflac_bool32;
56402 #define DRFLAC_TRUE             1
56403 #define DRFLAC_FALSE            0
56404 #if !defined(DRFLAC_API)
56405     #if defined(DRFLAC_DLL)
56406         #if defined(_WIN32)
56407             #define DRFLAC_DLL_IMPORT  __declspec(dllimport)
56408             #define DRFLAC_DLL_EXPORT  __declspec(dllexport)
56409             #define DRFLAC_DLL_PRIVATE static
56410         #else
56411             #if defined(__GNUC__) && __GNUC__ >= 4
56412                 #define DRFLAC_DLL_IMPORT  __attribute__((visibility("default")))
56413                 #define DRFLAC_DLL_EXPORT  __attribute__((visibility("default")))
56414                 #define DRFLAC_DLL_PRIVATE __attribute__((visibility("hidden")))
56415             #else
56416                 #define DRFLAC_DLL_IMPORT
56417                 #define DRFLAC_DLL_EXPORT
56418                 #define DRFLAC_DLL_PRIVATE static
56419             #endif
56420         #endif
56421         #if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION)
56422             #define DRFLAC_API  DRFLAC_DLL_EXPORT
56423         #else
56424             #define DRFLAC_API  DRFLAC_DLL_IMPORT
56425         #endif
56426         #define DRFLAC_PRIVATE DRFLAC_DLL_PRIVATE
56427     #else
56428         #define DRFLAC_API extern
56429         #define DRFLAC_PRIVATE static
56430     #endif
56431 #endif
56432 #if defined(_MSC_VER) && _MSC_VER >= 1700
56433     #define DRFLAC_DEPRECATED       __declspec(deprecated)
56434 #elif (defined(__GNUC__) && __GNUC__ >= 4)
56435     #define DRFLAC_DEPRECATED       __attribute__((deprecated))
56436 #elif defined(__has_feature)
56437     #if __has_feature(attribute_deprecated)
56438         #define DRFLAC_DEPRECATED   __attribute__((deprecated))
56439     #else
56440         #define DRFLAC_DEPRECATED
56441     #endif
56442 #else
56443     #define DRFLAC_DEPRECATED
56444 #endif
56445 DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision);
56446 DRFLAC_API const char* drflac_version_string(void);
56447 #ifndef DR_FLAC_BUFFER_SIZE
56448 #define DR_FLAC_BUFFER_SIZE   4096
56449 #endif
56450 #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
56451 #define DRFLAC_64BIT
56452 #endif
56453 #ifdef DRFLAC_64BIT
56454 typedef drflac_uint64 drflac_cache_t;
56455 #else
56456 typedef drflac_uint32 drflac_cache_t;
56457 #endif
56458 #define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO       0
56459 #define DRFLAC_METADATA_BLOCK_TYPE_PADDING          1
56460 #define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION      2
56461 #define DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE        3
56462 #define DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT   4
56463 #define DRFLAC_METADATA_BLOCK_TYPE_CUESHEET         5
56464 #define DRFLAC_METADATA_BLOCK_TYPE_PICTURE          6
56465 #define DRFLAC_METADATA_BLOCK_TYPE_INVALID          127
56466 #define DRFLAC_PICTURE_TYPE_OTHER                   0
56467 #define DRFLAC_PICTURE_TYPE_FILE_ICON               1
56468 #define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON         2
56469 #define DRFLAC_PICTURE_TYPE_COVER_FRONT             3
56470 #define DRFLAC_PICTURE_TYPE_COVER_BACK              4
56471 #define DRFLAC_PICTURE_TYPE_LEAFLET_PAGE            5
56472 #define DRFLAC_PICTURE_TYPE_MEDIA                   6
56473 #define DRFLAC_PICTURE_TYPE_LEAD_ARTIST             7
56474 #define DRFLAC_PICTURE_TYPE_ARTIST                  8
56475 #define DRFLAC_PICTURE_TYPE_CONDUCTOR               9
56476 #define DRFLAC_PICTURE_TYPE_BAND                    10
56477 #define DRFLAC_PICTURE_TYPE_COMPOSER                11
56478 #define DRFLAC_PICTURE_TYPE_LYRICIST                12
56479 #define DRFLAC_PICTURE_TYPE_RECORDING_LOCATION      13
56480 #define DRFLAC_PICTURE_TYPE_DURING_RECORDING        14
56481 #define DRFLAC_PICTURE_TYPE_DURING_PERFORMANCE      15
56482 #define DRFLAC_PICTURE_TYPE_SCREEN_CAPTURE          16
56483 #define DRFLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH     17
56484 #define DRFLAC_PICTURE_TYPE_ILLUSTRATION            18
56485 #define DRFLAC_PICTURE_TYPE_BAND_LOGOTYPE           19
56486 #define DRFLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE      20
56487 typedef enum
56488 {
56489     drflac_container_native,
56490     drflac_container_ogg,
56491     drflac_container_unknown
56492 } drflac_container;
56493 typedef enum
56494 {
56495     drflac_seek_origin_start,
56496     drflac_seek_origin_current
56497 } drflac_seek_origin;
56498 #pragma pack(2)
56499 typedef struct
56500 {
56501     drflac_uint64 firstPCMFrame;
56502     drflac_uint64 flacFrameOffset;
56503     drflac_uint16 pcmFrameCount;
56504 } drflac_seekpoint;
56505 #pragma pack()
56506 typedef struct
56507 {
56508     drflac_uint16 minBlockSizeInPCMFrames;
56509     drflac_uint16 maxBlockSizeInPCMFrames;
56510     drflac_uint32 minFrameSizeInPCMFrames;
56511     drflac_uint32 maxFrameSizeInPCMFrames;
56512     drflac_uint32 sampleRate;
56513     drflac_uint8  channels;
56514     drflac_uint8  bitsPerSample;
56515     drflac_uint64 totalPCMFrameCount;
56516     drflac_uint8  md5[16];
56517 } drflac_streaminfo;
56518 typedef struct
56519 {
56520     drflac_uint32 type;
56521     const void* pRawData;
56522     drflac_uint32 rawDataSize;
56523     union
56524     {
56525         drflac_streaminfo streaminfo;
56526         struct
56527         {
56528             int unused;
56529         } padding;
56530         struct
56531         {
56532             drflac_uint32 id;
56533             const void* pData;
56534             drflac_uint32 dataSize;
56535         } application;
56536         struct
56537         {
56538             drflac_uint32 seekpointCount;
56539             const drflac_seekpoint* pSeekpoints;
56540         } seektable;
56541         struct
56542         {
56543             drflac_uint32 vendorLength;
56544             const char* vendor;
56545             drflac_uint32 commentCount;
56546             const void* pComments;
56547         } vorbis_comment;
56548         struct
56549         {
56550             char catalog[128];
56551             drflac_uint64 leadInSampleCount;
56552             drflac_bool32 isCD;
56553             drflac_uint8 trackCount;
56554             const void* pTrackData;
56555         } cuesheet;
56556         struct
56557         {
56558             drflac_uint32 type;
56559             drflac_uint32 mimeLength;
56560             const char* mime;
56561             drflac_uint32 descriptionLength;
56562             const char* description;
56563             drflac_uint32 width;
56564             drflac_uint32 height;
56565             drflac_uint32 colorDepth;
56566             drflac_uint32 indexColorCount;
56567             drflac_uint32 pictureDataSize;
56568             const drflac_uint8* pPictureData;
56569         } picture;
56570     } data;
56571 } drflac_metadata;
56572 typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
56573 typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
56574 typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata);
56575 typedef struct
56576 {
56577     void* pUserData;
56578     void* (* onMalloc)(size_t sz, void* pUserData);
56579     void* (* onRealloc)(void* p, size_t sz, void* pUserData);
56580     void  (* onFree)(void* p, void* pUserData);
56581 } drflac_allocation_callbacks;
56582 typedef struct
56583 {
56584     const drflac_uint8* data;
56585     size_t dataSize;
56586     size_t currentReadPos;
56587 } drflac__memory_stream;
56588 typedef struct
56589 {
56590     drflac_read_proc onRead;
56591     drflac_seek_proc onSeek;
56592     void* pUserData;
56593     size_t unalignedByteCount;
56594     drflac_cache_t unalignedCache;
56595     drflac_uint32 nextL2Line;
56596     drflac_uint32 consumedBits;
56597     drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)];
56598     drflac_cache_t cache;
56599     drflac_uint16 crc16;
56600     drflac_cache_t crc16Cache;
56601     drflac_uint32 crc16CacheIgnoredBytes;
56602 } drflac_bs;
56603 typedef struct
56604 {
56605     drflac_uint8 subframeType;
56606     drflac_uint8 wastedBitsPerSample;
56607     drflac_uint8 lpcOrder;
56608     drflac_int32* pSamplesS32;
56609 } drflac_subframe;
56610 typedef struct
56611 {
56612     drflac_uint64 pcmFrameNumber;
56613     drflac_uint32 flacFrameNumber;
56614     drflac_uint32 sampleRate;
56615     drflac_uint16 blockSizeInPCMFrames;
56616     drflac_uint8 channelAssignment;
56617     drflac_uint8 bitsPerSample;
56618     drflac_uint8 crc8;
56619 } drflac_frame_header;
56620 typedef struct
56621 {
56622     drflac_frame_header header;
56623     drflac_uint32 pcmFramesRemaining;
56624     drflac_subframe subframes[8];
56625 } drflac_frame;
56626 typedef struct
56627 {
56628     drflac_meta_proc onMeta;
56629     void* pUserDataMD;
56630     drflac_allocation_callbacks allocationCallbacks;
56631     drflac_uint32 sampleRate;
56632     drflac_uint8 channels;
56633     drflac_uint8 bitsPerSample;
56634     drflac_uint16 maxBlockSizeInPCMFrames;
56635     drflac_uint64 totalPCMFrameCount;
56636     drflac_container container;
56637     drflac_uint32 seekpointCount;
56638     drflac_frame currentFLACFrame;
56639     drflac_uint64 currentPCMFrame;
56640     drflac_uint64 firstFLACFramePosInBytes;
56641     drflac__memory_stream memoryStream;
56642     drflac_int32* pDecodedSamples;
56643     drflac_seekpoint* pSeekpoints;
56644     void* _oggbs;
56645     drflac_bool32 _noSeekTableSeek    : 1;
56646     drflac_bool32 _noBinarySearchSeek : 1;
56647     drflac_bool32 _noBruteForceSeek   : 1;
56648     drflac_bs bs;
56649     drflac_uint8 pExtraData[1];
56650 } drflac;
56651 DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
56652 DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
56653 DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
56654 DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
56655 DRFLAC_API void drflac_close(drflac* pFlac);
56656 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut);
56657 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut);
56658 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut);
56659 DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex);
56660 #ifndef DR_FLAC_NO_STDIO
56661 DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
56662 DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
56663 DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
56664 DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
56665 #endif
56666 DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks);
56667 DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
56668 DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
56669 DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
56670 DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
56671 #ifndef DR_FLAC_NO_STDIO
56672 DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
56673 DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
56674 DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
56675 #endif
56676 DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
56677 DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
56678 DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
56679 DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks);
56680 typedef struct
56681 {
56682     drflac_uint32 countRemaining;
56683     const char* pRunningData;
56684 } drflac_vorbis_comment_iterator;
56685 DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments);
56686 DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut);
56687 typedef struct
56688 {
56689     drflac_uint32 countRemaining;
56690     const char* pRunningData;
56691 } drflac_cuesheet_track_iterator;
56692 #pragma pack(4)
56693 typedef struct
56694 {
56695     drflac_uint64 offset;
56696     drflac_uint8 index;
56697     drflac_uint8 reserved[3];
56698 } drflac_cuesheet_track_index;
56699 #pragma pack()
56700 typedef struct
56701 {
56702     drflac_uint64 offset;
56703     drflac_uint8 trackNumber;
56704     char ISRC[12];
56705     drflac_bool8 isAudio;
56706     drflac_bool8 preEmphasis;
56707     drflac_uint8 indexCount;
56708     const drflac_cuesheet_track_index* pIndexPoints;
56709 } drflac_cuesheet_track;
56710 DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData);
56711 DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack);
56712 #ifdef __cplusplus
56713 }
56714 #endif
56715 #endif
56716 /* dr_flac_h end */
56717 #endif  /* MA_NO_FLAC */
56718
56719 #if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING)
56720 /* dr_mp3_h begin */
56721 #ifndef dr_mp3_h
56722 #define dr_mp3_h
56723 #ifdef __cplusplus
56724 extern "C" {
56725 #endif
56726 #define DRMP3_STRINGIFY(x)      #x
56727 #define DRMP3_XSTRINGIFY(x)     DRMP3_STRINGIFY(x)
56728 #define DRMP3_VERSION_MAJOR     0
56729 #define DRMP3_VERSION_MINOR     6
56730 #define DRMP3_VERSION_REVISION  32
56731 #define DRMP3_VERSION_STRING    DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
56732 #include <stddef.h>
56733 typedef   signed char           drmp3_int8;
56734 typedef unsigned char           drmp3_uint8;
56735 typedef   signed short          drmp3_int16;
56736 typedef unsigned short          drmp3_uint16;
56737 typedef   signed int            drmp3_int32;
56738 typedef unsigned int            drmp3_uint32;
56739 #if defined(_MSC_VER) && !defined(__clang__)
56740     typedef   signed __int64    drmp3_int64;
56741     typedef unsigned __int64    drmp3_uint64;
56742 #else
56743     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
56744         #pragma GCC diagnostic push
56745         #pragma GCC diagnostic ignored "-Wlong-long"
56746         #if defined(__clang__)
56747             #pragma GCC diagnostic ignored "-Wc++11-long-long"
56748         #endif
56749     #endif
56750     typedef   signed long long  drmp3_int64;
56751     typedef unsigned long long  drmp3_uint64;
56752     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
56753         #pragma GCC diagnostic pop
56754     #endif
56755 #endif
56756 #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
56757     typedef drmp3_uint64        drmp3_uintptr;
56758 #else
56759     typedef drmp3_uint32        drmp3_uintptr;
56760 #endif
56761 typedef drmp3_uint8             drmp3_bool8;
56762 typedef drmp3_uint32            drmp3_bool32;
56763 #define DRMP3_TRUE              1
56764 #define DRMP3_FALSE             0
56765 #if !defined(DRMP3_API)
56766     #if defined(DRMP3_DLL)
56767         #if defined(_WIN32)
56768             #define DRMP3_DLL_IMPORT  __declspec(dllimport)
56769             #define DRMP3_DLL_EXPORT  __declspec(dllexport)
56770             #define DRMP3_DLL_PRIVATE static
56771         #else
56772             #if defined(__GNUC__) && __GNUC__ >= 4
56773                 #define DRMP3_DLL_IMPORT  __attribute__((visibility("default")))
56774                 #define DRMP3_DLL_EXPORT  __attribute__((visibility("default")))
56775                 #define DRMP3_DLL_PRIVATE __attribute__((visibility("hidden")))
56776             #else
56777                 #define DRMP3_DLL_IMPORT
56778                 #define DRMP3_DLL_EXPORT
56779                 #define DRMP3_DLL_PRIVATE static
56780             #endif
56781         #endif
56782         #if defined(DR_MP3_IMPLEMENTATION) || defined(DRMP3_IMPLEMENTATION)
56783             #define DRMP3_API  DRMP3_DLL_EXPORT
56784         #else
56785             #define DRMP3_API  DRMP3_DLL_IMPORT
56786         #endif
56787         #define DRMP3_PRIVATE DRMP3_DLL_PRIVATE
56788     #else
56789         #define DRMP3_API extern
56790         #define DRMP3_PRIVATE static
56791     #endif
56792 #endif
56793 typedef drmp3_int32 drmp3_result;
56794 #define DRMP3_SUCCESS                        0
56795 #define DRMP3_ERROR                         -1
56796 #define DRMP3_INVALID_ARGS                  -2
56797 #define DRMP3_INVALID_OPERATION             -3
56798 #define DRMP3_OUT_OF_MEMORY                 -4
56799 #define DRMP3_OUT_OF_RANGE                  -5
56800 #define DRMP3_ACCESS_DENIED                 -6
56801 #define DRMP3_DOES_NOT_EXIST                -7
56802 #define DRMP3_ALREADY_EXISTS                -8
56803 #define DRMP3_TOO_MANY_OPEN_FILES           -9
56804 #define DRMP3_INVALID_FILE                  -10
56805 #define DRMP3_TOO_BIG                       -11
56806 #define DRMP3_PATH_TOO_LONG                 -12
56807 #define DRMP3_NAME_TOO_LONG                 -13
56808 #define DRMP3_NOT_DIRECTORY                 -14
56809 #define DRMP3_IS_DIRECTORY                  -15
56810 #define DRMP3_DIRECTORY_NOT_EMPTY           -16
56811 #define DRMP3_END_OF_FILE                   -17
56812 #define DRMP3_NO_SPACE                      -18
56813 #define DRMP3_BUSY                          -19
56814 #define DRMP3_IO_ERROR                      -20
56815 #define DRMP3_INTERRUPT                     -21
56816 #define DRMP3_UNAVAILABLE                   -22
56817 #define DRMP3_ALREADY_IN_USE                -23
56818 #define DRMP3_BAD_ADDRESS                   -24
56819 #define DRMP3_BAD_SEEK                      -25
56820 #define DRMP3_BAD_PIPE                      -26
56821 #define DRMP3_DEADLOCK                      -27
56822 #define DRMP3_TOO_MANY_LINKS                -28
56823 #define DRMP3_NOT_IMPLEMENTED               -29
56824 #define DRMP3_NO_MESSAGE                    -30
56825 #define DRMP3_BAD_MESSAGE                   -31
56826 #define DRMP3_NO_DATA_AVAILABLE             -32
56827 #define DRMP3_INVALID_DATA                  -33
56828 #define DRMP3_TIMEOUT                       -34
56829 #define DRMP3_NO_NETWORK                    -35
56830 #define DRMP3_NOT_UNIQUE                    -36
56831 #define DRMP3_NOT_SOCKET                    -37
56832 #define DRMP3_NO_ADDRESS                    -38
56833 #define DRMP3_BAD_PROTOCOL                  -39
56834 #define DRMP3_PROTOCOL_UNAVAILABLE          -40
56835 #define DRMP3_PROTOCOL_NOT_SUPPORTED        -41
56836 #define DRMP3_PROTOCOL_FAMILY_NOT_SUPPORTED -42
56837 #define DRMP3_ADDRESS_FAMILY_NOT_SUPPORTED  -43
56838 #define DRMP3_SOCKET_NOT_SUPPORTED          -44
56839 #define DRMP3_CONNECTION_RESET              -45
56840 #define DRMP3_ALREADY_CONNECTED             -46
56841 #define DRMP3_NOT_CONNECTED                 -47
56842 #define DRMP3_CONNECTION_REFUSED            -48
56843 #define DRMP3_NO_HOST                       -49
56844 #define DRMP3_IN_PROGRESS                   -50
56845 #define DRMP3_CANCELLED                     -51
56846 #define DRMP3_MEMORY_ALREADY_MAPPED         -52
56847 #define DRMP3_AT_END                        -53
56848 #define DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME  1152
56849 #define DRMP3_MAX_SAMPLES_PER_FRAME         (DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2)
56850 #ifdef _MSC_VER
56851     #define DRMP3_INLINE __forceinline
56852 #elif defined(__GNUC__)
56853     #if defined(__STRICT_ANSI__)
56854         #define DRMP3_INLINE __inline__ __attribute__((always_inline))
56855     #else
56856         #define DRMP3_INLINE inline __attribute__((always_inline))
56857     #endif
56858 #elif defined(__WATCOMC__)
56859     #define DRMP3_INLINE __inline
56860 #else
56861     #define DRMP3_INLINE
56862 #endif
56863 DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision);
56864 DRMP3_API const char* drmp3_version_string(void);
56865 typedef struct
56866 {
56867     int frame_bytes, channels, hz, layer, bitrate_kbps;
56868 } drmp3dec_frame_info;
56869 typedef struct
56870 {
56871     float mdct_overlap[2][9*32], qmf_state[15*2*32];
56872     int reserv, free_format_bytes;
56873     drmp3_uint8 header[4], reserv_buf[511];
56874 } drmp3dec;
56875 DRMP3_API void drmp3dec_init(drmp3dec *dec);
56876 DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info);
56877 DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num_samples);
56878 typedef enum
56879 {
56880     drmp3_seek_origin_start,
56881     drmp3_seek_origin_current
56882 } drmp3_seek_origin;
56883 typedef struct
56884 {
56885     drmp3_uint64 seekPosInBytes;
56886     drmp3_uint64 pcmFrameIndex;
56887     drmp3_uint16 mp3FramesToDiscard;
56888     drmp3_uint16 pcmFramesToDiscard;
56889 } drmp3_seek_point;
56890 typedef size_t (* drmp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
56891 typedef drmp3_bool32 (* drmp3_seek_proc)(void* pUserData, int offset, drmp3_seek_origin origin);
56892 typedef struct
56893 {
56894     void* pUserData;
56895     void* (* onMalloc)(size_t sz, void* pUserData);
56896     void* (* onRealloc)(void* p, size_t sz, void* pUserData);
56897     void  (* onFree)(void* p, void* pUserData);
56898 } drmp3_allocation_callbacks;
56899 typedef struct
56900 {
56901     drmp3_uint32 channels;
56902     drmp3_uint32 sampleRate;
56903 } drmp3_config;
56904 typedef struct
56905 {
56906     drmp3dec decoder;
56907     drmp3dec_frame_info frameInfo;
56908     drmp3_uint32 channels;
56909     drmp3_uint32 sampleRate;
56910     drmp3_read_proc onRead;
56911     drmp3_seek_proc onSeek;
56912     void* pUserData;
56913     drmp3_allocation_callbacks allocationCallbacks;
56914     drmp3_uint32 mp3FrameChannels;
56915     drmp3_uint32 mp3FrameSampleRate;
56916     drmp3_uint32 pcmFramesConsumedInMP3Frame;
56917     drmp3_uint32 pcmFramesRemainingInMP3Frame;
56918     drmp3_uint8 pcmFrames[sizeof(float)*DRMP3_MAX_SAMPLES_PER_FRAME];
56919     drmp3_uint64 currentPCMFrame;
56920     drmp3_uint64 streamCursor;
56921     drmp3_seek_point* pSeekPoints;
56922     drmp3_uint32 seekPointCount;
56923     size_t dataSize;
56924     size_t dataCapacity;
56925     size_t dataConsumed;
56926     drmp3_uint8* pData;
56927     drmp3_bool32 atEnd : 1;
56928     struct
56929     {
56930         const drmp3_uint8* pData;
56931         size_t dataSize;
56932         size_t currentReadPos;
56933     } memory;
56934 } drmp3;
56935 DRMP3_API drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks);
56936 DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_allocation_callbacks* pAllocationCallbacks);
56937 #ifndef DR_MP3_NO_STDIO
56938 DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks);
56939 DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks);
56940 #endif
56941 DRMP3_API void drmp3_uninit(drmp3* pMP3);
56942 DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut);
56943 DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut);
56944 DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex);
56945 DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3);
56946 DRMP3_API drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3);
56947 DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount);
56948 DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints);
56949 DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints);
56950 DRMP3_API float* drmp3_open_and_read_pcm_frames_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
56951 DRMP3_API drmp3_int16* drmp3_open_and_read_pcm_frames_s16(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
56952 DRMP3_API float* drmp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
56953 DRMP3_API drmp3_int16* drmp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
56954 #ifndef DR_MP3_NO_STDIO
56955 DRMP3_API float* drmp3_open_file_and_read_pcm_frames_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
56956 DRMP3_API drmp3_int16* drmp3_open_file_and_read_pcm_frames_s16(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
56957 #endif
56958 DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks);
56959 DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks);
56960 #ifdef __cplusplus
56961 }
56962 #endif
56963 #endif
56964 /* dr_mp3_h end */
56965 #endif  /* MA_NO_MP3 */
56966
56967
56968 /**************************************************************************************************************************************************************
56969
56970 Decoding
56971
56972 **************************************************************************************************************************************************************/
56973 #ifndef MA_NO_DECODING
56974
56975 static ma_result ma_decoder_read_bytes(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead)
56976 {
56977     MA_ASSERT(pDecoder != NULL);
56978
56979     return pDecoder->onRead(pDecoder, pBufferOut, bytesToRead, pBytesRead);
56980 }
56981
56982 static ma_result ma_decoder_seek_bytes(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin)
56983 {
56984     MA_ASSERT(pDecoder != NULL);
56985
56986     return pDecoder->onSeek(pDecoder, byteOffset, origin);
56987 }
56988
56989 static ma_result ma_decoder_tell_bytes(ma_decoder* pDecoder, ma_int64* pCursor)
56990 {
56991     MA_ASSERT(pDecoder != NULL);
56992
56993     if (pDecoder->onTell == NULL) {
56994         return MA_NOT_IMPLEMENTED;
56995     }
56996
56997     return pDecoder->onTell(pDecoder, pCursor);
56998 }
56999
57000
57001 MA_API ma_decoding_backend_config ma_decoding_backend_config_init(ma_format preferredFormat, ma_uint32 seekPointCount)
57002 {
57003     ma_decoding_backend_config config;
57004
57005     MA_ZERO_OBJECT(&config);
57006     config.preferredFormat = preferredFormat;
57007     config.seekPointCount  = seekPointCount;
57008
57009     return config;
57010 }
57011
57012
57013 MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate)
57014 {
57015     ma_decoder_config config;
57016     MA_ZERO_OBJECT(&config);
57017     config.format         = outputFormat;
57018     config.channels       = outputChannels;
57019     config.sampleRate     = outputSampleRate;
57020     config.resampling     = ma_resampler_config_init(ma_format_unknown, 0, 0, 0, ma_resample_algorithm_linear); /* Format/channels/rate doesn't matter here. */
57021     config.encodingFormat = ma_encoding_format_unknown;
57022
57023     /* Note that we are intentionally leaving the channel map empty here which will cause the default channel map to be used. */
57024
57025     return config;
57026 }
57027
57028 MA_API ma_decoder_config ma_decoder_config_init_default()
57029 {
57030     return ma_decoder_config_init(ma_format_unknown, 0, 0);
57031 }
57032
57033 MA_API ma_decoder_config ma_decoder_config_init_copy(const ma_decoder_config* pConfig)
57034 {
57035     ma_decoder_config config;
57036     if (pConfig != NULL) {
57037         config = *pConfig;
57038     } else {
57039         MA_ZERO_OBJECT(&config);
57040     }
57041
57042     return config;
57043 }
57044
57045 static ma_result ma_decoder__init_data_converter(ma_decoder* pDecoder, const ma_decoder_config* pConfig)
57046 {
57047     ma_result result;
57048     ma_data_converter_config converterConfig;
57049     ma_format internalFormat;
57050     ma_uint32 internalChannels;
57051     ma_uint32 internalSampleRate;
57052     ma_channel internalChannelMap[MA_MAX_CHANNELS];
57053
57054     MA_ASSERT(pDecoder != NULL);
57055     MA_ASSERT(pConfig  != NULL);
57056
57057     result = ma_data_source_get_data_format(pDecoder->pBackend, &internalFormat, &internalChannels, &internalSampleRate, internalChannelMap, ma_countof(internalChannelMap));
57058     if (result != MA_SUCCESS) {
57059         return result;  /* Failed to retrieve the internal data format. */
57060     }
57061
57062
57063     /* Make sure we're not asking for too many channels. */
57064     if (pConfig->channels > MA_MAX_CHANNELS) {
57065         return MA_INVALID_ARGS;
57066     }
57067
57068     /* The internal channels should have already been validated at a higher level, but we'll do it again explicitly here for safety. */
57069     if (internalChannels > MA_MAX_CHANNELS) {
57070         return MA_INVALID_ARGS;
57071     }
57072
57073
57074     /* Output format. */
57075     if (pConfig->format == ma_format_unknown) {
57076         pDecoder->outputFormat = internalFormat;
57077     } else {
57078         pDecoder->outputFormat = pConfig->format;
57079     }
57080
57081     if (pConfig->channels == 0) {
57082         pDecoder->outputChannels = internalChannels;
57083     } else {
57084         pDecoder->outputChannels = pConfig->channels;
57085     }
57086
57087     if (pConfig->sampleRate == 0) {
57088         pDecoder->outputSampleRate = internalSampleRate;
57089     } else {
57090         pDecoder->outputSampleRate = pConfig->sampleRate;
57091     }
57092
57093     converterConfig = ma_data_converter_config_init(
57094         internalFormat,     pDecoder->outputFormat,
57095         internalChannels,   pDecoder->outputChannels,
57096         internalSampleRate, pDecoder->outputSampleRate
57097     );
57098     converterConfig.pChannelMapIn          = internalChannelMap;
57099     converterConfig.pChannelMapOut         = pConfig->pChannelMap;
57100     converterConfig.channelMixMode         = pConfig->channelMixMode;
57101     converterConfig.ditherMode             = pConfig->ditherMode;
57102     converterConfig.allowDynamicSampleRate = MA_FALSE;   /* Never allow dynamic sample rate conversion. Setting this to true will disable passthrough optimizations. */
57103     converterConfig.resampling             = pConfig->resampling;
57104
57105     result = ma_data_converter_init(&converterConfig, &pDecoder->allocationCallbacks, &pDecoder->converter);
57106     if (result != MA_SUCCESS) {
57107         return result;
57108     }
57109
57110     /*
57111     Now that we have the decoder we need to determine whether or not we need a heap-allocated cache. We'll
57112     need this if the data converter does not support calculation of the required input frame count. To
57113     determine support for this we'll just run a test.
57114     */
57115     {
57116         ma_uint64 unused;
57117
57118         result = ma_data_converter_get_required_input_frame_count(&pDecoder->converter, 1, &unused);
57119         if (result != MA_SUCCESS) {
57120             /*
57121             We were unable to calculate the required input frame count which means we'll need to use
57122             a heap-allocated cache.
57123             */
57124             ma_uint64 inputCacheCapSizeInBytes;
57125
57126             pDecoder->inputCacheCap = MA_DATA_CONVERTER_STACK_BUFFER_SIZE / ma_get_bytes_per_frame(internalFormat, internalChannels);
57127
57128             /* Not strictly necessary, but keeping here for safety in case we change the default value of pDecoder->inputCacheCap. */
57129             inputCacheCapSizeInBytes = pDecoder->inputCacheCap * ma_get_bytes_per_frame(internalFormat, internalChannels);
57130             if (inputCacheCapSizeInBytes > MA_SIZE_MAX) {
57131                 ma_data_converter_uninit(&pDecoder->converter, &pDecoder->allocationCallbacks);
57132                 return MA_OUT_OF_MEMORY;
57133             }
57134
57135             pDecoder->pInputCache = ma_malloc((size_t)inputCacheCapSizeInBytes, &pDecoder->allocationCallbacks);    /* Safe cast to size_t. */
57136             if (pDecoder->pInputCache == NULL) {
57137                 ma_data_converter_uninit(&pDecoder->converter, &pDecoder->allocationCallbacks);
57138                 return MA_OUT_OF_MEMORY;
57139             }
57140         }
57141     }
57142
57143     return MA_SUCCESS;
57144 }
57145
57146
57147
57148 static ma_result ma_decoder_internal_on_read__custom(void* pUserData, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead)
57149 {
57150     ma_decoder* pDecoder = (ma_decoder*)pUserData;
57151     MA_ASSERT(pDecoder != NULL);
57152
57153     return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead, pBytesRead);
57154 }
57155
57156 static ma_result ma_decoder_internal_on_seek__custom(void* pUserData, ma_int64 offset, ma_seek_origin origin)
57157 {
57158     ma_decoder* pDecoder = (ma_decoder*)pUserData;
57159     MA_ASSERT(pDecoder != NULL);
57160
57161     return ma_decoder_seek_bytes(pDecoder, offset, origin);
57162 }
57163
57164 static ma_result ma_decoder_internal_on_tell__custom(void* pUserData, ma_int64* pCursor)
57165 {
57166     ma_decoder* pDecoder = (ma_decoder*)pUserData;
57167     MA_ASSERT(pDecoder != NULL);
57168
57169     return ma_decoder_tell_bytes(pDecoder, pCursor);
57170 }
57171
57172
57173 static ma_result ma_decoder_init_from_vtable(const ma_decoding_backend_vtable* pVTable, void* pVTableUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
57174 {
57175     ma_result result;
57176     ma_decoding_backend_config backendConfig;
57177     ma_data_source* pBackend;
57178
57179     MA_ASSERT(pVTable  != NULL);
57180     MA_ASSERT(pConfig  != NULL);
57181     MA_ASSERT(pDecoder != NULL);
57182
57183     if (pVTable->onInit == NULL) {
57184         return MA_NOT_IMPLEMENTED;
57185     }
57186
57187     backendConfig = ma_decoding_backend_config_init(pConfig->format, pConfig->seekPointCount);
57188
57189     result = pVTable->onInit(pVTableUserData, ma_decoder_internal_on_read__custom, ma_decoder_internal_on_seek__custom, ma_decoder_internal_on_tell__custom, pDecoder, &backendConfig, &pDecoder->allocationCallbacks, &pBackend);
57190     if (result != MA_SUCCESS) {
57191         return result;  /* Failed to initialize the backend from this vtable. */
57192     }
57193
57194     /* Getting here means we were able to initialize the backend so we can now initialize the decoder. */
57195     pDecoder->pBackend         = pBackend;
57196     pDecoder->pBackendVTable   = pVTable;
57197     pDecoder->pBackendUserData = pConfig->pCustomBackendUserData;
57198
57199     return MA_SUCCESS;
57200 }
57201
57202
57203
57204 static ma_result ma_decoder_init_custom__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
57205 {
57206     ma_result result = MA_NO_BACKEND;
57207     size_t ivtable;
57208
57209     MA_ASSERT(pConfig != NULL);
57210     MA_ASSERT(pDecoder != NULL);
57211
57212     if (pConfig->ppCustomBackendVTables == NULL) {
57213         return MA_NO_BACKEND;
57214     }
57215
57216     /* The order each backend is listed is what defines the priority. */
57217     for (ivtable = 0; ivtable < pConfig->customBackendCount; ivtable += 1) {
57218         const ma_decoding_backend_vtable* pVTable = pConfig->ppCustomBackendVTables[ivtable];
57219         if (pVTable != NULL && pVTable->onInit != NULL) {
57220             result = ma_decoder_init_from_vtable(pVTable, pConfig->pCustomBackendUserData, pConfig, pDecoder);
57221             if (result == MA_SUCCESS) {
57222                 return MA_SUCCESS;
57223             } else {
57224                 /* Initialization failed. Move on to the next one, but seek back to the start first so the next vtable starts from the first byte of the file. */
57225                 result = ma_decoder_seek_bytes(pDecoder, 0, ma_seek_origin_start);
57226                 if (result != MA_SUCCESS) {
57227                     return result;  /* Failed to seek back to the start. */
57228                 }
57229             }
57230         } else {
57231             /* No vtable. */
57232         }
57233     }
57234
57235     /* Getting here means we couldn't find a backend. */
57236     return MA_NO_BACKEND;
57237 }
57238
57239
57240 /* WAV */
57241 #ifdef dr_wav_h
57242 #define MA_HAS_WAV
57243
57244 typedef struct
57245 {
57246     ma_data_source_base ds;
57247     ma_read_proc onRead;
57248     ma_seek_proc onSeek;
57249     ma_tell_proc onTell;
57250     void* pReadSeekTellUserData;
57251     ma_format format;           /* Can be f32, s16 or s32. */
57252 #if !defined(MA_NO_WAV)
57253     drwav dr;
57254 #endif
57255 } ma_wav;
57256
57257 MA_API ma_result ma_wav_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav);
57258 MA_API ma_result ma_wav_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav);
57259 MA_API ma_result ma_wav_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav);
57260 MA_API ma_result ma_wav_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav);
57261 MA_API void ma_wav_uninit(ma_wav* pWav, const ma_allocation_callbacks* pAllocationCallbacks);
57262 MA_API ma_result ma_wav_read_pcm_frames(ma_wav* pWav, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
57263 MA_API ma_result ma_wav_seek_to_pcm_frame(ma_wav* pWav, ma_uint64 frameIndex);
57264 MA_API ma_result ma_wav_get_data_format(ma_wav* pWav, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
57265 MA_API ma_result ma_wav_get_cursor_in_pcm_frames(ma_wav* pWav, ma_uint64* pCursor);
57266 MA_API ma_result ma_wav_get_length_in_pcm_frames(ma_wav* pWav, ma_uint64* pLength);
57267
57268
57269 static ma_result ma_wav_ds_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
57270 {
57271     return ma_wav_read_pcm_frames((ma_wav*)pDataSource, pFramesOut, frameCount, pFramesRead);
57272 }
57273
57274 static ma_result ma_wav_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
57275 {
57276     return ma_wav_seek_to_pcm_frame((ma_wav*)pDataSource, frameIndex);
57277 }
57278
57279 static ma_result ma_wav_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
57280 {
57281     return ma_wav_get_data_format((ma_wav*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
57282 }
57283
57284 static ma_result ma_wav_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
57285 {
57286     return ma_wav_get_cursor_in_pcm_frames((ma_wav*)pDataSource, pCursor);
57287 }
57288
57289 static ma_result ma_wav_ds_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
57290 {
57291     return ma_wav_get_length_in_pcm_frames((ma_wav*)pDataSource, pLength);
57292 }
57293
57294 static ma_data_source_vtable g_ma_wav_ds_vtable =
57295 {
57296     ma_wav_ds_read,
57297     ma_wav_ds_seek,
57298     ma_wav_ds_get_data_format,
57299     ma_wav_ds_get_cursor,
57300     ma_wav_ds_get_length,
57301     NULL,   /* onSetLooping */
57302     0
57303 };
57304
57305
57306 #if !defined(MA_NO_WAV)
57307 static drwav_allocation_callbacks drwav_allocation_callbacks_from_miniaudio(const ma_allocation_callbacks* pAllocationCallbacks)
57308 {
57309     drwav_allocation_callbacks callbacks;
57310
57311     if (pAllocationCallbacks != NULL) {
57312         callbacks.onMalloc  = pAllocationCallbacks->onMalloc;
57313         callbacks.onRealloc = pAllocationCallbacks->onRealloc;
57314         callbacks.onFree    = pAllocationCallbacks->onFree;
57315         callbacks.pUserData = pAllocationCallbacks->pUserData;
57316     } else {
57317         callbacks.onMalloc  = ma__malloc_default;
57318         callbacks.onRealloc = ma__realloc_default;
57319         callbacks.onFree    = ma__free_default;
57320         callbacks.pUserData = NULL;
57321     }
57322
57323     return callbacks;
57324 }
57325
57326 static size_t ma_wav_dr_callback__read(void* pUserData, void* pBufferOut, size_t bytesToRead)
57327 {
57328     ma_wav* pWav = (ma_wav*)pUserData;
57329     ma_result result;
57330     size_t bytesRead;
57331
57332     MA_ASSERT(pWav != NULL);
57333
57334     result = pWav->onRead(pWav->pReadSeekTellUserData, pBufferOut, bytesToRead, &bytesRead);
57335     (void)result;
57336
57337     return bytesRead;
57338 }
57339
57340 static drwav_bool32 ma_wav_dr_callback__seek(void* pUserData, int offset, drwav_seek_origin origin)
57341 {
57342     ma_wav* pWav = (ma_wav*)pUserData;
57343     ma_result result;
57344     ma_seek_origin maSeekOrigin;
57345
57346     MA_ASSERT(pWav != NULL);
57347
57348     maSeekOrigin = ma_seek_origin_start;
57349     if (origin == drwav_seek_origin_current) {
57350         maSeekOrigin =  ma_seek_origin_current;
57351     }
57352
57353     result = pWav->onSeek(pWav->pReadSeekTellUserData, offset, maSeekOrigin);
57354     if (result != MA_SUCCESS) {
57355         return MA_FALSE;
57356     }
57357
57358     return MA_TRUE;
57359 }
57360 #endif
57361
57362 static ma_result ma_wav_init_internal(const ma_decoding_backend_config* pConfig, ma_wav* pWav)
57363 {
57364     ma_result result;
57365     ma_data_source_config dataSourceConfig;
57366
57367     if (pWav == NULL) {
57368         return MA_INVALID_ARGS;
57369     }
57370
57371     MA_ZERO_OBJECT(pWav);
57372     pWav->format = ma_format_f32;    /* f32 by default. */
57373
57374     if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16 || pConfig->preferredFormat == ma_format_s32)) {
57375         pWav->format = pConfig->preferredFormat;
57376     } else {
57377         /* Getting here means something other than f32 and s16 was specified. Just leave this unset to use the default format. */
57378     }
57379
57380     dataSourceConfig = ma_data_source_config_init();
57381     dataSourceConfig.vtable = &g_ma_wav_ds_vtable;
57382
57383     result = ma_data_source_init(&dataSourceConfig, &pWav->ds);
57384     if (result != MA_SUCCESS) {
57385         return result;  /* Failed to initialize the base data source. */
57386     }
57387
57388     return MA_SUCCESS;
57389 }
57390
57391 MA_API ma_result ma_wav_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav)
57392 {
57393     ma_result result;
57394
57395     result = ma_wav_init_internal(pConfig, pWav);
57396     if (result != MA_SUCCESS) {
57397         return result;
57398     }
57399
57400     if (onRead == NULL || onSeek == NULL) {
57401         return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */
57402     }
57403
57404     pWav->onRead = onRead;
57405     pWav->onSeek = onSeek;
57406     pWav->onTell = onTell;
57407     pWav->pReadSeekTellUserData = pReadSeekTellUserData;
57408
57409     #if !defined(MA_NO_WAV)
57410     {
57411         drwav_allocation_callbacks wavAllocationCallbacks = drwav_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
57412         drwav_bool32 wavResult;
57413
57414         wavResult = drwav_init(&pWav->dr, ma_wav_dr_callback__read, ma_wav_dr_callback__seek, pWav, &wavAllocationCallbacks);
57415         if (wavResult != MA_TRUE) {
57416             return MA_INVALID_FILE;
57417         }
57418
57419         return MA_SUCCESS;
57420     }
57421     #else
57422     {
57423         /* wav is disabled. */
57424         (void)pAllocationCallbacks;
57425         return MA_NOT_IMPLEMENTED;
57426     }
57427     #endif
57428 }
57429
57430 MA_API ma_result ma_wav_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav)
57431 {
57432     ma_result result;
57433
57434     result = ma_wav_init_internal(pConfig, pWav);
57435     if (result != MA_SUCCESS) {
57436         return result;
57437     }
57438
57439     #if !defined(MA_NO_WAV)
57440     {
57441         drwav_allocation_callbacks wavAllocationCallbacks = drwav_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
57442         drwav_bool32 wavResult;
57443
57444         wavResult = drwav_init_file(&pWav->dr, pFilePath, &wavAllocationCallbacks);
57445         if (wavResult != MA_TRUE) {
57446             return MA_INVALID_FILE;
57447         }
57448
57449         return MA_SUCCESS;
57450     }
57451     #else
57452     {
57453         /* wav is disabled. */
57454         (void)pFilePath;
57455         (void)pAllocationCallbacks;
57456         return MA_NOT_IMPLEMENTED;
57457     }
57458     #endif
57459 }
57460
57461 MA_API ma_result ma_wav_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav)
57462 {
57463     ma_result result;
57464
57465     result = ma_wav_init_internal(pConfig, pWav);
57466     if (result != MA_SUCCESS) {
57467         return result;
57468     }
57469
57470     #if !defined(MA_NO_WAV)
57471     {
57472         drwav_allocation_callbacks wavAllocationCallbacks = drwav_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
57473         drwav_bool32 wavResult;
57474
57475         wavResult = drwav_init_file_w(&pWav->dr, pFilePath, &wavAllocationCallbacks);
57476         if (wavResult != MA_TRUE) {
57477             return MA_INVALID_FILE;
57478         }
57479
57480         return MA_SUCCESS;
57481     }
57482     #else
57483     {
57484         /* wav is disabled. */
57485         (void)pFilePath;
57486         (void)pAllocationCallbacks;
57487         return MA_NOT_IMPLEMENTED;
57488     }
57489     #endif
57490 }
57491
57492 MA_API ma_result ma_wav_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_wav* pWav)
57493 {
57494     ma_result result;
57495
57496     result = ma_wav_init_internal(pConfig, pWav);
57497     if (result != MA_SUCCESS) {
57498         return result;
57499     }
57500
57501     #if !defined(MA_NO_WAV)
57502     {
57503         drwav_allocation_callbacks wavAllocationCallbacks = drwav_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
57504         drwav_bool32 wavResult;
57505
57506         wavResult = drwav_init_memory(&pWav->dr, pData, dataSize, &wavAllocationCallbacks);
57507         if (wavResult != MA_TRUE) {
57508             return MA_INVALID_FILE;
57509         }
57510
57511         return MA_SUCCESS;
57512     }
57513     #else
57514     {
57515         /* wav is disabled. */
57516         (void)pData;
57517         (void)dataSize;
57518         (void)pAllocationCallbacks;
57519         return MA_NOT_IMPLEMENTED;
57520     }
57521     #endif
57522 }
57523
57524 MA_API void ma_wav_uninit(ma_wav* pWav, const ma_allocation_callbacks* pAllocationCallbacks)
57525 {
57526     if (pWav == NULL) {
57527         return;
57528     }
57529
57530     (void)pAllocationCallbacks;
57531
57532     #if !defined(MA_NO_WAV)
57533     {
57534         drwav_uninit(&pWav->dr);
57535     }
57536     #else
57537     {
57538         /* wav is disabled. Should never hit this since initialization would have failed. */
57539         MA_ASSERT(MA_FALSE);
57540     }
57541     #endif
57542
57543     ma_data_source_uninit(&pWav->ds);
57544 }
57545
57546 MA_API ma_result ma_wav_read_pcm_frames(ma_wav* pWav, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
57547 {
57548     if (pFramesRead != NULL) {
57549         *pFramesRead = 0;
57550     }
57551
57552     if (frameCount == 0) {
57553         return MA_INVALID_ARGS;
57554     }
57555
57556     if (pWav == NULL) {
57557         return MA_INVALID_ARGS;
57558     }
57559
57560     #if !defined(MA_NO_WAV)
57561     {
57562         /* We always use floating point format. */
57563         ma_result result = MA_SUCCESS;  /* Must be initialized to MA_SUCCESS. */
57564         ma_uint64 totalFramesRead = 0;
57565         ma_format format;
57566
57567         ma_wav_get_data_format(pWav, &format, NULL, NULL, NULL, 0);
57568
57569         switch (format)
57570         {
57571             case ma_format_f32:
57572             {
57573                 totalFramesRead = drwav_read_pcm_frames_f32(&pWav->dr, frameCount, (float*)pFramesOut);
57574             } break;
57575
57576             case ma_format_s16:
57577             {
57578                 totalFramesRead = drwav_read_pcm_frames_s16(&pWav->dr, frameCount, (drwav_int16*)pFramesOut);
57579             } break;
57580
57581             case ma_format_s32:
57582             {
57583                 totalFramesRead = drwav_read_pcm_frames_s32(&pWav->dr, frameCount, (drwav_int32*)pFramesOut);
57584             } break;
57585
57586             /* Fallback to a raw read. */
57587             case ma_format_unknown: return MA_INVALID_OPERATION; /* <-- this should never be hit because initialization would just fall back to supported format. */
57588             default:
57589             {
57590                 totalFramesRead = drwav_read_pcm_frames(&pWav->dr, frameCount, pFramesOut);
57591             } break;
57592         }
57593
57594         /* In the future we'll update dr_wav to return MA_AT_END for us. */
57595         if (totalFramesRead == 0) {
57596             result = MA_AT_END;
57597         }
57598
57599         if (pFramesRead != NULL) {
57600             *pFramesRead = totalFramesRead;
57601         }
57602
57603         if (result == MA_SUCCESS && totalFramesRead == 0) {
57604             result  = MA_AT_END;
57605         }
57606
57607         return result;
57608     }
57609     #else
57610     {
57611         /* wav is disabled. Should never hit this since initialization would have failed. */
57612         MA_ASSERT(MA_FALSE);
57613
57614         (void)pFramesOut;
57615         (void)frameCount;
57616         (void)pFramesRead;
57617
57618         return MA_NOT_IMPLEMENTED;
57619     }
57620     #endif
57621 }
57622
57623 MA_API ma_result ma_wav_seek_to_pcm_frame(ma_wav* pWav, ma_uint64 frameIndex)
57624 {
57625     if (pWav == NULL) {
57626         return MA_INVALID_ARGS;
57627     }
57628
57629     #if !defined(MA_NO_WAV)
57630     {
57631         drwav_bool32 wavResult;
57632
57633         wavResult = drwav_seek_to_pcm_frame(&pWav->dr, frameIndex);
57634         if (wavResult != DRWAV_TRUE) {
57635             return MA_ERROR;
57636         }
57637
57638         return MA_SUCCESS;
57639     }
57640     #else
57641     {
57642         /* wav is disabled. Should never hit this since initialization would have failed. */
57643         MA_ASSERT(MA_FALSE);
57644
57645         (void)frameIndex;
57646
57647         return MA_NOT_IMPLEMENTED;
57648     }
57649     #endif
57650 }
57651
57652 MA_API ma_result ma_wav_get_data_format(ma_wav* pWav, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
57653 {
57654     /* Defaults for safety. */
57655     if (pFormat != NULL) {
57656         *pFormat = ma_format_unknown;
57657     }
57658     if (pChannels != NULL) {
57659         *pChannels = 0;
57660     }
57661     if (pSampleRate != NULL) {
57662         *pSampleRate = 0;
57663     }
57664     if (pChannelMap != NULL) {
57665         MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
57666     }
57667
57668     if (pWav == NULL) {
57669         return MA_INVALID_OPERATION;
57670     }
57671
57672     if (pFormat != NULL) {
57673         *pFormat = pWav->format;
57674     }
57675
57676     #if !defined(MA_NO_WAV)
57677     {
57678         if (pChannels != NULL) {
57679             *pChannels = pWav->dr.channels;
57680         }
57681
57682         if (pSampleRate != NULL) {
57683             *pSampleRate = pWav->dr.sampleRate;
57684         }
57685
57686         if (pChannelMap != NULL) {
57687             ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pChannelMap, channelMapCap, pWav->dr.channels);
57688         }
57689
57690         return MA_SUCCESS;
57691     }
57692     #else
57693     {
57694         /* wav is disabled. Should never hit this since initialization would have failed. */
57695         MA_ASSERT(MA_FALSE);
57696         return MA_NOT_IMPLEMENTED;
57697     }
57698     #endif
57699 }
57700
57701 MA_API ma_result ma_wav_get_cursor_in_pcm_frames(ma_wav* pWav, ma_uint64* pCursor)
57702 {
57703     if (pCursor == NULL) {
57704         return MA_INVALID_ARGS;
57705     }
57706
57707     *pCursor = 0;   /* Safety. */
57708
57709     if (pWav == NULL) {
57710         return MA_INVALID_ARGS;
57711     }
57712
57713     #if !defined(MA_NO_WAV)
57714     {
57715         drwav_result wavResult = drwav_get_cursor_in_pcm_frames(&pWav->dr, pCursor);
57716         if (wavResult != DRWAV_SUCCESS) {
57717             return (ma_result)wavResult;    /* dr_wav result codes map to miniaudio's. */
57718         }
57719
57720         return MA_SUCCESS;
57721     }
57722     #else
57723     {
57724         /* wav is disabled. Should never hit this since initialization would have failed. */
57725         MA_ASSERT(MA_FALSE);
57726         return MA_NOT_IMPLEMENTED;
57727     }
57728     #endif
57729 }
57730
57731 MA_API ma_result ma_wav_get_length_in_pcm_frames(ma_wav* pWav, ma_uint64* pLength)
57732 {
57733     if (pLength == NULL) {
57734         return MA_INVALID_ARGS;
57735     }
57736
57737     *pLength = 0;   /* Safety. */
57738
57739     if (pWav == NULL) {
57740         return MA_INVALID_ARGS;
57741     }
57742
57743     #if !defined(MA_NO_WAV)
57744     {
57745         drwav_result wavResult = drwav_get_length_in_pcm_frames(&pWav->dr, pLength);
57746         if (wavResult != DRWAV_SUCCESS) {
57747             return (ma_result)wavResult;    /* dr_wav result codes map to miniaudio's. */
57748         }
57749
57750         return MA_SUCCESS;
57751     }
57752     #else
57753     {
57754         /* wav is disabled. Should never hit this since initialization would have failed. */
57755         MA_ASSERT(MA_FALSE);
57756         return MA_NOT_IMPLEMENTED;
57757     }
57758     #endif
57759 }
57760
57761
57762 static ma_result ma_decoding_backend_init__wav(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
57763 {
57764     ma_result result;
57765     ma_wav* pWav;
57766
57767     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
57768
57769     /* For now we're just allocating the decoder backend on the heap. */
57770     pWav = (ma_wav*)ma_malloc(sizeof(*pWav), pAllocationCallbacks);
57771     if (pWav == NULL) {
57772         return MA_OUT_OF_MEMORY;
57773     }
57774
57775     result = ma_wav_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pWav);
57776     if (result != MA_SUCCESS) {
57777         ma_free(pWav, pAllocationCallbacks);
57778         return result;
57779     }
57780
57781     *ppBackend = pWav;
57782
57783     return MA_SUCCESS;
57784 }
57785
57786 static ma_result ma_decoding_backend_init_file__wav(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
57787 {
57788     ma_result result;
57789     ma_wav* pWav;
57790
57791     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
57792
57793     /* For now we're just allocating the decoder backend on the heap. */
57794     pWav = (ma_wav*)ma_malloc(sizeof(*pWav), pAllocationCallbacks);
57795     if (pWav == NULL) {
57796         return MA_OUT_OF_MEMORY;
57797     }
57798
57799     result = ma_wav_init_file(pFilePath, pConfig, pAllocationCallbacks, pWav);
57800     if (result != MA_SUCCESS) {
57801         ma_free(pWav, pAllocationCallbacks);
57802         return result;
57803     }
57804
57805     *ppBackend = pWav;
57806
57807     return MA_SUCCESS;
57808 }
57809
57810 static ma_result ma_decoding_backend_init_file_w__wav(void* pUserData, const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
57811 {
57812     ma_result result;
57813     ma_wav* pWav;
57814
57815     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
57816
57817     /* For now we're just allocating the decoder backend on the heap. */
57818     pWav = (ma_wav*)ma_malloc(sizeof(*pWav), pAllocationCallbacks);
57819     if (pWav == NULL) {
57820         return MA_OUT_OF_MEMORY;
57821     }
57822
57823     result = ma_wav_init_file_w(pFilePath, pConfig, pAllocationCallbacks, pWav);
57824     if (result != MA_SUCCESS) {
57825         ma_free(pWav, pAllocationCallbacks);
57826         return result;
57827     }
57828
57829     *ppBackend = pWav;
57830
57831     return MA_SUCCESS;
57832 }
57833
57834 static ma_result ma_decoding_backend_init_memory__wav(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
57835 {
57836     ma_result result;
57837     ma_wav* pWav;
57838
57839     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
57840
57841     /* For now we're just allocating the decoder backend on the heap. */
57842     pWav = (ma_wav*)ma_malloc(sizeof(*pWav), pAllocationCallbacks);
57843     if (pWav == NULL) {
57844         return MA_OUT_OF_MEMORY;
57845     }
57846
57847     result = ma_wav_init_memory(pData, dataSize, pConfig, pAllocationCallbacks, pWav);
57848     if (result != MA_SUCCESS) {
57849         ma_free(pWav, pAllocationCallbacks);
57850         return result;
57851     }
57852
57853     *ppBackend = pWav;
57854
57855     return MA_SUCCESS;
57856 }
57857
57858 static void ma_decoding_backend_uninit__wav(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks)
57859 {
57860     ma_wav* pWav = (ma_wav*)pBackend;
57861
57862     (void)pUserData;
57863
57864     ma_wav_uninit(pWav, pAllocationCallbacks);
57865     ma_free(pWav, pAllocationCallbacks);
57866 }
57867
57868 static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_wav =
57869 {
57870     ma_decoding_backend_init__wav,
57871     ma_decoding_backend_init_file__wav,
57872     ma_decoding_backend_init_file_w__wav,
57873     ma_decoding_backend_init_memory__wav,
57874     ma_decoding_backend_uninit__wav
57875 };
57876
57877 static ma_result ma_decoder_init_wav__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
57878 {
57879     return ma_decoder_init_from_vtable(&g_ma_decoding_backend_vtable_wav, NULL, pConfig, pDecoder);
57880 }
57881 #endif  /* dr_wav_h */
57882
57883 /* FLAC */
57884 #ifdef dr_flac_h
57885 #define MA_HAS_FLAC
57886
57887 typedef struct
57888 {
57889     ma_data_source_base ds;
57890     ma_read_proc onRead;
57891     ma_seek_proc onSeek;
57892     ma_tell_proc onTell;
57893     void* pReadSeekTellUserData;
57894     ma_format format;           /* Can be f32, s16 or s32. */
57895 #if !defined(MA_NO_FLAC)
57896     drflac* dr;
57897 #endif
57898 } ma_flac;
57899
57900 MA_API ma_result ma_flac_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac);
57901 MA_API ma_result ma_flac_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac);
57902 MA_API ma_result ma_flac_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac);
57903 MA_API ma_result ma_flac_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac);
57904 MA_API void ma_flac_uninit(ma_flac* pFlac, const ma_allocation_callbacks* pAllocationCallbacks);
57905 MA_API ma_result ma_flac_read_pcm_frames(ma_flac* pFlac, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
57906 MA_API ma_result ma_flac_seek_to_pcm_frame(ma_flac* pFlac, ma_uint64 frameIndex);
57907 MA_API ma_result ma_flac_get_data_format(ma_flac* pFlac, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
57908 MA_API ma_result ma_flac_get_cursor_in_pcm_frames(ma_flac* pFlac, ma_uint64* pCursor);
57909 MA_API ma_result ma_flac_get_length_in_pcm_frames(ma_flac* pFlac, ma_uint64* pLength);
57910
57911
57912 static ma_result ma_flac_ds_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
57913 {
57914     return ma_flac_read_pcm_frames((ma_flac*)pDataSource, pFramesOut, frameCount, pFramesRead);
57915 }
57916
57917 static ma_result ma_flac_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
57918 {
57919     return ma_flac_seek_to_pcm_frame((ma_flac*)pDataSource, frameIndex);
57920 }
57921
57922 static ma_result ma_flac_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
57923 {
57924     return ma_flac_get_data_format((ma_flac*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
57925 }
57926
57927 static ma_result ma_flac_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
57928 {
57929     return ma_flac_get_cursor_in_pcm_frames((ma_flac*)pDataSource, pCursor);
57930 }
57931
57932 static ma_result ma_flac_ds_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
57933 {
57934     return ma_flac_get_length_in_pcm_frames((ma_flac*)pDataSource, pLength);
57935 }
57936
57937 static ma_data_source_vtable g_ma_flac_ds_vtable =
57938 {
57939     ma_flac_ds_read,
57940     ma_flac_ds_seek,
57941     ma_flac_ds_get_data_format,
57942     ma_flac_ds_get_cursor,
57943     ma_flac_ds_get_length,
57944     NULL,   /* onSetLooping */
57945     0
57946 };
57947
57948
57949 #if !defined(MA_NO_FLAC)
57950 static drflac_allocation_callbacks drflac_allocation_callbacks_from_miniaudio(const ma_allocation_callbacks* pAllocationCallbacks)
57951 {
57952     drflac_allocation_callbacks callbacks;
57953
57954     if (pAllocationCallbacks != NULL) {
57955         callbacks.onMalloc  = pAllocationCallbacks->onMalloc;
57956         callbacks.onRealloc = pAllocationCallbacks->onRealloc;
57957         callbacks.onFree    = pAllocationCallbacks->onFree;
57958         callbacks.pUserData = pAllocationCallbacks->pUserData;
57959     } else {
57960         callbacks.onMalloc  = ma__malloc_default;
57961         callbacks.onRealloc = ma__realloc_default;
57962         callbacks.onFree    = ma__free_default;
57963         callbacks.pUserData = NULL;
57964     }
57965
57966     return callbacks;
57967 }
57968
57969 static size_t ma_flac_dr_callback__read(void* pUserData, void* pBufferOut, size_t bytesToRead)
57970 {
57971     ma_flac* pFlac = (ma_flac*)pUserData;
57972     ma_result result;
57973     size_t bytesRead;
57974
57975     MA_ASSERT(pFlac != NULL);
57976
57977     result = pFlac->onRead(pFlac->pReadSeekTellUserData, pBufferOut, bytesToRead, &bytesRead);
57978     (void)result;
57979
57980     return bytesRead;
57981 }
57982
57983 static drflac_bool32 ma_flac_dr_callback__seek(void* pUserData, int offset, drflac_seek_origin origin)
57984 {
57985     ma_flac* pFlac = (ma_flac*)pUserData;
57986     ma_result result;
57987     ma_seek_origin maSeekOrigin;
57988
57989     MA_ASSERT(pFlac != NULL);
57990
57991     maSeekOrigin = ma_seek_origin_start;
57992     if (origin == drflac_seek_origin_current) {
57993         maSeekOrigin =  ma_seek_origin_current;
57994     }
57995
57996     result = pFlac->onSeek(pFlac->pReadSeekTellUserData, offset, maSeekOrigin);
57997     if (result != MA_SUCCESS) {
57998         return MA_FALSE;
57999     }
58000
58001     return MA_TRUE;
58002 }
58003 #endif
58004
58005 static ma_result ma_flac_init_internal(const ma_decoding_backend_config* pConfig, ma_flac* pFlac)
58006 {
58007     ma_result result;
58008     ma_data_source_config dataSourceConfig;
58009
58010     if (pFlac == NULL) {
58011         return MA_INVALID_ARGS;
58012     }
58013
58014     MA_ZERO_OBJECT(pFlac);
58015     pFlac->format = ma_format_f32;    /* f32 by default. */
58016
58017     if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16 || pConfig->preferredFormat == ma_format_s32)) {
58018         pFlac->format = pConfig->preferredFormat;
58019     } else {
58020         /* Getting here means something other than f32 and s16 was specified. Just leave this unset to use the default format. */
58021     }
58022
58023     dataSourceConfig = ma_data_source_config_init();
58024     dataSourceConfig.vtable = &g_ma_flac_ds_vtable;
58025
58026     result = ma_data_source_init(&dataSourceConfig, &pFlac->ds);
58027     if (result != MA_SUCCESS) {
58028         return result;  /* Failed to initialize the base data source. */
58029     }
58030
58031     return MA_SUCCESS;
58032 }
58033
58034 MA_API ma_result ma_flac_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac)
58035 {
58036     ma_result result;
58037
58038     result = ma_flac_init_internal(pConfig, pFlac);
58039     if (result != MA_SUCCESS) {
58040         return result;
58041     }
58042
58043     if (onRead == NULL || onSeek == NULL) {
58044         return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */
58045     }
58046
58047     pFlac->onRead = onRead;
58048     pFlac->onSeek = onSeek;
58049     pFlac->onTell = onTell;
58050     pFlac->pReadSeekTellUserData = pReadSeekTellUserData;
58051
58052     #if !defined(MA_NO_FLAC)
58053     {
58054         drflac_allocation_callbacks flacAllocationCallbacks = drflac_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
58055
58056         pFlac->dr = drflac_open(ma_flac_dr_callback__read, ma_flac_dr_callback__seek, pFlac, &flacAllocationCallbacks);
58057         if (pFlac->dr == NULL) {
58058             return MA_INVALID_FILE;
58059         }
58060
58061         return MA_SUCCESS;
58062     }
58063     #else
58064     {
58065         /* flac is disabled. */
58066         (void)pAllocationCallbacks;
58067         return MA_NOT_IMPLEMENTED;
58068     }
58069     #endif
58070 }
58071
58072 MA_API ma_result ma_flac_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac)
58073 {
58074     ma_result result;
58075
58076     result = ma_flac_init_internal(pConfig, pFlac);
58077     if (result != MA_SUCCESS) {
58078         return result;
58079     }
58080
58081     #if !defined(MA_NO_FLAC)
58082     {
58083         drflac_allocation_callbacks flacAllocationCallbacks = drflac_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
58084
58085         pFlac->dr = drflac_open_file(pFilePath, &flacAllocationCallbacks);
58086         if (pFlac->dr == NULL) {
58087             return MA_INVALID_FILE;
58088         }
58089
58090         return MA_SUCCESS;
58091     }
58092     #else
58093     {
58094         /* flac is disabled. */
58095         (void)pFilePath;
58096         (void)pAllocationCallbacks;
58097         return MA_NOT_IMPLEMENTED;
58098     }
58099     #endif
58100 }
58101
58102 MA_API ma_result ma_flac_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac)
58103 {
58104     ma_result result;
58105
58106     result = ma_flac_init_internal(pConfig, pFlac);
58107     if (result != MA_SUCCESS) {
58108         return result;
58109     }
58110
58111     #if !defined(MA_NO_FLAC)
58112     {
58113         drflac_allocation_callbacks flacAllocationCallbacks = drflac_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
58114
58115         pFlac->dr = drflac_open_file_w(pFilePath, &flacAllocationCallbacks);
58116         if (pFlac->dr == NULL) {
58117             return MA_INVALID_FILE;
58118         }
58119
58120         return MA_SUCCESS;
58121     }
58122     #else
58123     {
58124         /* flac is disabled. */
58125         (void)pFilePath;
58126         (void)pAllocationCallbacks;
58127         return MA_NOT_IMPLEMENTED;
58128     }
58129     #endif
58130 }
58131
58132 MA_API ma_result ma_flac_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_flac* pFlac)
58133 {
58134     ma_result result;
58135
58136     result = ma_flac_init_internal(pConfig, pFlac);
58137     if (result != MA_SUCCESS) {
58138         return result;
58139     }
58140
58141     #if !defined(MA_NO_FLAC)
58142     {
58143         drflac_allocation_callbacks flacAllocationCallbacks = drflac_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
58144
58145         pFlac->dr = drflac_open_memory(pData, dataSize, &flacAllocationCallbacks);
58146         if (pFlac->dr == NULL) {
58147             return MA_INVALID_FILE;
58148         }
58149
58150         return MA_SUCCESS;
58151     }
58152     #else
58153     {
58154         /* flac is disabled. */
58155         (void)pData;
58156         (void)dataSize;
58157         (void)pAllocationCallbacks;
58158         return MA_NOT_IMPLEMENTED;
58159     }
58160     #endif
58161 }
58162
58163 MA_API void ma_flac_uninit(ma_flac* pFlac, const ma_allocation_callbacks* pAllocationCallbacks)
58164 {
58165     if (pFlac == NULL) {
58166         return;
58167     }
58168
58169     (void)pAllocationCallbacks;
58170
58171     #if !defined(MA_NO_FLAC)
58172     {
58173         drflac_close(pFlac->dr);
58174     }
58175     #else
58176     {
58177         /* flac is disabled. Should never hit this since initialization would have failed. */
58178         MA_ASSERT(MA_FALSE);
58179     }
58180     #endif
58181
58182     ma_data_source_uninit(&pFlac->ds);
58183 }
58184
58185 MA_API ma_result ma_flac_read_pcm_frames(ma_flac* pFlac, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
58186 {
58187     if (pFramesRead != NULL) {
58188         *pFramesRead = 0;
58189     }
58190
58191     if (frameCount == 0) {
58192         return MA_INVALID_ARGS;
58193     }
58194
58195     if (pFlac == NULL) {
58196         return MA_INVALID_ARGS;
58197     }
58198
58199     #if !defined(MA_NO_FLAC)
58200     {
58201         /* We always use floating point format. */
58202         ma_result result = MA_SUCCESS;  /* Must be initialized to MA_SUCCESS. */
58203         ma_uint64 totalFramesRead = 0;
58204         ma_format format;
58205
58206         ma_flac_get_data_format(pFlac, &format, NULL, NULL, NULL, 0);
58207
58208         switch (format)
58209         {
58210             case ma_format_f32:
58211             {
58212                 totalFramesRead = drflac_read_pcm_frames_f32(pFlac->dr, frameCount, (float*)pFramesOut);
58213             } break;
58214
58215             case ma_format_s16:
58216             {
58217                 totalFramesRead = drflac_read_pcm_frames_s16(pFlac->dr, frameCount, (drflac_int16*)pFramesOut);
58218             } break;
58219
58220             case ma_format_s32:
58221             {
58222                 totalFramesRead = drflac_read_pcm_frames_s32(pFlac->dr, frameCount, (drflac_int32*)pFramesOut);
58223             } break;
58224
58225             case ma_format_u8:
58226             case ma_format_s24:
58227             case ma_format_unknown:
58228             default:
58229             {
58230                 return MA_INVALID_OPERATION;
58231             };
58232         }
58233
58234         /* In the future we'll update dr_flac to return MA_AT_END for us. */
58235         if (totalFramesRead == 0) {
58236             result = MA_AT_END;
58237         }
58238
58239         if (pFramesRead != NULL) {
58240             *pFramesRead = totalFramesRead;
58241         }
58242
58243         if (result == MA_SUCCESS && totalFramesRead == 0) {
58244             result  = MA_AT_END;
58245         }
58246
58247         return result;
58248     }
58249     #else
58250     {
58251         /* flac is disabled. Should never hit this since initialization would have failed. */
58252         MA_ASSERT(MA_FALSE);
58253
58254         (void)pFramesOut;
58255         (void)frameCount;
58256         (void)pFramesRead;
58257
58258         return MA_NOT_IMPLEMENTED;
58259     }
58260     #endif
58261 }
58262
58263 MA_API ma_result ma_flac_seek_to_pcm_frame(ma_flac* pFlac, ma_uint64 frameIndex)
58264 {
58265     if (pFlac == NULL) {
58266         return MA_INVALID_ARGS;
58267     }
58268
58269     #if !defined(MA_NO_FLAC)
58270     {
58271         drflac_bool32 flacResult;
58272
58273         flacResult = drflac_seek_to_pcm_frame(pFlac->dr, frameIndex);
58274         if (flacResult != DRFLAC_TRUE) {
58275             return MA_ERROR;
58276         }
58277
58278         return MA_SUCCESS;
58279     }
58280     #else
58281     {
58282         /* flac is disabled. Should never hit this since initialization would have failed. */
58283         MA_ASSERT(MA_FALSE);
58284
58285         (void)frameIndex;
58286
58287         return MA_NOT_IMPLEMENTED;
58288     }
58289     #endif
58290 }
58291
58292 MA_API ma_result ma_flac_get_data_format(ma_flac* pFlac, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
58293 {
58294     /* Defaults for safety. */
58295     if (pFormat != NULL) {
58296         *pFormat = ma_format_unknown;
58297     }
58298     if (pChannels != NULL) {
58299         *pChannels = 0;
58300     }
58301     if (pSampleRate != NULL) {
58302         *pSampleRate = 0;
58303     }
58304     if (pChannelMap != NULL) {
58305         MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
58306     }
58307
58308     if (pFlac == NULL) {
58309         return MA_INVALID_OPERATION;
58310     }
58311
58312     if (pFormat != NULL) {
58313         *pFormat = pFlac->format;
58314     }
58315
58316     #if !defined(MA_NO_FLAC)
58317     {
58318         if (pChannels != NULL) {
58319             *pChannels = pFlac->dr->channels;
58320         }
58321
58322         if (pSampleRate != NULL) {
58323             *pSampleRate = pFlac->dr->sampleRate;
58324         }
58325
58326         if (pChannelMap != NULL) {
58327             ma_channel_map_init_standard(ma_standard_channel_map_microsoft, pChannelMap, channelMapCap, pFlac->dr->channels);
58328         }
58329
58330         return MA_SUCCESS;
58331     }
58332     #else
58333     {
58334         /* flac is disabled. Should never hit this since initialization would have failed. */
58335         MA_ASSERT(MA_FALSE);
58336         return MA_NOT_IMPLEMENTED;
58337     }
58338     #endif
58339 }
58340
58341 MA_API ma_result ma_flac_get_cursor_in_pcm_frames(ma_flac* pFlac, ma_uint64* pCursor)
58342 {
58343     if (pCursor == NULL) {
58344         return MA_INVALID_ARGS;
58345     }
58346
58347     *pCursor = 0;   /* Safety. */
58348
58349     if (pFlac == NULL) {
58350         return MA_INVALID_ARGS;
58351     }
58352
58353     #if !defined(MA_NO_FLAC)
58354     {
58355         *pCursor = pFlac->dr->currentPCMFrame;
58356
58357         return MA_SUCCESS;
58358     }
58359     #else
58360     {
58361         /* flac is disabled. Should never hit this since initialization would have failed. */
58362         MA_ASSERT(MA_FALSE);
58363         return MA_NOT_IMPLEMENTED;
58364     }
58365     #endif
58366 }
58367
58368 MA_API ma_result ma_flac_get_length_in_pcm_frames(ma_flac* pFlac, ma_uint64* pLength)
58369 {
58370     if (pLength == NULL) {
58371         return MA_INVALID_ARGS;
58372     }
58373
58374     *pLength = 0;   /* Safety. */
58375
58376     if (pFlac == NULL) {
58377         return MA_INVALID_ARGS;
58378     }
58379
58380     #if !defined(MA_NO_FLAC)
58381     {
58382         *pLength = pFlac->dr->totalPCMFrameCount;
58383
58384         return MA_SUCCESS;
58385     }
58386     #else
58387     {
58388         /* flac is disabled. Should never hit this since initialization would have failed. */
58389         MA_ASSERT(MA_FALSE);
58390         return MA_NOT_IMPLEMENTED;
58391     }
58392     #endif
58393 }
58394
58395
58396 static ma_result ma_decoding_backend_init__flac(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
58397 {
58398     ma_result result;
58399     ma_flac* pFlac;
58400
58401     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
58402
58403     /* For now we're just allocating the decoder backend on the heap. */
58404     pFlac = (ma_flac*)ma_malloc(sizeof(*pFlac), pAllocationCallbacks);
58405     if (pFlac == NULL) {
58406         return MA_OUT_OF_MEMORY;
58407     }
58408
58409     result = ma_flac_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pFlac);
58410     if (result != MA_SUCCESS) {
58411         ma_free(pFlac, pAllocationCallbacks);
58412         return result;
58413     }
58414
58415     *ppBackend = pFlac;
58416
58417     return MA_SUCCESS;
58418 }
58419
58420 static ma_result ma_decoding_backend_init_file__flac(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
58421 {
58422     ma_result result;
58423     ma_flac* pFlac;
58424
58425     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
58426
58427     /* For now we're just allocating the decoder backend on the heap. */
58428     pFlac = (ma_flac*)ma_malloc(sizeof(*pFlac), pAllocationCallbacks);
58429     if (pFlac == NULL) {
58430         return MA_OUT_OF_MEMORY;
58431     }
58432
58433     result = ma_flac_init_file(pFilePath, pConfig, pAllocationCallbacks, pFlac);
58434     if (result != MA_SUCCESS) {
58435         ma_free(pFlac, pAllocationCallbacks);
58436         return result;
58437     }
58438
58439     *ppBackend = pFlac;
58440
58441     return MA_SUCCESS;
58442 }
58443
58444 static ma_result ma_decoding_backend_init_file_w__flac(void* pUserData, const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
58445 {
58446     ma_result result;
58447     ma_flac* pFlac;
58448
58449     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
58450
58451     /* For now we're just allocating the decoder backend on the heap. */
58452     pFlac = (ma_flac*)ma_malloc(sizeof(*pFlac), pAllocationCallbacks);
58453     if (pFlac == NULL) {
58454         return MA_OUT_OF_MEMORY;
58455     }
58456
58457     result = ma_flac_init_file_w(pFilePath, pConfig, pAllocationCallbacks, pFlac);
58458     if (result != MA_SUCCESS) {
58459         ma_free(pFlac, pAllocationCallbacks);
58460         return result;
58461     }
58462
58463     *ppBackend = pFlac;
58464
58465     return MA_SUCCESS;
58466 }
58467
58468 static ma_result ma_decoding_backend_init_memory__flac(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
58469 {
58470     ma_result result;
58471     ma_flac* pFlac;
58472
58473     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
58474
58475     /* For now we're just allocating the decoder backend on the heap. */
58476     pFlac = (ma_flac*)ma_malloc(sizeof(*pFlac), pAllocationCallbacks);
58477     if (pFlac == NULL) {
58478         return MA_OUT_OF_MEMORY;
58479     }
58480
58481     result = ma_flac_init_memory(pData, dataSize, pConfig, pAllocationCallbacks, pFlac);
58482     if (result != MA_SUCCESS) {
58483         ma_free(pFlac, pAllocationCallbacks);
58484         return result;
58485     }
58486
58487     *ppBackend = pFlac;
58488
58489     return MA_SUCCESS;
58490 }
58491
58492 static void ma_decoding_backend_uninit__flac(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks)
58493 {
58494     ma_flac* pFlac = (ma_flac*)pBackend;
58495
58496     (void)pUserData;
58497
58498     ma_flac_uninit(pFlac, pAllocationCallbacks);
58499     ma_free(pFlac, pAllocationCallbacks);
58500 }
58501
58502 static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_flac =
58503 {
58504     ma_decoding_backend_init__flac,
58505     ma_decoding_backend_init_file__flac,
58506     ma_decoding_backend_init_file_w__flac,
58507     ma_decoding_backend_init_memory__flac,
58508     ma_decoding_backend_uninit__flac
58509 };
58510
58511 static ma_result ma_decoder_init_flac__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
58512 {
58513     return ma_decoder_init_from_vtable(&g_ma_decoding_backend_vtable_flac, NULL, pConfig, pDecoder);
58514 }
58515 #endif  /* dr_flac_h */
58516
58517 /* MP3 */
58518 #ifdef dr_mp3_h
58519 #define MA_HAS_MP3
58520
58521 typedef struct
58522 {
58523     ma_data_source_base ds;
58524     ma_read_proc onRead;
58525     ma_seek_proc onSeek;
58526     ma_tell_proc onTell;
58527     void* pReadSeekTellUserData;
58528     ma_format format;           /* Can be f32 or s16. */
58529 #if !defined(MA_NO_MP3)
58530     drmp3 dr;
58531     drmp3_uint32 seekPointCount;
58532     drmp3_seek_point* pSeekPoints;  /* Only used if seek table generation is used. */
58533 #endif
58534 } ma_mp3;
58535
58536 MA_API ma_result ma_mp3_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3);
58537 MA_API ma_result ma_mp3_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3);
58538 MA_API ma_result ma_mp3_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3);
58539 MA_API ma_result ma_mp3_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3);
58540 MA_API void ma_mp3_uninit(ma_mp3* pMP3, const ma_allocation_callbacks* pAllocationCallbacks);
58541 MA_API ma_result ma_mp3_read_pcm_frames(ma_mp3* pMP3, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
58542 MA_API ma_result ma_mp3_seek_to_pcm_frame(ma_mp3* pMP3, ma_uint64 frameIndex);
58543 MA_API ma_result ma_mp3_get_data_format(ma_mp3* pMP3, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
58544 MA_API ma_result ma_mp3_get_cursor_in_pcm_frames(ma_mp3* pMP3, ma_uint64* pCursor);
58545 MA_API ma_result ma_mp3_get_length_in_pcm_frames(ma_mp3* pMP3, ma_uint64* pLength);
58546
58547
58548 static ma_result ma_mp3_ds_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
58549 {
58550     return ma_mp3_read_pcm_frames((ma_mp3*)pDataSource, pFramesOut, frameCount, pFramesRead);
58551 }
58552
58553 static ma_result ma_mp3_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
58554 {
58555     return ma_mp3_seek_to_pcm_frame((ma_mp3*)pDataSource, frameIndex);
58556 }
58557
58558 static ma_result ma_mp3_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
58559 {
58560     return ma_mp3_get_data_format((ma_mp3*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
58561 }
58562
58563 static ma_result ma_mp3_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
58564 {
58565     return ma_mp3_get_cursor_in_pcm_frames((ma_mp3*)pDataSource, pCursor);
58566 }
58567
58568 static ma_result ma_mp3_ds_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
58569 {
58570     return ma_mp3_get_length_in_pcm_frames((ma_mp3*)pDataSource, pLength);
58571 }
58572
58573 static ma_data_source_vtable g_ma_mp3_ds_vtable =
58574 {
58575     ma_mp3_ds_read,
58576     ma_mp3_ds_seek,
58577     ma_mp3_ds_get_data_format,
58578     ma_mp3_ds_get_cursor,
58579     ma_mp3_ds_get_length,
58580     NULL,   /* onSetLooping */
58581     0
58582 };
58583
58584
58585 #if !defined(MA_NO_MP3)
58586 static drmp3_allocation_callbacks drmp3_allocation_callbacks_from_miniaudio(const ma_allocation_callbacks* pAllocationCallbacks)
58587 {
58588     drmp3_allocation_callbacks callbacks;
58589
58590     if (pAllocationCallbacks != NULL) {
58591         callbacks.onMalloc  = pAllocationCallbacks->onMalloc;
58592         callbacks.onRealloc = pAllocationCallbacks->onRealloc;
58593         callbacks.onFree    = pAllocationCallbacks->onFree;
58594         callbacks.pUserData = pAllocationCallbacks->pUserData;
58595     } else {
58596         callbacks.onMalloc  = ma__malloc_default;
58597         callbacks.onRealloc = ma__realloc_default;
58598         callbacks.onFree    = ma__free_default;
58599         callbacks.pUserData = NULL;
58600     }
58601
58602     return callbacks;
58603 }
58604
58605 static size_t ma_mp3_dr_callback__read(void* pUserData, void* pBufferOut, size_t bytesToRead)
58606 {
58607     ma_mp3* pMP3 = (ma_mp3*)pUserData;
58608     ma_result result;
58609     size_t bytesRead;
58610
58611     MA_ASSERT(pMP3 != NULL);
58612
58613     result = pMP3->onRead(pMP3->pReadSeekTellUserData, pBufferOut, bytesToRead, &bytesRead);
58614     (void)result;
58615
58616     return bytesRead;
58617 }
58618
58619 static drmp3_bool32 ma_mp3_dr_callback__seek(void* pUserData, int offset, drmp3_seek_origin origin)
58620 {
58621     ma_mp3* pMP3 = (ma_mp3*)pUserData;
58622     ma_result result;
58623     ma_seek_origin maSeekOrigin;
58624
58625     MA_ASSERT(pMP3 != NULL);
58626
58627     maSeekOrigin = ma_seek_origin_start;
58628     if (origin == drmp3_seek_origin_current) {
58629         maSeekOrigin =  ma_seek_origin_current;
58630     }
58631
58632     result = pMP3->onSeek(pMP3->pReadSeekTellUserData, offset, maSeekOrigin);
58633     if (result != MA_SUCCESS) {
58634         return MA_FALSE;
58635     }
58636
58637     return MA_TRUE;
58638 }
58639 #endif
58640
58641 static ma_result ma_mp3_init_internal(const ma_decoding_backend_config* pConfig, ma_mp3* pMP3)
58642 {
58643     ma_result result;
58644     ma_data_source_config dataSourceConfig;
58645
58646     if (pMP3 == NULL) {
58647         return MA_INVALID_ARGS;
58648     }
58649
58650     MA_ZERO_OBJECT(pMP3);
58651     pMP3->format = ma_format_f32;    /* f32 by default. */
58652
58653     if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16)) {
58654         pMP3->format = pConfig->preferredFormat;
58655     } else {
58656         /* Getting here means something other than f32 and s16 was specified. Just leave this unset to use the default format. */
58657     }
58658
58659     dataSourceConfig = ma_data_source_config_init();
58660     dataSourceConfig.vtable = &g_ma_mp3_ds_vtable;
58661
58662     result = ma_data_source_init(&dataSourceConfig, &pMP3->ds);
58663     if (result != MA_SUCCESS) {
58664         return result;  /* Failed to initialize the base data source. */
58665     }
58666
58667     return MA_SUCCESS;
58668 }
58669
58670 static ma_result ma_mp3_generate_seek_table(ma_mp3* pMP3, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks)
58671 {
58672     drmp3_bool32 mp3Result;
58673     drmp3_uint32 seekPointCount = 0;
58674     drmp3_seek_point* pSeekPoints = NULL;
58675
58676     MA_ASSERT(pMP3    != NULL);
58677     MA_ASSERT(pConfig != NULL);
58678
58679     seekPointCount = pConfig->seekPointCount;
58680     if (seekPointCount > 0) {
58681         pSeekPoints = (drmp3_seek_point*)ma_malloc(sizeof(*pMP3->pSeekPoints) * seekPointCount, pAllocationCallbacks);
58682         if (pSeekPoints == NULL) {
58683             return MA_OUT_OF_MEMORY;
58684         }
58685     }
58686
58687     mp3Result = drmp3_calculate_seek_points(&pMP3->dr, &seekPointCount, pSeekPoints);
58688     if (mp3Result != MA_TRUE) {
58689         return MA_ERROR;
58690     }
58691
58692     mp3Result = drmp3_bind_seek_table(&pMP3->dr, seekPointCount, pSeekPoints);
58693     if (mp3Result != MA_TRUE) {
58694         ma_free(pSeekPoints, pAllocationCallbacks);
58695         return MA_ERROR;
58696     }
58697
58698     pMP3->seekPointCount = seekPointCount;
58699     pMP3->pSeekPoints    = pSeekPoints;
58700
58701     return MA_SUCCESS;
58702 }
58703
58704 MA_API ma_result ma_mp3_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3)
58705 {
58706     ma_result result;
58707
58708     result = ma_mp3_init_internal(pConfig, pMP3);
58709     if (result != MA_SUCCESS) {
58710         return result;
58711     }
58712
58713     if (onRead == NULL || onSeek == NULL) {
58714         return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */
58715     }
58716
58717     pMP3->onRead = onRead;
58718     pMP3->onSeek = onSeek;
58719     pMP3->onTell = onTell;
58720     pMP3->pReadSeekTellUserData = pReadSeekTellUserData;
58721
58722     #if !defined(MA_NO_MP3)
58723     {
58724         drmp3_allocation_callbacks mp3AllocationCallbacks = drmp3_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
58725         drmp3_bool32 mp3Result;
58726
58727         mp3Result = drmp3_init(&pMP3->dr, ma_mp3_dr_callback__read, ma_mp3_dr_callback__seek, pMP3, &mp3AllocationCallbacks);
58728         if (mp3Result != MA_TRUE) {
58729             return MA_INVALID_FILE;
58730         }
58731
58732         ma_mp3_generate_seek_table(pMP3, pConfig, pAllocationCallbacks);
58733
58734         return MA_SUCCESS;
58735     }
58736     #else
58737     {
58738         /* mp3 is disabled. */
58739         (void)pAllocationCallbacks;
58740         return MA_NOT_IMPLEMENTED;
58741     }
58742     #endif
58743 }
58744
58745 MA_API ma_result ma_mp3_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3)
58746 {
58747     ma_result result;
58748
58749     result = ma_mp3_init_internal(pConfig, pMP3);
58750     if (result != MA_SUCCESS) {
58751         return result;
58752     }
58753
58754     #if !defined(MA_NO_MP3)
58755     {
58756         drmp3_allocation_callbacks mp3AllocationCallbacks = drmp3_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
58757         drmp3_bool32 mp3Result;
58758
58759         mp3Result = drmp3_init_file(&pMP3->dr, pFilePath, &mp3AllocationCallbacks);
58760         if (mp3Result != MA_TRUE) {
58761             return MA_INVALID_FILE;
58762         }
58763
58764         ma_mp3_generate_seek_table(pMP3, pConfig, pAllocationCallbacks);
58765
58766         return MA_SUCCESS;
58767     }
58768     #else
58769     {
58770         /* mp3 is disabled. */
58771         (void)pFilePath;
58772         (void)pAllocationCallbacks;
58773         return MA_NOT_IMPLEMENTED;
58774     }
58775     #endif
58776 }
58777
58778 MA_API ma_result ma_mp3_init_file_w(const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3)
58779 {
58780     ma_result result;
58781
58782     result = ma_mp3_init_internal(pConfig, pMP3);
58783     if (result != MA_SUCCESS) {
58784         return result;
58785     }
58786
58787     #if !defined(MA_NO_MP3)
58788     {
58789         drmp3_allocation_callbacks mp3AllocationCallbacks = drmp3_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
58790         drmp3_bool32 mp3Result;
58791
58792         mp3Result = drmp3_init_file_w(&pMP3->dr, pFilePath, &mp3AllocationCallbacks);
58793         if (mp3Result != MA_TRUE) {
58794             return MA_INVALID_FILE;
58795         }
58796
58797         ma_mp3_generate_seek_table(pMP3, pConfig, pAllocationCallbacks);
58798
58799         return MA_SUCCESS;
58800     }
58801     #else
58802     {
58803         /* mp3 is disabled. */
58804         (void)pFilePath;
58805         (void)pAllocationCallbacks;
58806         return MA_NOT_IMPLEMENTED;
58807     }
58808     #endif
58809 }
58810
58811 MA_API ma_result ma_mp3_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_mp3* pMP3)
58812 {
58813     ma_result result;
58814
58815     result = ma_mp3_init_internal(pConfig, pMP3);
58816     if (result != MA_SUCCESS) {
58817         return result;
58818     }
58819
58820     #if !defined(MA_NO_MP3)
58821     {
58822         drmp3_allocation_callbacks mp3AllocationCallbacks = drmp3_allocation_callbacks_from_miniaudio(pAllocationCallbacks);
58823         drmp3_bool32 mp3Result;
58824
58825         mp3Result = drmp3_init_memory(&pMP3->dr, pData, dataSize, &mp3AllocationCallbacks);
58826         if (mp3Result != MA_TRUE) {
58827             return MA_INVALID_FILE;
58828         }
58829
58830         ma_mp3_generate_seek_table(pMP3, pConfig, pAllocationCallbacks);
58831
58832         return MA_SUCCESS;
58833     }
58834     #else
58835     {
58836         /* mp3 is disabled. */
58837         (void)pData;
58838         (void)dataSize;
58839         (void)pAllocationCallbacks;
58840         return MA_NOT_IMPLEMENTED;
58841     }
58842     #endif
58843 }
58844
58845 MA_API void ma_mp3_uninit(ma_mp3* pMP3, const ma_allocation_callbacks* pAllocationCallbacks)
58846 {
58847     if (pMP3 == NULL) {
58848         return;
58849     }
58850
58851     #if !defined(MA_NO_MP3)
58852     {
58853         drmp3_uninit(&pMP3->dr);
58854     }
58855     #else
58856     {
58857         /* mp3 is disabled. Should never hit this since initialization would have failed. */
58858         MA_ASSERT(MA_FALSE);
58859     }
58860     #endif
58861
58862     /* Seek points need to be freed after the MP3 decoder has been uninitialized to ensure they're no longer being referenced. */
58863     ma_free(pMP3->pSeekPoints, pAllocationCallbacks);
58864
58865     ma_data_source_uninit(&pMP3->ds);
58866 }
58867
58868 MA_API ma_result ma_mp3_read_pcm_frames(ma_mp3* pMP3, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
58869 {
58870     if (pFramesRead != NULL) {
58871         *pFramesRead = 0;
58872     }
58873
58874     if (frameCount == 0) {
58875         return MA_INVALID_ARGS;
58876     }
58877
58878     if (pMP3 == NULL) {
58879         return MA_INVALID_ARGS;
58880     }
58881
58882     #if !defined(MA_NO_MP3)
58883     {
58884         /* We always use floating point format. */
58885         ma_result result = MA_SUCCESS;  /* Must be initialized to MA_SUCCESS. */
58886         ma_uint64 totalFramesRead = 0;
58887         ma_format format;
58888
58889         ma_mp3_get_data_format(pMP3, &format, NULL, NULL, NULL, 0);
58890
58891         switch (format)
58892         {
58893             case ma_format_f32:
58894             {
58895                 totalFramesRead = drmp3_read_pcm_frames_f32(&pMP3->dr, frameCount, (float*)pFramesOut);
58896             } break;
58897
58898             case ma_format_s16:
58899             {
58900                 totalFramesRead = drmp3_read_pcm_frames_s16(&pMP3->dr, frameCount, (drmp3_int16*)pFramesOut);
58901             } break;
58902
58903             case ma_format_u8:
58904             case ma_format_s24:
58905             case ma_format_s32:
58906             case ma_format_unknown:
58907             default:
58908             {
58909                 return MA_INVALID_OPERATION;
58910             };
58911         }
58912
58913         /* In the future we'll update dr_mp3 to return MA_AT_END for us. */
58914         if (totalFramesRead == 0) {
58915             result = MA_AT_END;
58916         }
58917
58918         if (pFramesRead != NULL) {
58919             *pFramesRead = totalFramesRead;
58920         }
58921
58922         return result;
58923     }
58924     #else
58925     {
58926         /* mp3 is disabled. Should never hit this since initialization would have failed. */
58927         MA_ASSERT(MA_FALSE);
58928
58929         (void)pFramesOut;
58930         (void)frameCount;
58931         (void)pFramesRead;
58932
58933         return MA_NOT_IMPLEMENTED;
58934     }
58935     #endif
58936 }
58937
58938 MA_API ma_result ma_mp3_seek_to_pcm_frame(ma_mp3* pMP3, ma_uint64 frameIndex)
58939 {
58940     if (pMP3 == NULL) {
58941         return MA_INVALID_ARGS;
58942     }
58943
58944     #if !defined(MA_NO_MP3)
58945     {
58946         drmp3_bool32 mp3Result;
58947
58948         mp3Result = drmp3_seek_to_pcm_frame(&pMP3->dr, frameIndex);
58949         if (mp3Result != DRMP3_TRUE) {
58950             return MA_ERROR;
58951         }
58952
58953         return MA_SUCCESS;
58954     }
58955     #else
58956     {
58957         /* mp3 is disabled. Should never hit this since initialization would have failed. */
58958         MA_ASSERT(MA_FALSE);
58959
58960         (void)frameIndex;
58961
58962         return MA_NOT_IMPLEMENTED;
58963     }
58964     #endif
58965 }
58966
58967 MA_API ma_result ma_mp3_get_data_format(ma_mp3* pMP3, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
58968 {
58969     /* Defaults for safety. */
58970     if (pFormat != NULL) {
58971         *pFormat = ma_format_unknown;
58972     }
58973     if (pChannels != NULL) {
58974         *pChannels = 0;
58975     }
58976     if (pSampleRate != NULL) {
58977         *pSampleRate = 0;
58978     }
58979     if (pChannelMap != NULL) {
58980         MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
58981     }
58982
58983     if (pMP3 == NULL) {
58984         return MA_INVALID_OPERATION;
58985     }
58986
58987     if (pFormat != NULL) {
58988         *pFormat = pMP3->format;
58989     }
58990
58991     #if !defined(MA_NO_MP3)
58992     {
58993         if (pChannels != NULL) {
58994             *pChannels = pMP3->dr.channels;
58995         }
58996
58997         if (pSampleRate != NULL) {
58998             *pSampleRate = pMP3->dr.sampleRate;
58999         }
59000
59001         if (pChannelMap != NULL) {
59002             ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pMP3->dr.channels);
59003         }
59004
59005         return MA_SUCCESS;
59006     }
59007     #else
59008     {
59009         /* mp3 is disabled. Should never hit this since initialization would have failed. */
59010         MA_ASSERT(MA_FALSE);
59011         return MA_NOT_IMPLEMENTED;
59012     }
59013     #endif
59014 }
59015
59016 MA_API ma_result ma_mp3_get_cursor_in_pcm_frames(ma_mp3* pMP3, ma_uint64* pCursor)
59017 {
59018     if (pCursor == NULL) {
59019         return MA_INVALID_ARGS;
59020     }
59021
59022     *pCursor = 0;   /* Safety. */
59023
59024     if (pMP3 == NULL) {
59025         return MA_INVALID_ARGS;
59026     }
59027
59028     #if !defined(MA_NO_MP3)
59029     {
59030         *pCursor = pMP3->dr.currentPCMFrame;
59031
59032         return MA_SUCCESS;
59033     }
59034     #else
59035     {
59036         /* mp3 is disabled. Should never hit this since initialization would have failed. */
59037         MA_ASSERT(MA_FALSE);
59038         return MA_NOT_IMPLEMENTED;
59039     }
59040     #endif
59041 }
59042
59043 MA_API ma_result ma_mp3_get_length_in_pcm_frames(ma_mp3* pMP3, ma_uint64* pLength)
59044 {
59045     if (pLength == NULL) {
59046         return MA_INVALID_ARGS;
59047     }
59048
59049     *pLength = 0;   /* Safety. */
59050
59051     if (pMP3 == NULL) {
59052         return MA_INVALID_ARGS;
59053     }
59054
59055     #if !defined(MA_NO_MP3)
59056     {
59057         *pLength = drmp3_get_pcm_frame_count(&pMP3->dr);
59058
59059         return MA_SUCCESS;
59060     }
59061     #else
59062     {
59063         /* mp3 is disabled. Should never hit this since initialization would have failed. */
59064         MA_ASSERT(MA_FALSE);
59065         return MA_NOT_IMPLEMENTED;
59066     }
59067     #endif
59068 }
59069
59070
59071 static ma_result ma_decoding_backend_init__mp3(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
59072 {
59073     ma_result result;
59074     ma_mp3* pMP3;
59075
59076     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
59077
59078     /* For now we're just allocating the decoder backend on the heap. */
59079     pMP3 = (ma_mp3*)ma_malloc(sizeof(*pMP3), pAllocationCallbacks);
59080     if (pMP3 == NULL) {
59081         return MA_OUT_OF_MEMORY;
59082     }
59083
59084     result = ma_mp3_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pMP3);
59085     if (result != MA_SUCCESS) {
59086         ma_free(pMP3, pAllocationCallbacks);
59087         return result;
59088     }
59089
59090     *ppBackend = pMP3;
59091
59092     return MA_SUCCESS;
59093 }
59094
59095 static ma_result ma_decoding_backend_init_file__mp3(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
59096 {
59097     ma_result result;
59098     ma_mp3* pMP3;
59099
59100     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
59101
59102     /* For now we're just allocating the decoder backend on the heap. */
59103     pMP3 = (ma_mp3*)ma_malloc(sizeof(*pMP3), pAllocationCallbacks);
59104     if (pMP3 == NULL) {
59105         return MA_OUT_OF_MEMORY;
59106     }
59107
59108     result = ma_mp3_init_file(pFilePath, pConfig, pAllocationCallbacks, pMP3);
59109     if (result != MA_SUCCESS) {
59110         ma_free(pMP3, pAllocationCallbacks);
59111         return result;
59112     }
59113
59114     *ppBackend = pMP3;
59115
59116     return MA_SUCCESS;
59117 }
59118
59119 static ma_result ma_decoding_backend_init_file_w__mp3(void* pUserData, const wchar_t* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
59120 {
59121     ma_result result;
59122     ma_mp3* pMP3;
59123
59124     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
59125
59126     /* For now we're just allocating the decoder backend on the heap. */
59127     pMP3 = (ma_mp3*)ma_malloc(sizeof(*pMP3), pAllocationCallbacks);
59128     if (pMP3 == NULL) {
59129         return MA_OUT_OF_MEMORY;
59130     }
59131
59132     result = ma_mp3_init_file_w(pFilePath, pConfig, pAllocationCallbacks, pMP3);
59133     if (result != MA_SUCCESS) {
59134         ma_free(pMP3, pAllocationCallbacks);
59135         return result;
59136     }
59137
59138     *ppBackend = pMP3;
59139
59140     return MA_SUCCESS;
59141 }
59142
59143 static ma_result ma_decoding_backend_init_memory__mp3(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
59144 {
59145     ma_result result;
59146     ma_mp3* pMP3;
59147
59148     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
59149
59150     /* For now we're just allocating the decoder backend on the heap. */
59151     pMP3 = (ma_mp3*)ma_malloc(sizeof(*pMP3), pAllocationCallbacks);
59152     if (pMP3 == NULL) {
59153         return MA_OUT_OF_MEMORY;
59154     }
59155
59156     result = ma_mp3_init_memory(pData, dataSize, pConfig, pAllocationCallbacks, pMP3);
59157     if (result != MA_SUCCESS) {
59158         ma_free(pMP3, pAllocationCallbacks);
59159         return result;
59160     }
59161
59162     *ppBackend = pMP3;
59163
59164     return MA_SUCCESS;
59165 }
59166
59167 static void ma_decoding_backend_uninit__mp3(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks)
59168 {
59169     ma_mp3* pMP3 = (ma_mp3*)pBackend;
59170
59171     (void)pUserData;
59172
59173     ma_mp3_uninit(pMP3, pAllocationCallbacks);
59174     ma_free(pMP3, pAllocationCallbacks);
59175 }
59176
59177 static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_mp3 =
59178 {
59179     ma_decoding_backend_init__mp3,
59180     ma_decoding_backend_init_file__mp3,
59181     ma_decoding_backend_init_file_w__mp3,
59182     ma_decoding_backend_init_memory__mp3,
59183     ma_decoding_backend_uninit__mp3
59184 };
59185
59186 static ma_result ma_decoder_init_mp3__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
59187 {
59188     return ma_decoder_init_from_vtable(&g_ma_decoding_backend_vtable_mp3, NULL, pConfig, pDecoder);
59189 }
59190 #endif  /* dr_mp3_h */
59191
59192 /* Vorbis */
59193 #ifdef STB_VORBIS_INCLUDE_STB_VORBIS_H
59194 #define MA_HAS_VORBIS
59195
59196 /* The size in bytes of each chunk of data to read from the Vorbis stream. */
59197 #define MA_VORBIS_DATA_CHUNK_SIZE  4096
59198
59199 typedef struct
59200 {
59201     ma_data_source_base ds;
59202     ma_read_proc onRead;
59203     ma_seek_proc onSeek;
59204     ma_tell_proc onTell;
59205     void* pReadSeekTellUserData;
59206     ma_allocation_callbacks allocationCallbacks;    /* Store the allocation callbacks within the structure because we may need to dynamically expand a buffer in ma_stbvorbis_read_pcm_frames() when using push mode. */
59207     ma_format format;               /* Only f32 is allowed with stb_vorbis. */
59208     ma_uint32 channels;
59209     ma_uint32 sampleRate;
59210     ma_uint64 cursor;
59211 #if !defined(MA_NO_VORBIS)
59212     stb_vorbis* stb;
59213     ma_bool32 usingPushMode;
59214     struct
59215     {
59216         ma_uint8* pData;
59217         size_t dataSize;
59218         size_t dataCapacity;
59219         ma_uint32 framesConsumed;   /* The number of frames consumed in ppPacketData. */
59220         ma_uint32 framesRemaining;  /* The number of frames remaining in ppPacketData. */
59221         float** ppPacketData;
59222     } push;
59223 #endif
59224 } ma_stbvorbis;
59225
59226 MA_API ma_result ma_stbvorbis_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis);
59227 MA_API ma_result ma_stbvorbis_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis);
59228 MA_API ma_result ma_stbvorbis_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis);
59229 MA_API void ma_stbvorbis_uninit(ma_stbvorbis* pVorbis, const ma_allocation_callbacks* pAllocationCallbacks);
59230 MA_API ma_result ma_stbvorbis_read_pcm_frames(ma_stbvorbis* pVorbis, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
59231 MA_API ma_result ma_stbvorbis_seek_to_pcm_frame(ma_stbvorbis* pVorbis, ma_uint64 frameIndex);
59232 MA_API ma_result ma_stbvorbis_get_data_format(ma_stbvorbis* pVorbis, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
59233 MA_API ma_result ma_stbvorbis_get_cursor_in_pcm_frames(ma_stbvorbis* pVorbis, ma_uint64* pCursor);
59234 MA_API ma_result ma_stbvorbis_get_length_in_pcm_frames(ma_stbvorbis* pVorbis, ma_uint64* pLength);
59235
59236
59237 static ma_result ma_stbvorbis_ds_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
59238 {
59239     return ma_stbvorbis_read_pcm_frames((ma_stbvorbis*)pDataSource, pFramesOut, frameCount, pFramesRead);
59240 }
59241
59242 static ma_result ma_stbvorbis_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
59243 {
59244     return ma_stbvorbis_seek_to_pcm_frame((ma_stbvorbis*)pDataSource, frameIndex);
59245 }
59246
59247 static ma_result ma_stbvorbis_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
59248 {
59249     return ma_stbvorbis_get_data_format((ma_stbvorbis*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
59250 }
59251
59252 static ma_result ma_stbvorbis_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
59253 {
59254     return ma_stbvorbis_get_cursor_in_pcm_frames((ma_stbvorbis*)pDataSource, pCursor);
59255 }
59256
59257 static ma_result ma_stbvorbis_ds_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
59258 {
59259     return ma_stbvorbis_get_length_in_pcm_frames((ma_stbvorbis*)pDataSource, pLength);
59260 }
59261
59262 static ma_data_source_vtable g_ma_stbvorbis_ds_vtable =
59263 {
59264     ma_stbvorbis_ds_read,
59265     ma_stbvorbis_ds_seek,
59266     ma_stbvorbis_ds_get_data_format,
59267     ma_stbvorbis_ds_get_cursor,
59268     ma_stbvorbis_ds_get_length,
59269     NULL,   /* onSetLooping */
59270     0
59271 };
59272
59273
59274 static ma_result ma_stbvorbis_init_internal(const ma_decoding_backend_config* pConfig, ma_stbvorbis* pVorbis)
59275 {
59276     ma_result result;
59277     ma_data_source_config dataSourceConfig;
59278
59279     (void)pConfig;
59280
59281     if (pVorbis == NULL) {
59282         return MA_INVALID_ARGS;
59283     }
59284
59285     MA_ZERO_OBJECT(pVorbis);
59286     pVorbis->format = ma_format_f32;    /* Only supporting f32. */
59287
59288     dataSourceConfig = ma_data_source_config_init();
59289     dataSourceConfig.vtable = &g_ma_stbvorbis_ds_vtable;
59290
59291     result = ma_data_source_init(&dataSourceConfig, &pVorbis->ds);
59292     if (result != MA_SUCCESS) {
59293         return result;  /* Failed to initialize the base data source. */
59294     }
59295
59296     return MA_SUCCESS;
59297 }
59298
59299 #if !defined(MA_NO_VORBIS)
59300 static ma_result ma_stbvorbis_post_init(ma_stbvorbis* pVorbis)
59301 {
59302     stb_vorbis_info info;
59303
59304     MA_ASSERT(pVorbis != NULL);
59305
59306     info = stb_vorbis_get_info(pVorbis->stb);
59307
59308     pVorbis->channels   = info.channels;
59309     pVorbis->sampleRate = info.sample_rate;
59310
59311     return MA_SUCCESS;
59312 }
59313 #endif
59314
59315 MA_API ma_result ma_stbvorbis_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis)
59316 {
59317     ma_result result;
59318
59319     result = ma_stbvorbis_init_internal(pConfig, pVorbis);
59320     if (result != MA_SUCCESS) {
59321         return result;
59322     }
59323
59324     if (onRead == NULL || onSeek == NULL) {
59325         return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */
59326     }
59327
59328     pVorbis->onRead = onRead;
59329     pVorbis->onSeek = onSeek;
59330     pVorbis->onTell = onTell;
59331     pVorbis->pReadSeekTellUserData = pReadSeekTellUserData;
59332     ma_allocation_callbacks_init_copy(&pVorbis->allocationCallbacks, pAllocationCallbacks);
59333
59334     #if !defined(MA_NO_VORBIS)
59335     {
59336         /*
59337         stb_vorbis lacks a callback based API for it's pulling API which means we're stuck with the
59338         pushing API. In order for us to be able to successfully initialize the decoder we need to
59339         supply it with enough data. We need to keep loading data until we have enough.
59340         */
59341         stb_vorbis* stb;
59342         size_t dataSize = 0;
59343         size_t dataCapacity = 0;
59344         ma_uint8* pData = NULL; /* <-- Must be initialized to NULL. */
59345
59346         for (;;) {
59347             int vorbisError;
59348             int consumedDataSize;   /* <-- Fill by stb_vorbis_open_pushdata(). */
59349             size_t bytesRead;
59350             ma_uint8* pNewData;
59351
59352             /* Allocate memory for the new chunk. */
59353             dataCapacity += MA_VORBIS_DATA_CHUNK_SIZE;
59354             pNewData = (ma_uint8*)ma_realloc(pData, dataCapacity, pAllocationCallbacks);
59355             if (pNewData == NULL) {
59356                 ma_free(pData, pAllocationCallbacks);
59357                 return MA_OUT_OF_MEMORY;
59358             }
59359
59360             pData = pNewData;
59361
59362             /* Read in the next chunk. */
59363             result = pVorbis->onRead(pVorbis->pReadSeekTellUserData, ma_offset_ptr(pData, dataSize), (dataCapacity - dataSize), &bytesRead);
59364             dataSize += bytesRead;
59365
59366             if (result != MA_SUCCESS) {
59367                 ma_free(pData, pAllocationCallbacks);
59368                 return result;
59369             }
59370
59371             /* We have a maximum of 31 bits with stb_vorbis. */
59372             if (dataSize > INT_MAX) {
59373                 ma_free(pData, pAllocationCallbacks);
59374                 return MA_TOO_BIG;
59375             }
59376
59377             stb = stb_vorbis_open_pushdata(pData, (int)dataSize, &consumedDataSize, &vorbisError, NULL);
59378             if (stb != NULL) {
59379                 /*
59380                 Successfully opened the Vorbis decoder. We might have some leftover unprocessed
59381                 data so we'll need to move that down to the front.
59382                 */
59383                 dataSize -= (size_t)consumedDataSize;   /* Consume the data. */
59384                 MA_MOVE_MEMORY(pData, ma_offset_ptr(pData, consumedDataSize), dataSize);
59385                 break;
59386             } else {
59387                 /* Failed to open the decoder. */
59388                 if (vorbisError == VORBIS_need_more_data) {
59389                     continue;
59390                 } else {
59391                     ma_free(pData, pAllocationCallbacks);
59392                     return MA_ERROR;   /* Failed to open the stb_vorbis decoder. */
59393                 }
59394             }
59395         }
59396
59397         MA_ASSERT(stb != NULL);
59398         pVorbis->stb = stb;
59399         pVorbis->push.pData = pData;
59400         pVorbis->push.dataSize = dataSize;
59401         pVorbis->push.dataCapacity = dataCapacity;
59402
59403         pVorbis->usingPushMode = MA_TRUE;
59404
59405         result = ma_stbvorbis_post_init(pVorbis);
59406         if (result != MA_SUCCESS) {
59407             stb_vorbis_close(pVorbis->stb);
59408             ma_free(pData, pAllocationCallbacks);
59409             return result;
59410         }
59411
59412         return MA_SUCCESS;
59413     }
59414     #else
59415     {
59416         /* vorbis is disabled. */
59417         (void)pAllocationCallbacks;
59418         return MA_NOT_IMPLEMENTED;
59419     }
59420     #endif
59421 }
59422
59423 MA_API ma_result ma_stbvorbis_init_file(const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis)
59424 {
59425     ma_result result;
59426
59427     result = ma_stbvorbis_init_internal(pConfig, pVorbis);
59428     if (result != MA_SUCCESS) {
59429         return result;
59430     }
59431
59432     #if !defined(MA_NO_VORBIS)
59433     {
59434         (void)pAllocationCallbacks; /* Don't know how to make use of this with stb_vorbis. */
59435
59436         /* We can use stb_vorbis' pull mode for file based streams. */
59437         pVorbis->stb = stb_vorbis_open_filename(pFilePath, NULL, NULL);
59438         if (pVorbis->stb == NULL) {
59439             return MA_INVALID_FILE;
59440         }
59441
59442         pVorbis->usingPushMode = MA_FALSE;
59443
59444         result = ma_stbvorbis_post_init(pVorbis);
59445         if (result != MA_SUCCESS) {
59446             stb_vorbis_close(pVorbis->stb);
59447             return result;
59448         }
59449
59450         return MA_SUCCESS;
59451     }
59452     #else
59453     {
59454         /* vorbis is disabled. */
59455         (void)pFilePath;
59456         (void)pAllocationCallbacks;
59457         return MA_NOT_IMPLEMENTED;
59458     }
59459     #endif
59460 }
59461
59462 MA_API ma_result ma_stbvorbis_init_memory(const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_stbvorbis* pVorbis)
59463 {
59464     ma_result result;
59465
59466     result = ma_stbvorbis_init_internal(pConfig, pVorbis);
59467     if (result != MA_SUCCESS) {
59468         return result;
59469     }
59470
59471     #if !defined(MA_NO_VORBIS)
59472     {
59473         (void)pAllocationCallbacks;
59474
59475         /* stb_vorbis uses an int as it's size specifier, restricting it to 32-bit even on 64-bit systems. *sigh*. */
59476         if (dataSize > INT_MAX) {
59477             return MA_TOO_BIG;
59478         }
59479
59480         pVorbis->stb = stb_vorbis_open_memory((const unsigned char*)pData, (int)dataSize, NULL, NULL);
59481         if (pVorbis->stb == NULL) {
59482             return MA_INVALID_FILE;
59483         }
59484
59485         pVorbis->usingPushMode = MA_FALSE;
59486
59487         result = ma_stbvorbis_post_init(pVorbis);
59488         if (result != MA_SUCCESS) {
59489             stb_vorbis_close(pVorbis->stb);
59490             return result;
59491         }
59492
59493         return MA_SUCCESS;
59494     }
59495     #else
59496     {
59497         /* vorbis is disabled. */
59498         (void)pData;
59499         (void)dataSize;
59500         (void)pAllocationCallbacks;
59501         return MA_NOT_IMPLEMENTED;
59502     }
59503     #endif
59504 }
59505
59506 MA_API void ma_stbvorbis_uninit(ma_stbvorbis* pVorbis, const ma_allocation_callbacks* pAllocationCallbacks)
59507 {
59508     if (pVorbis == NULL) {
59509         return;
59510     }
59511
59512     #if !defined(MA_NO_VORBIS)
59513     {
59514         stb_vorbis_close(pVorbis->stb);
59515
59516         /* We'll have to clear some memory if we're using push mode. */
59517         if (pVorbis->usingPushMode) {
59518             ma_free(pVorbis->push.pData, pAllocationCallbacks);
59519         }
59520     }
59521     #else
59522     {
59523         /* vorbis is disabled. Should never hit this since initialization would have failed. */
59524         MA_ASSERT(MA_FALSE);
59525     }
59526     #endif
59527
59528     ma_data_source_uninit(&pVorbis->ds);
59529 }
59530
59531 MA_API ma_result ma_stbvorbis_read_pcm_frames(ma_stbvorbis* pVorbis, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
59532 {
59533     if (pFramesRead != NULL) {
59534         *pFramesRead = 0;
59535     }
59536
59537     if (frameCount == 0) {
59538         return MA_INVALID_ARGS;
59539     }
59540
59541     if (pVorbis == NULL) {
59542         return MA_INVALID_ARGS;
59543     }
59544
59545     #if !defined(MA_NO_VORBIS)
59546     {
59547         /* We always use floating point format. */
59548         ma_result result = MA_SUCCESS;  /* Must be initialized to MA_SUCCESS. */
59549         ma_uint64 totalFramesRead = 0;
59550         ma_format format;
59551         ma_uint32 channels;
59552
59553         ma_stbvorbis_get_data_format(pVorbis, &format, &channels, NULL, NULL, 0);
59554
59555         if (format == ma_format_f32) {
59556             /* We read differently depending on whether or not we're using push mode. */
59557             if (pVorbis->usingPushMode) {
59558                 /* Push mode. This is the complex case. */
59559                 float* pFramesOutF32 = (float*)pFramesOut;
59560
59561                 while (totalFramesRead < frameCount) {
59562                     /* The first thing to do is read from any already-cached frames. */
59563                     ma_uint32 framesToReadFromCache = (ma_uint32)ma_min(pVorbis->push.framesRemaining, (frameCount - totalFramesRead));  /* Safe cast because pVorbis->framesRemaining is 32-bit. */
59564
59565                     /* The output pointer can be null in which case we just treate it as a seek. */
59566                     if (pFramesOut != NULL) {
59567                         ma_uint64 iFrame;
59568                         for (iFrame = 0; iFrame < framesToReadFromCache; iFrame += 1) {
59569                             ma_uint32 iChannel;
59570                             for (iChannel = 0; iChannel < pVorbis->channels; iChannel += 1) {
59571                                 pFramesOutF32[iChannel] = pVorbis->push.ppPacketData[iChannel][pVorbis->push.framesConsumed + iFrame];
59572                             }
59573
59574                             pFramesOutF32 += pVorbis->channels;
59575                         }
59576                     }
59577
59578                     /* Update pointers and counters. */
59579                     pVorbis->push.framesConsumed  += framesToReadFromCache;
59580                     pVorbis->push.framesRemaining -= framesToReadFromCache;
59581                     totalFramesRead               += framesToReadFromCache;
59582
59583                     /* Don't bother reading any more frames right now if we've just finished loading. */
59584                     if (totalFramesRead == frameCount) {
59585                         break;
59586                     }
59587
59588                     MA_ASSERT(pVorbis->push.framesRemaining == 0);
59589
59590                     /* Getting here means we've run out of cached frames. We'll need to load some more. */
59591                     for (;;) {
59592                         int samplesRead = 0;
59593                         int consumedDataSize;
59594
59595                         /* We need to case dataSize to an int, so make sure we can do it safely. */
59596                         if (pVorbis->push.dataSize > INT_MAX) {
59597                             break;  /* Too big. */
59598                         }
59599
59600                         consumedDataSize = stb_vorbis_decode_frame_pushdata(pVorbis->stb, pVorbis->push.pData, (int)pVorbis->push.dataSize, NULL, &pVorbis->push.ppPacketData, &samplesRead);
59601                         if (consumedDataSize != 0) {
59602                             /* Successfully decoded a Vorbis frame. Consume the data. */
59603                             pVorbis->push.dataSize -= (size_t)consumedDataSize;
59604                             MA_MOVE_MEMORY(pVorbis->push.pData, ma_offset_ptr(pVorbis->push.pData, consumedDataSize), pVorbis->push.dataSize);
59605
59606                             pVorbis->push.framesConsumed  = 0;
59607                             pVorbis->push.framesRemaining = samplesRead;
59608
59609                             break;
59610                         } else {
59611                             /* Not enough data. Read more. */
59612                             size_t bytesRead;
59613
59614                             /* Expand the data buffer if necessary. */
59615                             if (pVorbis->push.dataCapacity == pVorbis->push.dataSize) {
59616                                 size_t newCap = pVorbis->push.dataCapacity + MA_VORBIS_DATA_CHUNK_SIZE;
59617                                 ma_uint8* pNewData;
59618
59619                                 pNewData = (ma_uint8*)ma_realloc(pVorbis->push.pData, newCap, &pVorbis->allocationCallbacks);
59620                                 if (pNewData == NULL) {
59621                                     result = MA_OUT_OF_MEMORY;
59622                                     break;
59623                                 }
59624
59625                                 pVorbis->push.pData = pNewData;
59626                                 pVorbis->push.dataCapacity = newCap;
59627                             }
59628
59629                             /* We should have enough room to load some data. */
59630                             result = pVorbis->onRead(pVorbis->pReadSeekTellUserData, ma_offset_ptr(pVorbis->push.pData, pVorbis->push.dataSize), (pVorbis->push.dataCapacity - pVorbis->push.dataSize), &bytesRead);
59631                             pVorbis->push.dataSize += bytesRead;
59632
59633                             if (result != MA_SUCCESS) {
59634                                 break;  /* Failed to read any data. Get out. */
59635                             }
59636                         }
59637                     }
59638
59639                     /* If we don't have a success code at this point it means we've encounted an error or the end of the file has been reached (probably the latter). */
59640                     if (result != MA_SUCCESS) {
59641                         break;
59642                     }
59643                 }
59644             } else {
59645                 /* Pull mode. This is the simple case, but we still need to run in a loop because stb_vorbis loves using 32-bit instead of 64-bit. */
59646                 while (totalFramesRead < frameCount) {
59647                     ma_uint64 framesRemaining = (frameCount - totalFramesRead);
59648                     int framesRead;
59649
59650                     if (framesRemaining > INT_MAX) {
59651                         framesRemaining = INT_MAX;
59652                     }
59653
59654                     framesRead = stb_vorbis_get_samples_float_interleaved(pVorbis->stb, channels, (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels), (int)framesRemaining * channels);   /* Safe cast. */
59655                     totalFramesRead += framesRead;
59656
59657                     if (framesRead < (int)framesRemaining) {
59658                         break;  /* Nothing left to read. Get out. */
59659                     }
59660                 }
59661             }
59662         } else {
59663             result = MA_INVALID_ARGS;
59664         }
59665
59666         pVorbis->cursor += totalFramesRead;
59667
59668         if (totalFramesRead == 0) {
59669             result = MA_AT_END;
59670         }
59671
59672         if (pFramesRead != NULL) {
59673             *pFramesRead = totalFramesRead;
59674         }
59675
59676         if (result == MA_SUCCESS && totalFramesRead == 0) {
59677             result  = MA_AT_END;
59678         }
59679
59680         return result;
59681     }
59682     #else
59683     {
59684         /* vorbis is disabled. Should never hit this since initialization would have failed. */
59685         MA_ASSERT(MA_FALSE);
59686
59687         (void)pFramesOut;
59688         (void)frameCount;
59689         (void)pFramesRead;
59690
59691         return MA_NOT_IMPLEMENTED;
59692     }
59693     #endif
59694 }
59695
59696 MA_API ma_result ma_stbvorbis_seek_to_pcm_frame(ma_stbvorbis* pVorbis, ma_uint64 frameIndex)
59697 {
59698     if (pVorbis == NULL) {
59699         return MA_INVALID_ARGS;
59700     }
59701
59702     #if !defined(MA_NO_VORBIS)
59703     {
59704         /* Different seeking methods depending on whether or not we're using push mode. */
59705         if (pVorbis->usingPushMode) {
59706             /* Push mode. This is the complex case. */
59707             ma_result result;
59708             float buffer[4096];
59709
59710             /*
59711             This is terribly inefficient because stb_vorbis does not have a good seeking solution with it's push API. Currently this just performs
59712             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
59713             find the one containing the sample we need. Then we know exactly where to seek for stb_vorbis.
59714
59715             TODO: Use seeking logic documented for stb_vorbis_flush_pushdata().
59716             */
59717
59718             /* Seek to the start of the file to begin with. */
59719             result = pVorbis->onSeek(pVorbis->pReadSeekTellUserData, 0, ma_seek_origin_start);
59720             if (result != MA_SUCCESS) {
59721                 return result;
59722             }
59723
59724             stb_vorbis_flush_pushdata(pVorbis->stb);
59725             pVorbis->push.framesRemaining = 0;
59726             pVorbis->push.dataSize        = 0;
59727
59728             /* Move the cursor back to the start. We'll increment this in the loop below. */
59729             pVorbis->cursor = 0;
59730
59731             while (pVorbis->cursor < frameIndex) {
59732                 ma_uint64 framesRead;
59733                 ma_uint64 framesToRead = ma_countof(buffer)/pVorbis->channels;
59734                 if (framesToRead > (frameIndex - pVorbis->cursor)) {
59735                     framesToRead = (frameIndex - pVorbis->cursor);
59736                 }
59737
59738                 result = ma_stbvorbis_read_pcm_frames(pVorbis, buffer, framesToRead, &framesRead);
59739                 pVorbis->cursor += framesRead;
59740
59741                 if (result != MA_SUCCESS) {
59742                     return result;
59743                 }
59744             }
59745         } else {
59746             /* Pull mode. This is the simple case. */
59747             int vorbisResult;
59748
59749             if (frameIndex > UINT_MAX) {
59750                 return MA_INVALID_ARGS; /* Trying to seek beyond the 32-bit maximum of stb_vorbis. */
59751             }
59752
59753             vorbisResult = stb_vorbis_seek(pVorbis->stb, (unsigned int)frameIndex);  /* Safe cast. */
59754             if (vorbisResult == 0) {
59755                 return MA_ERROR;    /* See failed. */
59756             }
59757
59758             pVorbis->cursor = frameIndex;
59759         }
59760
59761         return MA_SUCCESS;
59762     }
59763     #else
59764     {
59765         /* vorbis is disabled. Should never hit this since initialization would have failed. */
59766         MA_ASSERT(MA_FALSE);
59767
59768         (void)frameIndex;
59769
59770         return MA_NOT_IMPLEMENTED;
59771     }
59772     #endif
59773 }
59774
59775 MA_API ma_result ma_stbvorbis_get_data_format(ma_stbvorbis* pVorbis, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
59776 {
59777     /* Defaults for safety. */
59778     if (pFormat != NULL) {
59779         *pFormat = ma_format_unknown;
59780     }
59781     if (pChannels != NULL) {
59782         *pChannels = 0;
59783     }
59784     if (pSampleRate != NULL) {
59785         *pSampleRate = 0;
59786     }
59787     if (pChannelMap != NULL) {
59788         MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
59789     }
59790
59791     if (pVorbis == NULL) {
59792         return MA_INVALID_OPERATION;
59793     }
59794
59795     if (pFormat != NULL) {
59796         *pFormat = pVorbis->format;
59797     }
59798
59799     #if !defined(MA_NO_VORBIS)
59800     {
59801         if (pChannels != NULL) {
59802             *pChannels = pVorbis->channels;
59803         }
59804
59805         if (pSampleRate != NULL) {
59806             *pSampleRate = pVorbis->sampleRate;
59807         }
59808
59809         if (pChannelMap != NULL) {
59810             ma_channel_map_init_standard(ma_standard_channel_map_vorbis, pChannelMap, channelMapCap, pVorbis->channels);
59811         }
59812
59813         return MA_SUCCESS;
59814     }
59815     #else
59816     {
59817         /* vorbis is disabled. Should never hit this since initialization would have failed. */
59818         MA_ASSERT(MA_FALSE);
59819         return MA_NOT_IMPLEMENTED;
59820     }
59821     #endif
59822 }
59823
59824 MA_API ma_result ma_stbvorbis_get_cursor_in_pcm_frames(ma_stbvorbis* pVorbis, ma_uint64* pCursor)
59825 {
59826     if (pCursor == NULL) {
59827         return MA_INVALID_ARGS;
59828     }
59829
59830     *pCursor = 0;   /* Safety. */
59831
59832     if (pVorbis == NULL) {
59833         return MA_INVALID_ARGS;
59834     }
59835
59836     #if !defined(MA_NO_VORBIS)
59837     {
59838         *pCursor = pVorbis->cursor;
59839
59840         return MA_SUCCESS;
59841     }
59842     #else
59843     {
59844         /* vorbis is disabled. Should never hit this since initialization would have failed. */
59845         MA_ASSERT(MA_FALSE);
59846         return MA_NOT_IMPLEMENTED;
59847     }
59848     #endif
59849 }
59850
59851 MA_API ma_result ma_stbvorbis_get_length_in_pcm_frames(ma_stbvorbis* pVorbis, ma_uint64* pLength)
59852 {
59853     if (pLength == NULL) {
59854         return MA_INVALID_ARGS;
59855     }
59856
59857     *pLength = 0;   /* Safety. */
59858
59859     if (pVorbis == NULL) {
59860         return MA_INVALID_ARGS;
59861     }
59862
59863     #if !defined(MA_NO_VORBIS)
59864     {
59865         if (pVorbis->usingPushMode) {
59866             *pLength = 0;   /* I don't know of a good way to determine this reliably with stb_vorbis and push mode. */
59867         } else {
59868             *pLength = stb_vorbis_stream_length_in_samples(pVorbis->stb);
59869         }
59870
59871         return MA_SUCCESS;
59872     }
59873     #else
59874     {
59875         /* vorbis is disabled. Should never hit this since initialization would have failed. */
59876         MA_ASSERT(MA_FALSE);
59877         return MA_NOT_IMPLEMENTED;
59878     }
59879     #endif
59880 }
59881
59882
59883 static ma_result ma_decoding_backend_init__stbvorbis(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
59884 {
59885     ma_result result;
59886     ma_stbvorbis* pVorbis;
59887
59888     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
59889
59890     /* For now we're just allocating the decoder backend on the heap. */
59891     pVorbis = (ma_stbvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks);
59892     if (pVorbis == NULL) {
59893         return MA_OUT_OF_MEMORY;
59894     }
59895
59896     result = ma_stbvorbis_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pVorbis);
59897     if (result != MA_SUCCESS) {
59898         ma_free(pVorbis, pAllocationCallbacks);
59899         return result;
59900     }
59901
59902     *ppBackend = pVorbis;
59903
59904     return MA_SUCCESS;
59905 }
59906
59907 static ma_result ma_decoding_backend_init_file__stbvorbis(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
59908 {
59909     ma_result result;
59910     ma_stbvorbis* pVorbis;
59911
59912     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
59913
59914     /* For now we're just allocating the decoder backend on the heap. */
59915     pVorbis = (ma_stbvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks);
59916     if (pVorbis == NULL) {
59917         return MA_OUT_OF_MEMORY;
59918     }
59919
59920     result = ma_stbvorbis_init_file(pFilePath, pConfig, pAllocationCallbacks, pVorbis);
59921     if (result != MA_SUCCESS) {
59922         ma_free(pVorbis, pAllocationCallbacks);
59923         return result;
59924     }
59925
59926     *ppBackend = pVorbis;
59927
59928     return MA_SUCCESS;
59929 }
59930
59931 static ma_result ma_decoding_backend_init_memory__stbvorbis(void* pUserData, const void* pData, size_t dataSize, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend)
59932 {
59933     ma_result result;
59934     ma_stbvorbis* pVorbis;
59935
59936     (void)pUserData;    /* For now not using pUserData, but once we start storing the vorbis decoder state within the ma_decoder structure this will be set to the decoder so we can avoid a malloc. */
59937
59938     /* For now we're just allocating the decoder backend on the heap. */
59939     pVorbis = (ma_stbvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks);
59940     if (pVorbis == NULL) {
59941         return MA_OUT_OF_MEMORY;
59942     }
59943
59944     result = ma_stbvorbis_init_memory(pData, dataSize, pConfig, pAllocationCallbacks, pVorbis);
59945     if (result != MA_SUCCESS) {
59946         ma_free(pVorbis, pAllocationCallbacks);
59947         return result;
59948     }
59949
59950     *ppBackend = pVorbis;
59951
59952     return MA_SUCCESS;
59953 }
59954
59955 static void ma_decoding_backend_uninit__stbvorbis(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks)
59956 {
59957     ma_stbvorbis* pVorbis = (ma_stbvorbis*)pBackend;
59958
59959     (void)pUserData;
59960
59961     ma_stbvorbis_uninit(pVorbis, pAllocationCallbacks);
59962     ma_free(pVorbis, pAllocationCallbacks);
59963 }
59964
59965 static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_stbvorbis =
59966 {
59967     ma_decoding_backend_init__stbvorbis,
59968     ma_decoding_backend_init_file__stbvorbis,
59969     NULL, /* onInitFileW() */
59970     ma_decoding_backend_init_memory__stbvorbis,
59971     ma_decoding_backend_uninit__stbvorbis
59972 };
59973
59974 static ma_result ma_decoder_init_vorbis__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
59975 {
59976     return ma_decoder_init_from_vtable(&g_ma_decoding_backend_vtable_stbvorbis, NULL, pConfig, pDecoder);
59977 }
59978 #endif  /* STB_VORBIS_INCLUDE_STB_VORBIS_H */
59979
59980
59981
59982 static ma_result ma_decoder__init_allocation_callbacks(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
59983 {
59984     MA_ASSERT(pDecoder != NULL);
59985
59986     if (pConfig != NULL) {
59987         return ma_allocation_callbacks_init_copy(&pDecoder->allocationCallbacks, &pConfig->allocationCallbacks);
59988     } else {
59989         pDecoder->allocationCallbacks = ma_allocation_callbacks_init_default();
59990         return MA_SUCCESS;
59991     }
59992 }
59993
59994 static ma_result ma_decoder__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
59995 {
59996     return ma_decoder_read_pcm_frames((ma_decoder*)pDataSource, pFramesOut, frameCount, pFramesRead);
59997 }
59998
59999 static ma_result ma_decoder__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
60000 {
60001     return ma_decoder_seek_to_pcm_frame((ma_decoder*)pDataSource, frameIndex);
60002 }
60003
60004 static ma_result ma_decoder__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
60005 {
60006     return ma_decoder_get_data_format((ma_decoder*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
60007 }
60008
60009 static ma_result ma_decoder__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
60010 {
60011     return ma_decoder_get_cursor_in_pcm_frames((ma_decoder*)pDataSource, pCursor);
60012 }
60013
60014 static ma_result ma_decoder__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
60015 {
60016     return ma_decoder_get_length_in_pcm_frames((ma_decoder*)pDataSource, pLength);
60017 }
60018
60019 static ma_data_source_vtable g_ma_decoder_data_source_vtable =
60020 {
60021     ma_decoder__data_source_on_read,
60022     ma_decoder__data_source_on_seek,
60023     ma_decoder__data_source_on_get_data_format,
60024     ma_decoder__data_source_on_get_cursor,
60025     ma_decoder__data_source_on_get_length,
60026     NULL,   /* onSetLooping */
60027     0
60028 };
60029
60030 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)
60031 {
60032     ma_result result;
60033     ma_data_source_config dataSourceConfig;
60034
60035     MA_ASSERT(pConfig != NULL);
60036
60037     if (pDecoder == NULL) {
60038         return MA_INVALID_ARGS;
60039     }
60040
60041     MA_ZERO_OBJECT(pDecoder);
60042
60043     if (onRead == NULL || onSeek == NULL) {
60044         return MA_INVALID_ARGS;
60045     }
60046
60047     dataSourceConfig = ma_data_source_config_init();
60048     dataSourceConfig.vtable = &g_ma_decoder_data_source_vtable;
60049
60050     result = ma_data_source_init(&dataSourceConfig, &pDecoder->ds);
60051     if (result != MA_SUCCESS) {
60052         return result;
60053     }
60054
60055     pDecoder->onRead    = onRead;
60056     pDecoder->onSeek    = onSeek;
60057     pDecoder->onTell    = onTell;
60058     pDecoder->pUserData = pUserData;
60059
60060     result = ma_decoder__init_allocation_callbacks(pConfig, pDecoder);
60061     if (result != MA_SUCCESS) {
60062         ma_data_source_uninit(&pDecoder->ds);
60063         return result;
60064     }
60065
60066     return MA_SUCCESS;
60067 }
60068
60069 static ma_result ma_decoder__postinit(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
60070 {
60071     ma_result result;
60072
60073     result = ma_decoder__init_data_converter(pDecoder, pConfig);
60074
60075     /* If we failed post initialization we need to uninitialize the decoder before returning to prevent a memory leak. */
60076     if (result != MA_SUCCESS) {
60077         ma_decoder_uninit(pDecoder);
60078         return result;
60079     }
60080
60081     return result;
60082 }
60083
60084
60085 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)
60086 {
60087     ma_result result = MA_NO_BACKEND;
60088
60089     MA_ASSERT(pConfig != NULL);
60090     MA_ASSERT(pDecoder != NULL);
60091
60092     /* Silence some warnings in the case that we don't have any decoder backends enabled. */
60093     (void)onRead;
60094     (void)onSeek;
60095     (void)pUserData;
60096
60097
60098     /* If we've specified a specific encoding type, try that first. */
60099     if (pConfig->encodingFormat != ma_encoding_format_unknown) {
60100     #ifdef MA_HAS_WAV
60101         if (pConfig->encodingFormat == ma_encoding_format_wav) {
60102             result = ma_decoder_init_wav__internal(pConfig, pDecoder);
60103         }
60104     #endif
60105     #ifdef MA_HAS_FLAC
60106         if (pConfig->encodingFormat == ma_encoding_format_flac) {
60107             result = ma_decoder_init_flac__internal(pConfig, pDecoder);
60108         }
60109     #endif
60110     #ifdef MA_HAS_MP3
60111         if (pConfig->encodingFormat == ma_encoding_format_mp3) {
60112             result = ma_decoder_init_mp3__internal(pConfig, pDecoder);
60113         }
60114     #endif
60115     #ifdef MA_HAS_VORBIS
60116         if (pConfig->encodingFormat == ma_encoding_format_vorbis) {
60117             result = ma_decoder_init_vorbis__internal(pConfig, pDecoder);
60118         }
60119     #endif
60120
60121         /* If we weren't able to initialize the decoder, seek back to the start to give the next attempts a clean start. */
60122         if (result != MA_SUCCESS) {
60123             onSeek(pDecoder, 0, ma_seek_origin_start);
60124         }
60125     }
60126
60127     if (result != MA_SUCCESS) {
60128         /* Getting here means we couldn't load a specific decoding backend based on the encoding format. */
60129
60130         /*
60131         We use trial and error to open a decoder. We prioritize custom decoders so that if they
60132         implement the same encoding format they take priority over the built-in decoders.
60133         */
60134         if (result != MA_SUCCESS) {
60135             result = ma_decoder_init_custom__internal(pConfig, pDecoder);
60136             if (result != MA_SUCCESS) {
60137                 onSeek(pDecoder, 0, ma_seek_origin_start);
60138             }
60139         }
60140
60141         /*
60142         If we get to this point and we still haven't found a decoder, and the caller has requested a
60143         specific encoding format, there's no hope for it. Abort.
60144         */
60145         if (pConfig->encodingFormat != ma_encoding_format_unknown) {
60146             return MA_NO_BACKEND;
60147         }
60148
60149     #ifdef MA_HAS_WAV
60150         if (result != MA_SUCCESS) {
60151             result = ma_decoder_init_wav__internal(pConfig, pDecoder);
60152             if (result != MA_SUCCESS) {
60153                 onSeek(pDecoder, 0, ma_seek_origin_start);
60154             }
60155         }
60156     #endif
60157     #ifdef MA_HAS_FLAC
60158         if (result != MA_SUCCESS) {
60159             result = ma_decoder_init_flac__internal(pConfig, pDecoder);
60160             if (result != MA_SUCCESS) {
60161                 onSeek(pDecoder, 0, ma_seek_origin_start);
60162             }
60163         }
60164     #endif
60165     #ifdef MA_HAS_MP3
60166         if (result != MA_SUCCESS) {
60167             result = ma_decoder_init_mp3__internal(pConfig, pDecoder);
60168             if (result != MA_SUCCESS) {
60169                 onSeek(pDecoder, 0, ma_seek_origin_start);
60170             }
60171         }
60172     #endif
60173     #ifdef MA_HAS_VORBIS
60174         if (result != MA_SUCCESS) {
60175             result = ma_decoder_init_vorbis__internal(pConfig, pDecoder);
60176             if (result != MA_SUCCESS) {
60177                 onSeek(pDecoder, 0, ma_seek_origin_start);
60178             }
60179         }
60180     #endif
60181     }
60182
60183     if (result != MA_SUCCESS) {
60184         return result;
60185     }
60186
60187     return ma_decoder__postinit(pConfig, pDecoder);
60188 }
60189
60190 MA_API 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)
60191 {
60192     ma_decoder_config config;
60193     ma_result result;
60194
60195     config = ma_decoder_config_init_copy(pConfig);
60196
60197     result = ma_decoder__preinit(onRead, onSeek, NULL, pUserData, &config, pDecoder);
60198     if (result != MA_SUCCESS) {
60199         return result;
60200     }
60201
60202     return ma_decoder_init__internal(onRead, onSeek, pUserData, &config, pDecoder);
60203 }
60204
60205
60206 static ma_result ma_decoder__on_read_memory(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead)
60207 {
60208     size_t bytesRemaining;
60209
60210     MA_ASSERT(pDecoder->data.memory.dataSize >= pDecoder->data.memory.currentReadPos);
60211
60212     if (pBytesRead != NULL) {
60213         *pBytesRead = 0;
60214     }
60215
60216     bytesRemaining = pDecoder->data.memory.dataSize - pDecoder->data.memory.currentReadPos;
60217     if (bytesToRead > bytesRemaining) {
60218         bytesToRead = bytesRemaining;
60219     }
60220
60221     if (bytesRemaining == 0) {
60222         return MA_AT_END;
60223     }
60224
60225     if (bytesToRead > 0) {
60226         MA_COPY_MEMORY(pBufferOut, pDecoder->data.memory.pData + pDecoder->data.memory.currentReadPos, bytesToRead);
60227         pDecoder->data.memory.currentReadPos += bytesToRead;
60228     }
60229
60230     if (pBytesRead != NULL) {
60231         *pBytesRead = bytesToRead;
60232     }
60233
60234     return MA_SUCCESS;
60235 }
60236
60237 static ma_result ma_decoder__on_seek_memory(ma_decoder* pDecoder, ma_int64 byteOffset, ma_seek_origin origin)
60238 {
60239     if (byteOffset > 0 && (ma_uint64)byteOffset > MA_SIZE_MAX) {
60240         return MA_BAD_SEEK;
60241     }
60242
60243     if (origin == ma_seek_origin_current) {
60244         if (byteOffset > 0) {
60245             if (pDecoder->data.memory.currentReadPos + byteOffset > pDecoder->data.memory.dataSize) {
60246                 byteOffset = (ma_int64)(pDecoder->data.memory.dataSize - pDecoder->data.memory.currentReadPos);  /* Trying to seek too far forward. */
60247             }
60248
60249             pDecoder->data.memory.currentReadPos += (size_t)byteOffset;
60250         } else {
60251             if (pDecoder->data.memory.currentReadPos < (size_t)-byteOffset) {
60252                 byteOffset = -(ma_int64)pDecoder->data.memory.currentReadPos;  /* Trying to seek too far backwards. */
60253             }
60254
60255             pDecoder->data.memory.currentReadPos -= (size_t)-byteOffset;
60256         }
60257     } else {
60258         if (origin == ma_seek_origin_end) {
60259             if (byteOffset < 0) {
60260                 byteOffset = -byteOffset;
60261             }
60262
60263             if (byteOffset > (ma_int64)pDecoder->data.memory.dataSize) {
60264                 pDecoder->data.memory.currentReadPos = 0;   /* Trying to seek too far back. */
60265             } else {
60266                 pDecoder->data.memory.currentReadPos = pDecoder->data.memory.dataSize - (size_t)byteOffset;
60267             }
60268         } else {
60269             if ((size_t)byteOffset <= pDecoder->data.memory.dataSize) {
60270                 pDecoder->data.memory.currentReadPos = (size_t)byteOffset;
60271             } else {
60272                 pDecoder->data.memory.currentReadPos = pDecoder->data.memory.dataSize;  /* Trying to seek too far forward. */
60273             }
60274         }
60275     }
60276
60277     return MA_SUCCESS;
60278 }
60279
60280 static ma_result ma_decoder__on_tell_memory(ma_decoder* pDecoder, ma_int64* pCursor)
60281 {
60282     MA_ASSERT(pDecoder != NULL);
60283     MA_ASSERT(pCursor  != NULL);
60284
60285     *pCursor = (ma_int64)pDecoder->data.memory.currentReadPos;
60286
60287     return MA_SUCCESS;
60288 }
60289
60290 static ma_result ma_decoder__preinit_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
60291 {
60292     ma_result result = ma_decoder__preinit(ma_decoder__on_read_memory, ma_decoder__on_seek_memory, ma_decoder__on_tell_memory, NULL, pConfig, pDecoder);
60293     if (result != MA_SUCCESS) {
60294         return result;
60295     }
60296
60297     if (pData == NULL || dataSize == 0) {
60298         return MA_INVALID_ARGS;
60299     }
60300
60301     pDecoder->data.memory.pData = (const ma_uint8*)pData;
60302     pDecoder->data.memory.dataSize = dataSize;
60303     pDecoder->data.memory.currentReadPos = 0;
60304
60305     (void)pConfig;
60306     return MA_SUCCESS;
60307 }
60308
60309 MA_API ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
60310 {
60311     ma_decoder_config config;
60312     ma_result result;
60313
60314     config = ma_decoder_config_init_copy(pConfig);  /* Make sure the config is not NULL. */
60315
60316     result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
60317     if (result != MA_SUCCESS) {
60318         return result;
60319     }
60320
60321     return ma_decoder_init__internal(ma_decoder__on_read_memory, ma_decoder__on_seek_memory, NULL, &config, pDecoder);
60322 }
60323
60324
60325 #if defined(MA_HAS_WAV)    || \
60326     defined(MA_HAS_MP3)    || \
60327     defined(MA_HAS_FLAC)   || \
60328     defined(MA_HAS_VORBIS) || \
60329     defined(MA_HAS_OPUS)
60330 #define MA_HAS_PATH_API
60331 #endif
60332
60333 #if defined(MA_HAS_PATH_API)
60334 static const char* ma_path_file_name(const char* path)
60335 {
60336     const char* fileName;
60337
60338     if (path == NULL) {
60339         return NULL;
60340     }
60341
60342     fileName = path;
60343
60344     /* We just loop through the path until we find the last slash. */
60345     while (path[0] != '\0') {
60346         if (path[0] == '/' || path[0] == '\\') {
60347             fileName = path;
60348         }
60349
60350         path += 1;
60351     }
60352
60353     /* At this point the file name is sitting on a slash, so just move forward. */
60354     while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) {
60355         fileName += 1;
60356     }
60357
60358     return fileName;
60359 }
60360
60361 static const wchar_t* ma_path_file_name_w(const wchar_t* path)
60362 {
60363     const wchar_t* fileName;
60364
60365     if (path == NULL) {
60366         return NULL;
60367     }
60368
60369     fileName = path;
60370
60371     /* We just loop through the path until we find the last slash. */
60372     while (path[0] != '\0') {
60373         if (path[0] == '/' || path[0] == '\\') {
60374             fileName = path;
60375         }
60376
60377         path += 1;
60378     }
60379
60380     /* At this point the file name is sitting on a slash, so just move forward. */
60381     while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) {
60382         fileName += 1;
60383     }
60384
60385     return fileName;
60386 }
60387
60388
60389 static const char* ma_path_extension(const char* path)
60390 {
60391     const char* extension;
60392     const char* lastOccurance;
60393
60394     if (path == NULL) {
60395         path = "";
60396     }
60397
60398     extension = ma_path_file_name(path);
60399     lastOccurance = NULL;
60400
60401     /* Just find the last '.' and return. */
60402     while (extension[0] != '\0') {
60403         if (extension[0] == '.') {
60404             extension += 1;
60405             lastOccurance = extension;
60406         }
60407
60408         extension += 1;
60409     }
60410
60411     return (lastOccurance != NULL) ? lastOccurance : extension;
60412 }
60413
60414 static const wchar_t* ma_path_extension_w(const wchar_t* path)
60415 {
60416     const wchar_t* extension;
60417     const wchar_t* lastOccurance;
60418
60419     if (path == NULL) {
60420         path = L"";
60421     }
60422
60423     extension = ma_path_file_name_w(path);
60424     lastOccurance = NULL;
60425
60426     /* Just find the last '.' and return. */
60427     while (extension[0] != '\0') {
60428         if (extension[0] == '.') {
60429             extension += 1;
60430             lastOccurance = extension;
60431         }
60432
60433         extension += 1;
60434     }
60435
60436     return (lastOccurance != NULL) ? lastOccurance : extension;
60437 }
60438
60439
60440 static ma_bool32 ma_path_extension_equal(const char* path, const char* extension)
60441 {
60442     const char* ext1;
60443     const char* ext2;
60444
60445     if (path == NULL || extension == NULL) {
60446         return MA_FALSE;
60447     }
60448
60449     ext1 = extension;
60450     ext2 = ma_path_extension(path);
60451
60452 #if defined(_MSC_VER) || defined(__DMC__)
60453     return _stricmp(ext1, ext2) == 0;
60454 #else
60455     return strcasecmp(ext1, ext2) == 0;
60456 #endif
60457 }
60458
60459 static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* extension)
60460 {
60461     const wchar_t* ext1;
60462     const wchar_t* ext2;
60463
60464     if (path == NULL || extension == NULL) {
60465         return MA_FALSE;
60466     }
60467
60468     ext1 = extension;
60469     ext2 = ma_path_extension_w(path);
60470
60471 #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__)
60472     return _wcsicmp(ext1, ext2) == 0;
60473 #else
60474     /*
60475     I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This
60476     isn't the most efficient way to do it, but it should work OK.
60477     */
60478     {
60479         char ext1MB[4096];
60480         char ext2MB[4096];
60481         const wchar_t* pext1 = ext1;
60482         const wchar_t* pext2 = ext2;
60483         mbstate_t mbs1;
60484         mbstate_t mbs2;
60485
60486         MA_ZERO_OBJECT(&mbs1);
60487         MA_ZERO_OBJECT(&mbs2);
60488
60489         if (wcsrtombs(ext1MB, &pext1, sizeof(ext1MB), &mbs1) == (size_t)-1) {
60490             return MA_FALSE;
60491         }
60492         if (wcsrtombs(ext2MB, &pext2, sizeof(ext2MB), &mbs2) == (size_t)-1) {
60493             return MA_FALSE;
60494         }
60495
60496         return strcasecmp(ext1MB, ext2MB) == 0;
60497     }
60498 #endif
60499 }
60500 #endif  /* MA_HAS_PATH_API */
60501
60502
60503
60504 static ma_result ma_decoder__on_read_vfs(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead, size_t* pBytesRead)
60505 {
60506     MA_ASSERT(pDecoder   != NULL);
60507     MA_ASSERT(pBufferOut != NULL);
60508
60509     return ma_vfs_or_default_read(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file, pBufferOut, bytesToRead, pBytesRead);
60510 }
60511
60512 static ma_result ma_decoder__on_seek_vfs(ma_decoder* pDecoder, ma_int64 offset, ma_seek_origin origin)
60513 {
60514     MA_ASSERT(pDecoder != NULL);
60515
60516     return ma_vfs_or_default_seek(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file, offset, origin);
60517 }
60518
60519 static ma_result ma_decoder__on_tell_vfs(ma_decoder* pDecoder, ma_int64* pCursor)
60520 {
60521     MA_ASSERT(pDecoder != NULL);
60522
60523     return ma_vfs_or_default_tell(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file, pCursor);
60524 }
60525
60526 static ma_result ma_decoder__preinit_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
60527 {
60528     ma_result result;
60529     ma_vfs_file file;
60530
60531     result = ma_decoder__preinit(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, ma_decoder__on_tell_vfs, NULL, pConfig, pDecoder);
60532     if (result != MA_SUCCESS) {
60533         return result;
60534     }
60535
60536     if (pFilePath == NULL || pFilePath[0] == '\0') {
60537         return MA_INVALID_ARGS;
60538     }
60539
60540     result = ma_vfs_or_default_open(pVFS, pFilePath, MA_OPEN_MODE_READ, &file);
60541     if (result != MA_SUCCESS) {
60542         return result;
60543     }
60544
60545     pDecoder->data.vfs.pVFS = pVFS;
60546     pDecoder->data.vfs.file = file;
60547
60548     return MA_SUCCESS;
60549 }
60550
60551 MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
60552 {
60553     ma_result result;
60554     ma_decoder_config config;
60555
60556     config = ma_decoder_config_init_copy(pConfig);
60557     result = ma_decoder__preinit_vfs(pVFS, pFilePath, &config, pDecoder);
60558     if (result != MA_SUCCESS) {
60559         return result;
60560     }
60561
60562     result = MA_NO_BACKEND;
60563
60564     if (config.encodingFormat != ma_encoding_format_unknown) {
60565     #ifdef MA_HAS_WAV
60566         if (config.encodingFormat == ma_encoding_format_wav) {
60567             result = ma_decoder_init_wav__internal(&config, pDecoder);
60568         }
60569     #endif
60570     #ifdef MA_HAS_FLAC
60571         if (config.encodingFormat == ma_encoding_format_flac) {
60572             result = ma_decoder_init_flac__internal(&config, pDecoder);
60573         }
60574     #endif
60575     #ifdef MA_HAS_MP3
60576         if (config.encodingFormat == ma_encoding_format_mp3) {
60577             result = ma_decoder_init_mp3__internal(&config, pDecoder);
60578         }
60579     #endif
60580     #ifdef MA_HAS_VORBIS
60581         if (config.encodingFormat == ma_encoding_format_vorbis) {
60582             result = ma_decoder_init_vorbis__internal(&config, pDecoder);
60583         }
60584     #endif
60585
60586         /* Make sure we seek back to the start if we didn't initialize a decoder successfully so the next attempts have a fresh start. */
60587         if (result != MA_SUCCESS) {
60588             ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
60589         }
60590     }
60591
60592     if (result != MA_SUCCESS) {
60593         /* Getting here means we weren't able to initialize a decoder of a specific encoding format. */
60594
60595         /*
60596         We use trial and error to open a decoder. We prioritize custom decoders so that if they
60597         implement the same encoding format they take priority over the built-in decoders.
60598         */
60599         if (result != MA_SUCCESS) {
60600             result = ma_decoder_init_custom__internal(&config, pDecoder);
60601             if (result != MA_SUCCESS) {
60602                 ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
60603             }
60604         }
60605
60606         /*
60607         If we get to this point and we still haven't found a decoder, and the caller has requested a
60608         specific encoding format, there's no hope for it. Abort.
60609         */
60610         if (config.encodingFormat != ma_encoding_format_unknown) {
60611             return MA_NO_BACKEND;
60612         }
60613
60614     #ifdef MA_HAS_WAV
60615         if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "wav")) {
60616             result = ma_decoder_init_wav__internal(&config, pDecoder);
60617             if (result != MA_SUCCESS) {
60618                 ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
60619             }
60620         }
60621     #endif
60622     #ifdef MA_HAS_FLAC
60623         if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "flac")) {
60624             result = ma_decoder_init_flac__internal(&config, pDecoder);
60625             if (result != MA_SUCCESS) {
60626                 ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
60627             }
60628         }
60629     #endif
60630     #ifdef MA_HAS_MP3
60631         if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "mp3")) {
60632             result = ma_decoder_init_mp3__internal(&config, pDecoder);
60633             if (result != MA_SUCCESS) {
60634                 ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
60635             }
60636         }
60637     #endif
60638     }
60639
60640     /* If we still haven't got a result just use trial and error. Otherwise we can finish up. */
60641     if (result != MA_SUCCESS) {
60642         result = ma_decoder_init__internal(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, NULL, &config, pDecoder);
60643     } else {
60644         result = ma_decoder__postinit(&config, pDecoder);
60645     }
60646
60647     if (result != MA_SUCCESS) {
60648         if (pDecoder->data.vfs.file != NULL) {   /* <-- Will be reset to NULL if ma_decoder_uninit() is called in one of the steps above which allows us to avoid a double close of the file. */
60649             ma_vfs_or_default_close(pVFS, pDecoder->data.vfs.file);
60650         }
60651
60652         return result;
60653     }
60654
60655     return MA_SUCCESS;
60656 }
60657
60658
60659 static ma_result ma_decoder__preinit_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
60660 {
60661     ma_result result;
60662     ma_vfs_file file;
60663
60664     result = ma_decoder__preinit(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, ma_decoder__on_tell_vfs, NULL, pConfig, pDecoder);
60665     if (result != MA_SUCCESS) {
60666         return result;
60667     }
60668
60669     if (pFilePath == NULL || pFilePath[0] == '\0') {
60670         return MA_INVALID_ARGS;
60671     }
60672
60673     result = ma_vfs_or_default_open_w(pVFS, pFilePath, MA_OPEN_MODE_READ, &file);
60674     if (result != MA_SUCCESS) {
60675         return result;
60676     }
60677
60678     pDecoder->data.vfs.pVFS = pVFS;
60679     pDecoder->data.vfs.file = file;
60680
60681     return MA_SUCCESS;
60682 }
60683
60684 MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
60685 {
60686     ma_result result;
60687     ma_decoder_config config;
60688
60689     config = ma_decoder_config_init_copy(pConfig);
60690     result = ma_decoder__preinit_vfs_w(pVFS, pFilePath, &config, pDecoder);
60691     if (result != MA_SUCCESS) {
60692         return result;
60693     }
60694
60695     result = MA_NO_BACKEND;
60696
60697     if (config.encodingFormat != ma_encoding_format_unknown) {
60698     #ifdef MA_HAS_WAV
60699         if (config.encodingFormat == ma_encoding_format_wav) {
60700             result = ma_decoder_init_wav__internal(&config, pDecoder);
60701         }
60702     #endif
60703     #ifdef MA_HAS_FLAC
60704         if (config.encodingFormat == ma_encoding_format_flac) {
60705             result = ma_decoder_init_flac__internal(&config, pDecoder);
60706         }
60707     #endif
60708     #ifdef MA_HAS_MP3
60709         if (config.encodingFormat == ma_encoding_format_mp3) {
60710             result = ma_decoder_init_mp3__internal(&config, pDecoder);
60711         }
60712     #endif
60713     #ifdef MA_HAS_VORBIS
60714         if (config.encodingFormat == ma_encoding_format_vorbis) {
60715             result = ma_decoder_init_vorbis__internal(&config, pDecoder);
60716         }
60717     #endif
60718
60719         /* Make sure we seek back to the start if we didn't initialize a decoder successfully so the next attempts have a fresh start. */
60720         if (result != MA_SUCCESS) {
60721             ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
60722         }
60723     }
60724
60725     if (result != MA_SUCCESS) {
60726         /* Getting here means we weren't able to initialize a decoder of a specific encoding format. */
60727
60728         /*
60729         We use trial and error to open a decoder. We prioritize custom decoders so that if they
60730         implement the same encoding format they take priority over the built-in decoders.
60731         */
60732         if (result != MA_SUCCESS) {
60733             result = ma_decoder_init_custom__internal(&config, pDecoder);
60734             if (result != MA_SUCCESS) {
60735                 ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
60736             }
60737         }
60738
60739         /*
60740         If we get to this point and we still haven't found a decoder, and the caller has requested a
60741         specific encoding format, there's no hope for it. Abort.
60742         */
60743         if (config.encodingFormat != ma_encoding_format_unknown) {
60744             return MA_NO_BACKEND;
60745         }
60746
60747     #ifdef MA_HAS_WAV
60748         if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"wav")) {
60749             result = ma_decoder_init_wav__internal(&config, pDecoder);
60750             if (result != MA_SUCCESS) {
60751                 ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
60752             }
60753         }
60754     #endif
60755     #ifdef MA_HAS_FLAC
60756         if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"flac")) {
60757             result = ma_decoder_init_flac__internal(&config, pDecoder);
60758             if (result != MA_SUCCESS) {
60759                 ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
60760             }
60761         }
60762     #endif
60763     #ifdef MA_HAS_MP3
60764         if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"mp3")) {
60765             result = ma_decoder_init_mp3__internal(&config, pDecoder);
60766             if (result != MA_SUCCESS) {
60767                 ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
60768             }
60769         }
60770     #endif
60771     }
60772
60773     /* If we still haven't got a result just use trial and error. Otherwise we can finish up. */
60774     if (result != MA_SUCCESS) {
60775         result = ma_decoder_init__internal(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, NULL, &config, pDecoder);
60776     } else {
60777         result = ma_decoder__postinit(&config, pDecoder);
60778     }
60779
60780     if (result != MA_SUCCESS) {
60781         ma_vfs_or_default_close(pVFS, pDecoder->data.vfs.file);
60782         return result;
60783     }
60784
60785     return MA_SUCCESS;
60786 }
60787
60788 MA_API ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
60789 {
60790     return ma_decoder_init_vfs(NULL, pFilePath, pConfig, pDecoder);
60791 }
60792
60793 MA_API ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
60794 {
60795     return ma_decoder_init_vfs_w(NULL, pFilePath, pConfig, pDecoder);
60796 }
60797
60798 MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder)
60799 {
60800     if (pDecoder == NULL) {
60801         return MA_INVALID_ARGS;
60802     }
60803
60804     if (pDecoder->pBackend != NULL) {
60805         if (pDecoder->pBackendVTable != NULL && pDecoder->pBackendVTable->onUninit != NULL) {
60806             pDecoder->pBackendVTable->onUninit(pDecoder->pBackendUserData, pDecoder->pBackend, &pDecoder->allocationCallbacks);
60807         }
60808     }
60809
60810     if (pDecoder->onRead == ma_decoder__on_read_vfs) {
60811         ma_vfs_or_default_close(pDecoder->data.vfs.pVFS, pDecoder->data.vfs.file);
60812         pDecoder->data.vfs.file = NULL;
60813     }
60814
60815     ma_data_converter_uninit(&pDecoder->converter, &pDecoder->allocationCallbacks);
60816     ma_data_source_uninit(&pDecoder->ds);
60817
60818     if (pDecoder->pInputCache != NULL) {
60819         ma_free(pDecoder->pInputCache, &pDecoder->allocationCallbacks);
60820     }
60821
60822     return MA_SUCCESS;
60823 }
60824
60825 MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
60826 {
60827     ma_result result = MA_SUCCESS;
60828     ma_uint64 totalFramesReadOut;
60829     void* pRunningFramesOut;
60830
60831     if (pFramesRead != NULL) {
60832         *pFramesRead = 0;   /* Safety. */
60833     }
60834
60835     if (frameCount == 0) {
60836         return MA_INVALID_ARGS;
60837     }
60838
60839     if (pDecoder == NULL) {
60840         return MA_INVALID_ARGS;
60841     }
60842
60843     if (pDecoder->pBackend == NULL) {
60844         return MA_INVALID_OPERATION;
60845     }
60846
60847     /* Fast path. */
60848     if (pDecoder->converter.isPassthrough) {
60849         result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pFramesOut, frameCount, &totalFramesReadOut);
60850     } else {
60851         /*
60852         Getting here means we need to do data conversion. If we're seeking forward and are _not_ doing resampling we can run this in a fast path. If we're doing resampling we
60853         need to run through each sample because we need to ensure it's internal cache is updated.
60854         */
60855         if (pFramesOut == NULL && pDecoder->converter.hasResampler == MA_FALSE) {
60856             result = ma_data_source_read_pcm_frames(pDecoder->pBackend, NULL, frameCount, &totalFramesReadOut);
60857         } else {
60858             /* Slow path. Need to run everything through the data converter. */
60859             ma_format internalFormat;
60860             ma_uint32 internalChannels;
60861
60862             totalFramesReadOut = 0;
60863             pRunningFramesOut  = pFramesOut;
60864
60865             result = ma_data_source_get_data_format(pDecoder->pBackend, &internalFormat, &internalChannels, NULL, NULL, 0);
60866             if (result != MA_SUCCESS) {
60867                 return result;   /* Failed to retrieve the internal format and channel count. */
60868             }
60869
60870             /*
60871             We run a different path depending on whether or not we are using a heap-allocated
60872             intermediary buffer or not. If the data converter does not support the calculation of
60873             the required number of input frames, we'll use the heap-allocated path. Otherwise we'll
60874             use the stack-allocated path.
60875             */
60876             if (pDecoder->pInputCache != NULL) {
60877                 /* We don't have a way of determining the required number of input frames, so need to persistently store input data in a cache. */
60878                 while (totalFramesReadOut < frameCount) {
60879                     ma_uint64 framesToReadThisIterationIn;
60880                     ma_uint64 framesToReadThisIterationOut;
60881
60882                     /* If there's any data available in the cache, that needs to get processed first. */
60883                     if (pDecoder->inputCacheRemaining > 0) {
60884                         framesToReadThisIterationOut = (frameCount - totalFramesReadOut);
60885                         framesToReadThisIterationIn  = framesToReadThisIterationOut;
60886                         if (framesToReadThisIterationIn > pDecoder->inputCacheRemaining) {
60887                             framesToReadThisIterationIn = pDecoder->inputCacheRemaining;
60888                         }
60889
60890                         result = ma_data_converter_process_pcm_frames(&pDecoder->converter, ma_offset_pcm_frames_ptr(pDecoder->pInputCache, pDecoder->inputCacheConsumed, internalFormat, internalChannels), &framesToReadThisIterationIn, pRunningFramesOut, &framesToReadThisIterationOut);
60891                         if (result != MA_SUCCESS) {
60892                             break;
60893                         }
60894
60895                         pDecoder->inputCacheConsumed  += framesToReadThisIterationIn;
60896                         pDecoder->inputCacheRemaining -= framesToReadThisIterationIn;
60897
60898                         totalFramesReadOut += framesToReadThisIterationOut;
60899
60900                         if (pRunningFramesOut != NULL) {
60901                             pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesToReadThisIterationOut * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels));
60902                         }
60903
60904                         if (framesToReadThisIterationIn == 0 && framesToReadThisIterationOut == 0) {
60905                             break;  /* We're done. */
60906                         }
60907                     }
60908
60909                     /* Getting here means there's no data in the cache and we need to fill it up from the data source. */
60910                     if (pDecoder->inputCacheRemaining == 0) {
60911                         pDecoder->inputCacheConsumed = 0;
60912
60913                         result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pDecoder->pInputCache, pDecoder->inputCacheCap, &pDecoder->inputCacheRemaining);
60914                         if (result != MA_SUCCESS) {
60915                             break;
60916                         }
60917                     }
60918                 }
60919             } else {
60920                 /* We have a way of determining the required number of input frames so just use the stack. */
60921                 while (totalFramesReadOut < frameCount) {
60922                     ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In internal format. */
60923                     ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(internalFormat, internalChannels);
60924                     ma_uint64 framesToReadThisIterationIn;
60925                     ma_uint64 framesReadThisIterationIn;
60926                     ma_uint64 framesToReadThisIterationOut;
60927                     ma_uint64 framesReadThisIterationOut;
60928                     ma_uint64 requiredInputFrameCount;
60929
60930                     framesToReadThisIterationOut = (frameCount - totalFramesReadOut);
60931                     framesToReadThisIterationIn = framesToReadThisIterationOut;
60932                     if (framesToReadThisIterationIn > intermediaryBufferCap) {
60933                         framesToReadThisIterationIn = intermediaryBufferCap;
60934                     }
60935
60936                     ma_data_converter_get_required_input_frame_count(&pDecoder->converter, framesToReadThisIterationOut, &requiredInputFrameCount);
60937                     if (framesToReadThisIterationIn > requiredInputFrameCount) {
60938                         framesToReadThisIterationIn = requiredInputFrameCount;
60939                     }
60940
60941                     if (requiredInputFrameCount > 0) {
60942                         result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pIntermediaryBuffer, framesToReadThisIterationIn, &framesReadThisIterationIn);
60943                     } else {
60944                         framesReadThisIterationIn = 0;
60945                     }
60946
60947                     /*
60948                     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
60949                     input frames, we still want to try processing frames because there may some output frames generated from cached input data.
60950                     */
60951                     framesReadThisIterationOut = framesToReadThisIterationOut;
60952                     result = ma_data_converter_process_pcm_frames(&pDecoder->converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut);
60953                     if (result != MA_SUCCESS) {
60954                         break;
60955                     }
60956
60957                     totalFramesReadOut += framesReadThisIterationOut;
60958
60959                     if (pRunningFramesOut != NULL) {
60960                         pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels));
60961                     }
60962
60963                     if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) {
60964                         break;  /* We're done. */
60965                     }
60966                 }
60967             }
60968         }
60969     }
60970
60971     pDecoder->readPointerInPCMFrames += totalFramesReadOut;
60972
60973     if (pFramesRead != NULL) {
60974         *pFramesRead = totalFramesReadOut;
60975     }
60976
60977     if (result == MA_SUCCESS && totalFramesReadOut == 0) {
60978         result =  MA_AT_END;
60979     }
60980
60981     return result;
60982 }
60983
60984 MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex)
60985 {
60986     if (pDecoder == NULL) {
60987         return MA_INVALID_ARGS;
60988     }
60989
60990     if (pDecoder->pBackend != NULL) {
60991         ma_result result;
60992         ma_uint64 internalFrameIndex;
60993         ma_uint32 internalSampleRate;
60994
60995         result = ma_data_source_get_data_format(pDecoder->pBackend, NULL, NULL, &internalSampleRate, NULL, 0);
60996         if (result != MA_SUCCESS) {
60997             return result;  /* Failed to retrieve the internal sample rate. */
60998         }
60999
61000         if (internalSampleRate == pDecoder->outputSampleRate) {
61001             internalFrameIndex = frameIndex;
61002         } else {
61003             internalFrameIndex = ma_calculate_frame_count_after_resampling(internalSampleRate, pDecoder->outputSampleRate, frameIndex);
61004         }
61005
61006         result = ma_data_source_seek_to_pcm_frame(pDecoder->pBackend, internalFrameIndex);
61007         if (result == MA_SUCCESS) {
61008             pDecoder->readPointerInPCMFrames = frameIndex;
61009         }
61010
61011         return result;
61012     }
61013
61014     /* Should never get here, but if we do it means onSeekToPCMFrame was not set by the backend. */
61015     return MA_INVALID_ARGS;
61016 }
61017
61018 MA_API ma_result ma_decoder_get_data_format(ma_decoder* pDecoder, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
61019 {
61020     if (pDecoder == NULL) {
61021         return MA_INVALID_ARGS;
61022     }
61023
61024     if (pFormat != NULL) {
61025         *pFormat = pDecoder->outputFormat;
61026     }
61027
61028     if (pChannels != NULL) {
61029         *pChannels = pDecoder->outputChannels;
61030     }
61031
61032     if (pSampleRate != NULL) {
61033         *pSampleRate = pDecoder->outputSampleRate;
61034     }
61035
61036     if (pChannelMap != NULL) {
61037         ma_data_converter_get_output_channel_map(&pDecoder->converter, pChannelMap, channelMapCap);
61038     }
61039
61040     return MA_SUCCESS;
61041 }
61042
61043 MA_API ma_result ma_decoder_get_cursor_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pCursor)
61044 {
61045     if (pCursor == NULL) {
61046         return MA_INVALID_ARGS;
61047     }
61048
61049     *pCursor = 0;
61050
61051     if (pDecoder == NULL) {
61052         return MA_INVALID_ARGS;
61053     }
61054
61055     *pCursor = pDecoder->readPointerInPCMFrames;
61056
61057     return MA_SUCCESS;
61058 }
61059
61060 MA_API ma_result ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pLength)
61061 {
61062     if (pLength == NULL) {
61063         return MA_INVALID_ARGS;
61064     }
61065
61066     *pLength = 0;
61067
61068     if (pDecoder == NULL) {
61069         return MA_INVALID_ARGS;
61070     }
61071
61072     if (pDecoder->pBackend != NULL) {
61073         ma_result result;
61074         ma_uint64 internalLengthInPCMFrames;
61075         ma_uint32 internalSampleRate;
61076
61077         result = ma_data_source_get_length_in_pcm_frames(pDecoder->pBackend, &internalLengthInPCMFrames);
61078         if (result != MA_SUCCESS) {
61079             return result;  /* Failed to retrieve the internal length. */
61080         }
61081
61082         result = ma_data_source_get_data_format(pDecoder->pBackend, NULL, NULL, &internalSampleRate, NULL, 0);
61083         if (result != MA_SUCCESS) {
61084             return result;   /* Failed to retrieve the internal sample rate. */
61085         }
61086
61087         if (internalSampleRate == pDecoder->outputSampleRate) {
61088             *pLength = internalLengthInPCMFrames;
61089         } else {
61090             *pLength = ma_calculate_frame_count_after_resampling(pDecoder->outputSampleRate, internalSampleRate, internalLengthInPCMFrames);
61091         }
61092
61093         return MA_SUCCESS;
61094     } else {
61095         return MA_NO_BACKEND;
61096     }
61097 }
61098
61099 MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64* pAvailableFrames)
61100 {
61101     ma_result result;
61102     ma_uint64 totalFrameCount;
61103
61104     if (pAvailableFrames == NULL) {
61105         return MA_INVALID_ARGS;
61106     }
61107
61108     *pAvailableFrames = 0;
61109
61110     if (pDecoder == NULL) {
61111         return MA_INVALID_ARGS;
61112     }
61113
61114     result = ma_decoder_get_length_in_pcm_frames(pDecoder, &totalFrameCount);
61115     if (result != MA_SUCCESS) {
61116         return result;
61117     }
61118
61119     if (totalFrameCount <= pDecoder->readPointerInPCMFrames) {
61120         *pAvailableFrames = 0;
61121     } else {
61122         *pAvailableFrames = totalFrameCount - pDecoder->readPointerInPCMFrames;
61123     }
61124
61125     return MA_SUCCESS;
61126 }
61127
61128
61129 static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_decoder_config* pConfigOut, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
61130 {
61131     ma_result result;
61132     ma_uint64 totalFrameCount;
61133     ma_uint64 bpf;
61134     ma_uint64 dataCapInFrames;
61135     void* pPCMFramesOut;
61136
61137     MA_ASSERT(pDecoder != NULL);
61138
61139     totalFrameCount = 0;
61140     bpf = ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels);
61141
61142     /* The frame count is unknown until we try reading. Thus, we just run in a loop. */
61143     dataCapInFrames = 0;
61144     pPCMFramesOut = NULL;
61145     for (;;) {
61146         ma_uint64 frameCountToTryReading;
61147         ma_uint64 framesJustRead;
61148
61149         /* Make room if there's not enough. */
61150         if (totalFrameCount == dataCapInFrames) {
61151             void* pNewPCMFramesOut;
61152             ma_uint64 newDataCapInFrames = dataCapInFrames*2;
61153             if (newDataCapInFrames == 0) {
61154                 newDataCapInFrames = 4096;
61155             }
61156
61157             if ((newDataCapInFrames * bpf) > MA_SIZE_MAX) {
61158                 ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks);
61159                 return MA_TOO_BIG;
61160             }
61161
61162             pNewPCMFramesOut = (void*)ma_realloc(pPCMFramesOut, (size_t)(newDataCapInFrames * bpf), &pDecoder->allocationCallbacks);
61163             if (pNewPCMFramesOut == NULL) {
61164                 ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks);
61165                 return MA_OUT_OF_MEMORY;
61166             }
61167
61168             dataCapInFrames = newDataCapInFrames;
61169             pPCMFramesOut = pNewPCMFramesOut;
61170         }
61171
61172         frameCountToTryReading = dataCapInFrames - totalFrameCount;
61173         MA_ASSERT(frameCountToTryReading > 0);
61174
61175         result = ma_decoder_read_pcm_frames(pDecoder, (ma_uint8*)pPCMFramesOut + (totalFrameCount * bpf), frameCountToTryReading, &framesJustRead);
61176         totalFrameCount += framesJustRead;
61177
61178         if (result != MA_SUCCESS) {
61179             break;
61180         }
61181
61182         if (framesJustRead < frameCountToTryReading) {
61183             break;
61184         }
61185     }
61186
61187
61188     if (pConfigOut != NULL) {
61189         pConfigOut->format     = pDecoder->outputFormat;
61190         pConfigOut->channels   = pDecoder->outputChannels;
61191         pConfigOut->sampleRate = pDecoder->outputSampleRate;
61192     }
61193
61194     if (ppPCMFramesOut != NULL) {
61195         *ppPCMFramesOut = pPCMFramesOut;
61196     } else {
61197         ma_free(pPCMFramesOut, &pDecoder->allocationCallbacks);
61198     }
61199
61200     if (pFrameCountOut != NULL) {
61201         *pFrameCountOut = totalFrameCount;
61202     }
61203
61204     ma_decoder_uninit(pDecoder);
61205     return MA_SUCCESS;
61206 }
61207
61208 MA_API ma_result ma_decode_from_vfs(ma_vfs* pVFS, const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
61209 {
61210     ma_result result;
61211     ma_decoder_config config;
61212     ma_decoder decoder;
61213
61214     if (pFrameCountOut != NULL) {
61215         *pFrameCountOut = 0;
61216     }
61217     if (ppPCMFramesOut != NULL) {
61218         *ppPCMFramesOut = NULL;
61219     }
61220
61221     config = ma_decoder_config_init_copy(pConfig);
61222
61223     result = ma_decoder_init_vfs(pVFS, pFilePath, &config, &decoder);
61224     if (result != MA_SUCCESS) {
61225         return result;
61226     }
61227
61228     result = ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut);
61229
61230     return result;
61231 }
61232
61233 MA_API ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
61234 {
61235     return ma_decode_from_vfs(NULL, pFilePath, pConfig, pFrameCountOut, ppPCMFramesOut);
61236 }
61237
61238 MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
61239 {
61240     ma_decoder_config config;
61241     ma_decoder decoder;
61242     ma_result result;
61243
61244     if (pFrameCountOut != NULL) {
61245         *pFrameCountOut = 0;
61246     }
61247     if (ppPCMFramesOut != NULL) {
61248         *ppPCMFramesOut = NULL;
61249     }
61250
61251     if (pData == NULL || dataSize == 0) {
61252         return MA_INVALID_ARGS;
61253     }
61254
61255     config = ma_decoder_config_init_copy(pConfig);
61256
61257     result = ma_decoder_init_memory(pData, dataSize, &config, &decoder);
61258     if (result != MA_SUCCESS) {
61259         return result;
61260     }
61261
61262     return ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut);
61263 }
61264 #endif  /* MA_NO_DECODING */
61265
61266
61267 #ifndef MA_NO_ENCODING
61268
61269 #if defined(MA_HAS_WAV)
61270 static size_t ma_encoder__internal_on_write_wav(void* pUserData, const void* pData, size_t bytesToWrite)
61271 {
61272     ma_encoder* pEncoder = (ma_encoder*)pUserData;
61273     MA_ASSERT(pEncoder != NULL);
61274
61275     return pEncoder->onWrite(pEncoder, pData, bytesToWrite);
61276 }
61277
61278 static drwav_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, drwav_seek_origin origin)
61279 {
61280     ma_encoder* pEncoder = (ma_encoder*)pUserData;
61281     MA_ASSERT(pEncoder != NULL);
61282
61283     return pEncoder->onSeek(pEncoder, offset, (origin == drwav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current);
61284 }
61285
61286 static ma_result ma_encoder__on_init_wav(ma_encoder* pEncoder)
61287 {
61288     drwav_data_format wavFormat;
61289     drwav_allocation_callbacks allocationCallbacks;
61290     drwav* pWav;
61291
61292     MA_ASSERT(pEncoder != NULL);
61293
61294     pWav = (drwav*)ma_malloc(sizeof(*pWav), &pEncoder->config.allocationCallbacks);
61295     if (pWav == NULL) {
61296         return MA_OUT_OF_MEMORY;
61297     }
61298
61299     wavFormat.container     = drwav_container_riff;
61300     wavFormat.channels      = pEncoder->config.channels;
61301     wavFormat.sampleRate    = pEncoder->config.sampleRate;
61302     wavFormat.bitsPerSample = ma_get_bytes_per_sample(pEncoder->config.format) * 8;
61303     if (pEncoder->config.format == ma_format_f32) {
61304         wavFormat.format    = DR_WAVE_FORMAT_IEEE_FLOAT;
61305     } else {
61306         wavFormat.format    = DR_WAVE_FORMAT_PCM;
61307     }
61308
61309     allocationCallbacks.pUserData = pEncoder->config.allocationCallbacks.pUserData;
61310     allocationCallbacks.onMalloc  = pEncoder->config.allocationCallbacks.onMalloc;
61311     allocationCallbacks.onRealloc = pEncoder->config.allocationCallbacks.onRealloc;
61312     allocationCallbacks.onFree    = pEncoder->config.allocationCallbacks.onFree;
61313
61314     if (!drwav_init_write(pWav, &wavFormat, ma_encoder__internal_on_write_wav, ma_encoder__internal_on_seek_wav, pEncoder, &allocationCallbacks)) {
61315         return MA_ERROR;
61316     }
61317
61318     pEncoder->pInternalEncoder = pWav;
61319
61320     return MA_SUCCESS;
61321 }
61322
61323 static void ma_encoder__on_uninit_wav(ma_encoder* pEncoder)
61324 {
61325     drwav* pWav;
61326
61327     MA_ASSERT(pEncoder != NULL);
61328
61329     pWav = (drwav*)pEncoder->pInternalEncoder;
61330     MA_ASSERT(pWav != NULL);
61331
61332     drwav_uninit(pWav);
61333     ma_free(pWav, &pEncoder->config.allocationCallbacks);
61334 }
61335
61336 static ma_result ma_encoder__on_write_pcm_frames_wav(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten)
61337 {
61338     drwav* pWav;
61339     ma_uint64 framesWritten;
61340
61341     MA_ASSERT(pEncoder != NULL);
61342
61343     pWav = (drwav*)pEncoder->pInternalEncoder;
61344     MA_ASSERT(pWav != NULL);
61345
61346     framesWritten = drwav_write_pcm_frames(pWav, frameCount, pFramesIn);
61347
61348     if (pFramesWritten != NULL) {
61349         *pFramesWritten = framesWritten;
61350     }
61351
61352     return MA_SUCCESS;
61353 }
61354 #endif
61355
61356 MA_API ma_encoder_config ma_encoder_config_init(ma_encoding_format encodingFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
61357 {
61358     ma_encoder_config config;
61359
61360     MA_ZERO_OBJECT(&config);
61361     config.encodingFormat = encodingFormat;
61362     config.format = format;
61363     config.channels = channels;
61364     config.sampleRate = sampleRate;
61365
61366     return config;
61367 }
61368
61369 MA_API ma_result ma_encoder_preinit(const ma_encoder_config* pConfig, ma_encoder* pEncoder)
61370 {
61371     ma_result result;
61372
61373     if (pEncoder == NULL) {
61374         return MA_INVALID_ARGS;
61375     }
61376
61377     MA_ZERO_OBJECT(pEncoder);
61378
61379     if (pConfig == NULL) {
61380         return MA_INVALID_ARGS;
61381     }
61382
61383     if (pConfig->format == ma_format_unknown || pConfig->channels == 0 || pConfig->sampleRate == 0) {
61384         return MA_INVALID_ARGS;
61385     }
61386
61387     pEncoder->config = *pConfig;
61388
61389     result = ma_allocation_callbacks_init_copy(&pEncoder->config.allocationCallbacks, &pConfig->allocationCallbacks);
61390     if (result != MA_SUCCESS) {
61391         return result;
61392     }
61393
61394     return MA_SUCCESS;
61395 }
61396
61397 MA_API ma_result ma_encoder_init__internal(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void* pUserData, ma_encoder* pEncoder)
61398 {
61399     ma_result result = MA_SUCCESS;
61400
61401     /* This assumes ma_encoder_preinit() has been called prior. */
61402     MA_ASSERT(pEncoder != NULL);
61403
61404     if (onWrite == NULL || onSeek == NULL) {
61405         return MA_INVALID_ARGS;
61406     }
61407
61408     pEncoder->onWrite   = onWrite;
61409     pEncoder->onSeek    = onSeek;
61410     pEncoder->pUserData = pUserData;
61411
61412     switch (pEncoder->config.encodingFormat)
61413     {
61414         case ma_encoding_format_wav:
61415         {
61416         #if defined(MA_HAS_WAV)
61417             pEncoder->onInit           = ma_encoder__on_init_wav;
61418             pEncoder->onUninit         = ma_encoder__on_uninit_wav;
61419             pEncoder->onWritePCMFrames = ma_encoder__on_write_pcm_frames_wav;
61420         #else
61421             result = MA_NO_BACKEND;
61422         #endif
61423         } break;
61424
61425         default:
61426         {
61427             result = MA_INVALID_ARGS;
61428         } break;
61429     }
61430
61431     /* Getting here means we should have our backend callbacks set up. */
61432     if (result == MA_SUCCESS) {
61433         result = pEncoder->onInit(pEncoder);
61434         if (result != MA_SUCCESS) {
61435             return result;
61436         }
61437     }
61438
61439     return MA_SUCCESS;
61440 }
61441
61442 MA_API size_t ma_encoder__on_write_stdio(ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite)
61443 {
61444     return fwrite(pBufferIn, 1, bytesToWrite, (FILE*)pEncoder->pFile);
61445 }
61446
61447 MA_API ma_bool32 ma_encoder__on_seek_stdio(ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin)
61448 {
61449     return fseek((FILE*)pEncoder->pFile, byteOffset, (origin == ma_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
61450 }
61451
61452 MA_API ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder)
61453 {
61454     ma_result result;
61455     FILE* pFile;
61456
61457     result = ma_encoder_preinit(pConfig, pEncoder);
61458     if (result != MA_SUCCESS) {
61459         return result;
61460     }
61461
61462     /* Now open the file. If this fails we don't need to uninitialize the encoder. */
61463     result = ma_fopen(&pFile, pFilePath, "wb");
61464     if (pFile == NULL) {
61465         return result;
61466     }
61467
61468     pEncoder->pFile = pFile;
61469
61470     return ma_encoder_init__internal(ma_encoder__on_write_stdio, ma_encoder__on_seek_stdio, NULL, pEncoder);
61471 }
61472
61473 MA_API ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder)
61474 {
61475     ma_result result;
61476     FILE* pFile;
61477
61478     result = ma_encoder_preinit(pConfig, pEncoder);
61479     if (result != MA_SUCCESS) {
61480         return result;
61481     }
61482
61483     /* Now open the file. If this fails we don't need to uninitialize the encoder. */
61484     result = ma_wfopen(&pFile, pFilePath, L"wb", &pEncoder->config.allocationCallbacks);
61485     if (pFile == NULL) {
61486         return result;
61487     }
61488
61489     pEncoder->pFile = pFile;
61490
61491     return ma_encoder_init__internal(ma_encoder__on_write_stdio, ma_encoder__on_seek_stdio, NULL, pEncoder);
61492 }
61493
61494 MA_API 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)
61495 {
61496     ma_result result;
61497
61498     result = ma_encoder_preinit(pConfig, pEncoder);
61499     if (result != MA_SUCCESS) {
61500         return result;
61501     }
61502
61503     return ma_encoder_init__internal(onWrite, onSeek, pUserData, pEncoder);
61504 }
61505
61506
61507 MA_API void ma_encoder_uninit(ma_encoder* pEncoder)
61508 {
61509     if (pEncoder == NULL) {
61510         return;
61511     }
61512
61513     if (pEncoder->onUninit) {
61514         pEncoder->onUninit(pEncoder);
61515     }
61516
61517     /* If we have a file handle, close it. */
61518     if (pEncoder->onWrite == ma_encoder__on_write_stdio) {
61519         fclose((FILE*)pEncoder->pFile);
61520     }
61521 }
61522
61523
61524 MA_API ma_result ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount, ma_uint64* pFramesWritten)
61525 {
61526     if (pFramesWritten != NULL) {
61527         *pFramesWritten = 0;
61528     }
61529
61530     if (pEncoder == NULL || pFramesIn == NULL) {
61531         return MA_INVALID_ARGS;
61532     }
61533
61534     return pEncoder->onWritePCMFrames(pEncoder, pFramesIn, frameCount, pFramesWritten);
61535 }
61536 #endif  /* MA_NO_ENCODING */
61537
61538
61539
61540 /**************************************************************************************************************************************************************
61541
61542 Generation
61543
61544 **************************************************************************************************************************************************************/
61545 #ifndef MA_NO_GENERATION
61546 MA_API ma_waveform_config ma_waveform_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_waveform_type type, double amplitude, double frequency)
61547 {
61548     ma_waveform_config config;
61549
61550     MA_ZERO_OBJECT(&config);
61551     config.format     = format;
61552     config.channels   = channels;
61553     config.sampleRate = sampleRate;
61554     config.type       = type;
61555     config.amplitude  = amplitude;
61556     config.frequency  = frequency;
61557
61558     return config;
61559 }
61560
61561 static ma_result ma_waveform__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
61562 {
61563     return ma_waveform_read_pcm_frames((ma_waveform*)pDataSource, pFramesOut, frameCount, pFramesRead);
61564 }
61565
61566 static ma_result ma_waveform__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
61567 {
61568     return ma_waveform_seek_to_pcm_frame((ma_waveform*)pDataSource, frameIndex);
61569 }
61570
61571 static ma_result ma_waveform__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
61572 {
61573     ma_waveform* pWaveform = (ma_waveform*)pDataSource;
61574
61575     *pFormat     = pWaveform->config.format;
61576     *pChannels   = pWaveform->config.channels;
61577     *pSampleRate = pWaveform->config.sampleRate;
61578     ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pWaveform->config.channels);
61579
61580     return MA_SUCCESS;
61581 }
61582
61583 static ma_result ma_waveform__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
61584 {
61585     ma_waveform* pWaveform = (ma_waveform*)pDataSource;
61586
61587     *pCursor = (ma_uint64)(pWaveform->time / pWaveform->advance);
61588
61589     return MA_SUCCESS;
61590 }
61591
61592 static double ma_waveform__calculate_advance(ma_uint32 sampleRate, double frequency)
61593 {
61594     return (1.0 / (sampleRate / frequency));
61595 }
61596
61597 static void ma_waveform__update_advance(ma_waveform* pWaveform)
61598 {
61599     pWaveform->advance = ma_waveform__calculate_advance(pWaveform->config.sampleRate, pWaveform->config.frequency);
61600 }
61601
61602 static ma_data_source_vtable g_ma_waveform_data_source_vtable =
61603 {
61604     ma_waveform__data_source_on_read,
61605     ma_waveform__data_source_on_seek,
61606     ma_waveform__data_source_on_get_data_format,
61607     ma_waveform__data_source_on_get_cursor,
61608     NULL,   /* onGetLength. There's no notion of a length in waveforms. */
61609     NULL,   /* onSetLooping */
61610     0
61611 };
61612
61613 MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform)
61614 {
61615     ma_result result;
61616     ma_data_source_config dataSourceConfig;
61617
61618     if (pWaveform == NULL) {
61619         return MA_INVALID_ARGS;
61620     }
61621
61622     MA_ZERO_OBJECT(pWaveform);
61623
61624     dataSourceConfig = ma_data_source_config_init();
61625     dataSourceConfig.vtable = &g_ma_waveform_data_source_vtable;
61626
61627     result = ma_data_source_init(&dataSourceConfig, &pWaveform->ds);
61628     if (result != MA_SUCCESS) {
61629         return result;
61630     }
61631
61632     pWaveform->config  = *pConfig;
61633     pWaveform->advance = ma_waveform__calculate_advance(pWaveform->config.sampleRate, pWaveform->config.frequency);
61634     pWaveform->time    = 0;
61635
61636     return MA_SUCCESS;
61637 }
61638
61639 MA_API void ma_waveform_uninit(ma_waveform* pWaveform)
61640 {
61641     if (pWaveform == NULL) {
61642         return;
61643     }
61644
61645     ma_data_source_uninit(&pWaveform->ds);
61646 }
61647
61648 MA_API ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude)
61649 {
61650     if (pWaveform == NULL) {
61651         return MA_INVALID_ARGS;
61652     }
61653
61654     pWaveform->config.amplitude = amplitude;
61655     return MA_SUCCESS;
61656 }
61657
61658 MA_API ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency)
61659 {
61660     if (pWaveform == NULL) {
61661         return MA_INVALID_ARGS;
61662     }
61663
61664     pWaveform->config.frequency = frequency;
61665     ma_waveform__update_advance(pWaveform);
61666
61667     return MA_SUCCESS;
61668 }
61669
61670 MA_API ma_result ma_waveform_set_type(ma_waveform* pWaveform, ma_waveform_type type)
61671 {
61672     if (pWaveform == NULL) {
61673         return MA_INVALID_ARGS;
61674     }
61675
61676     pWaveform->config.type = type;
61677     return MA_SUCCESS;
61678 }
61679
61680 MA_API ma_result ma_waveform_set_sample_rate(ma_waveform* pWaveform, ma_uint32 sampleRate)
61681 {
61682     if (pWaveform == NULL) {
61683         return MA_INVALID_ARGS;
61684     }
61685
61686     pWaveform->config.sampleRate = sampleRate;
61687     ma_waveform__update_advance(pWaveform);
61688
61689     return MA_SUCCESS;
61690 }
61691
61692 static float ma_waveform_sine_f32(double time, double amplitude)
61693 {
61694     return (float)(ma_sind(MA_TAU_D * time) * amplitude);
61695 }
61696
61697 static ma_int16 ma_waveform_sine_s16(double time, double amplitude)
61698 {
61699     return ma_pcm_sample_f32_to_s16(ma_waveform_sine_f32(time, amplitude));
61700 }
61701
61702 static float ma_waveform_square_f32(double time, double amplitude)
61703 {
61704     double f = time - (ma_int64)time;
61705     double r;
61706
61707     if (f < 0.5) {
61708         r =  amplitude;
61709     } else {
61710         r = -amplitude;
61711     }
61712
61713     return (float)r;
61714 }
61715
61716 static ma_int16 ma_waveform_square_s16(double time, double amplitude)
61717 {
61718     return ma_pcm_sample_f32_to_s16(ma_waveform_square_f32(time, amplitude));
61719 }
61720
61721 static float ma_waveform_triangle_f32(double time, double amplitude)
61722 {
61723     double f = time - (ma_int64)time;
61724     double r;
61725
61726     r = 2 * ma_abs(2 * (f - 0.5)) - 1;
61727
61728     return (float)(r * amplitude);
61729 }
61730
61731 static ma_int16 ma_waveform_triangle_s16(double time, double amplitude)
61732 {
61733     return ma_pcm_sample_f32_to_s16(ma_waveform_triangle_f32(time, amplitude));
61734 }
61735
61736 static float ma_waveform_sawtooth_f32(double time, double amplitude)
61737 {
61738     double f = time - (ma_int64)time;
61739     double r;
61740
61741     r = 2 * (f - 0.5);
61742
61743     return (float)(r * amplitude);
61744 }
61745
61746 static ma_int16 ma_waveform_sawtooth_s16(double time, double amplitude)
61747 {
61748     return ma_pcm_sample_f32_to_s16(ma_waveform_sawtooth_f32(time, amplitude));
61749 }
61750
61751 static void ma_waveform_read_pcm_frames__sine(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
61752 {
61753     ma_uint64 iFrame;
61754     ma_uint64 iChannel;
61755     ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
61756     ma_uint32 bpf = bps * pWaveform->config.channels;
61757
61758     MA_ASSERT(pWaveform  != NULL);
61759     MA_ASSERT(pFramesOut != NULL);
61760
61761     if (pWaveform->config.format == ma_format_f32) {
61762         float* pFramesOutF32 = (float*)pFramesOut;
61763         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61764             float s = ma_waveform_sine_f32(pWaveform->time, pWaveform->config.amplitude);
61765             pWaveform->time += pWaveform->advance;
61766
61767             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61768                 pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
61769             }
61770         }
61771     } else if (pWaveform->config.format == ma_format_s16) {
61772         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
61773         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61774             ma_int16 s = ma_waveform_sine_s16(pWaveform->time, pWaveform->config.amplitude);
61775             pWaveform->time += pWaveform->advance;
61776
61777             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61778                 pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
61779             }
61780         }
61781     } else {
61782         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61783             float s = ma_waveform_sine_f32(pWaveform->time, pWaveform->config.amplitude);
61784             pWaveform->time += pWaveform->advance;
61785
61786             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61787                 ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
61788             }
61789         }
61790     }
61791 }
61792
61793 static void ma_waveform_read_pcm_frames__square(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
61794 {
61795     ma_uint64 iFrame;
61796     ma_uint64 iChannel;
61797     ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
61798     ma_uint32 bpf = bps * pWaveform->config.channels;
61799
61800     MA_ASSERT(pWaveform  != NULL);
61801     MA_ASSERT(pFramesOut != NULL);
61802
61803     if (pWaveform->config.format == ma_format_f32) {
61804         float* pFramesOutF32 = (float*)pFramesOut;
61805         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61806             float s = ma_waveform_square_f32(pWaveform->time, pWaveform->config.amplitude);
61807             pWaveform->time += pWaveform->advance;
61808
61809             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61810                 pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
61811             }
61812         }
61813     } else if (pWaveform->config.format == ma_format_s16) {
61814         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
61815         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61816             ma_int16 s = ma_waveform_square_s16(pWaveform->time, pWaveform->config.amplitude);
61817             pWaveform->time += pWaveform->advance;
61818
61819             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61820                 pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
61821             }
61822         }
61823     } else {
61824         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61825             float s = ma_waveform_square_f32(pWaveform->time, pWaveform->config.amplitude);
61826             pWaveform->time += pWaveform->advance;
61827
61828             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61829                 ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
61830             }
61831         }
61832     }
61833 }
61834
61835 static void ma_waveform_read_pcm_frames__triangle(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
61836 {
61837     ma_uint64 iFrame;
61838     ma_uint64 iChannel;
61839     ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
61840     ma_uint32 bpf = bps * pWaveform->config.channels;
61841
61842     MA_ASSERT(pWaveform  != NULL);
61843     MA_ASSERT(pFramesOut != NULL);
61844
61845     if (pWaveform->config.format == ma_format_f32) {
61846         float* pFramesOutF32 = (float*)pFramesOut;
61847         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61848             float s = ma_waveform_triangle_f32(pWaveform->time, pWaveform->config.amplitude);
61849             pWaveform->time += pWaveform->advance;
61850
61851             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61852                 pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
61853             }
61854         }
61855     } else if (pWaveform->config.format == ma_format_s16) {
61856         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
61857         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61858             ma_int16 s = ma_waveform_triangle_s16(pWaveform->time, pWaveform->config.amplitude);
61859             pWaveform->time += pWaveform->advance;
61860
61861             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61862                 pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
61863             }
61864         }
61865     } else {
61866         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61867             float s = ma_waveform_triangle_f32(pWaveform->time, pWaveform->config.amplitude);
61868             pWaveform->time += pWaveform->advance;
61869
61870             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61871                 ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
61872             }
61873         }
61874     }
61875 }
61876
61877 static void ma_waveform_read_pcm_frames__sawtooth(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
61878 {
61879     ma_uint64 iFrame;
61880     ma_uint64 iChannel;
61881     ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
61882     ma_uint32 bpf = bps * pWaveform->config.channels;
61883
61884     MA_ASSERT(pWaveform  != NULL);
61885     MA_ASSERT(pFramesOut != NULL);
61886
61887     if (pWaveform->config.format == ma_format_f32) {
61888         float* pFramesOutF32 = (float*)pFramesOut;
61889         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61890             float s = ma_waveform_sawtooth_f32(pWaveform->time, pWaveform->config.amplitude);
61891             pWaveform->time += pWaveform->advance;
61892
61893             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61894                 pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
61895             }
61896         }
61897     } else if (pWaveform->config.format == ma_format_s16) {
61898         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
61899         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61900             ma_int16 s = ma_waveform_sawtooth_s16(pWaveform->time, pWaveform->config.amplitude);
61901             pWaveform->time += pWaveform->advance;
61902
61903             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61904                 pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
61905             }
61906         }
61907     } else {
61908         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
61909             float s = ma_waveform_sawtooth_f32(pWaveform->time, pWaveform->config.amplitude);
61910             pWaveform->time += pWaveform->advance;
61911
61912             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
61913                 ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
61914             }
61915         }
61916     }
61917 }
61918
61919 MA_API ma_result ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
61920 {
61921     if (pFramesRead != NULL) {
61922         *pFramesRead = 0;
61923     }
61924
61925     if (frameCount == 0) {
61926         return MA_INVALID_ARGS;
61927     }
61928
61929     if (pWaveform == NULL) {
61930         return MA_INVALID_ARGS;
61931     }
61932
61933     if (pFramesOut != NULL) {
61934         switch (pWaveform->config.type)
61935         {
61936             case ma_waveform_type_sine:
61937             {
61938                 ma_waveform_read_pcm_frames__sine(pWaveform, pFramesOut, frameCount);
61939             } break;
61940
61941             case ma_waveform_type_square:
61942             {
61943                 ma_waveform_read_pcm_frames__square(pWaveform, pFramesOut, frameCount);
61944             } break;
61945
61946             case ma_waveform_type_triangle:
61947             {
61948                 ma_waveform_read_pcm_frames__triangle(pWaveform, pFramesOut, frameCount);
61949             } break;
61950
61951             case ma_waveform_type_sawtooth:
61952             {
61953                 ma_waveform_read_pcm_frames__sawtooth(pWaveform, pFramesOut, frameCount);
61954             } break;
61955
61956             default: return MA_INVALID_OPERATION;   /* Unknown waveform type. */
61957         }
61958     } else {
61959         pWaveform->time += pWaveform->advance * (ma_int64)frameCount; /* Cast to int64 required for VC6. Won't affect anything in practice. */
61960     }
61961
61962     if (pFramesRead != NULL) {
61963         *pFramesRead = frameCount;
61964     }
61965
61966     return MA_SUCCESS;
61967 }
61968
61969 MA_API ma_result ma_waveform_seek_to_pcm_frame(ma_waveform* pWaveform, ma_uint64 frameIndex)
61970 {
61971     if (pWaveform == NULL) {
61972         return MA_INVALID_ARGS;
61973     }
61974
61975     pWaveform->time = pWaveform->advance * (ma_int64)frameIndex;    /* Casting for VC6. Won't be an issue in practice. */
61976
61977     return MA_SUCCESS;
61978 }
61979
61980
61981 MA_API ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels, ma_noise_type type, ma_int32 seed, double amplitude)
61982 {
61983     ma_noise_config config;
61984     MA_ZERO_OBJECT(&config);
61985
61986     config.format    = format;
61987     config.channels  = channels;
61988     config.type      = type;
61989     config.seed      = seed;
61990     config.amplitude = amplitude;
61991
61992     if (config.seed == 0) {
61993         config.seed = MA_DEFAULT_LCG_SEED;
61994     }
61995
61996     return config;
61997 }
61998
61999
62000 static ma_result ma_noise__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
62001 {
62002     return ma_noise_read_pcm_frames((ma_noise*)pDataSource, pFramesOut, frameCount, pFramesRead);
62003 }
62004
62005 static ma_result ma_noise__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
62006 {
62007     /* No-op. Just pretend to be successful. */
62008     (void)pDataSource;
62009     (void)frameIndex;
62010     return MA_SUCCESS;
62011 }
62012
62013 static ma_result ma_noise__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
62014 {
62015     ma_noise* pNoise = (ma_noise*)pDataSource;
62016
62017     *pFormat     = pNoise->config.format;
62018     *pChannels   = pNoise->config.channels;
62019     *pSampleRate = 0;   /* There is no notion of sample rate with noise generation. */
62020     ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pNoise->config.channels);
62021
62022     return MA_SUCCESS;
62023 }
62024
62025 static ma_data_source_vtable g_ma_noise_data_source_vtable =
62026 {
62027     ma_noise__data_source_on_read,
62028     ma_noise__data_source_on_seek,  /* No-op for noise. */
62029     ma_noise__data_source_on_get_data_format,
62030     NULL,   /* onGetCursor. No notion of a cursor for noise. */
62031     NULL,   /* onGetLength. No notion of a length for noise. */
62032     NULL,   /* onSetLooping */
62033     0
62034 };
62035
62036
62037 #ifndef MA_PINK_NOISE_BIN_SIZE
62038 #define MA_PINK_NOISE_BIN_SIZE 16
62039 #endif
62040
62041 typedef struct
62042 {
62043     size_t sizeInBytes;
62044     struct
62045     {
62046         size_t binOffset;
62047         size_t accumulationOffset;
62048         size_t counterOffset;
62049     } pink;
62050     struct
62051     {
62052         size_t accumulationOffset;
62053     } brownian;
62054 } ma_noise_heap_layout;
62055
62056 static ma_result ma_noise_get_heap_layout(const ma_noise_config* pConfig, ma_noise_heap_layout* pHeapLayout)
62057 {
62058     MA_ASSERT(pHeapLayout != NULL);
62059
62060     MA_ZERO_OBJECT(pHeapLayout);
62061
62062     if (pConfig == NULL) {
62063         return MA_INVALID_ARGS;
62064     }
62065
62066     if (pConfig->channels == 0) {
62067         return MA_INVALID_ARGS;
62068     }
62069
62070     pHeapLayout->sizeInBytes = 0;
62071
62072     /* Pink. */
62073     if (pConfig->type == ma_noise_type_pink) {
62074         /* bin */
62075         pHeapLayout->pink.binOffset = pHeapLayout->sizeInBytes;
62076         pHeapLayout->sizeInBytes += sizeof(double*) * pConfig->channels;
62077         pHeapLayout->sizeInBytes += sizeof(double ) * pConfig->channels * MA_PINK_NOISE_BIN_SIZE;
62078
62079         /* accumulation */
62080         pHeapLayout->pink.accumulationOffset = pHeapLayout->sizeInBytes;
62081         pHeapLayout->sizeInBytes += sizeof(double) * pConfig->channels;
62082
62083         /* counter */
62084         pHeapLayout->pink.counterOffset = pHeapLayout->sizeInBytes;
62085         pHeapLayout->sizeInBytes += sizeof(ma_uint32) * pConfig->channels;
62086     }
62087
62088     /* Brownian. */
62089     if (pConfig->type == ma_noise_type_brownian) {
62090         /* accumulation */
62091         pHeapLayout->brownian.accumulationOffset = pHeapLayout->sizeInBytes;
62092         pHeapLayout->sizeInBytes += sizeof(double) * pConfig->channels;
62093     }
62094
62095     /* Make sure allocation size is aligned. */
62096     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
62097
62098     return MA_SUCCESS;
62099 }
62100
62101 MA_API ma_result ma_noise_get_heap_size(const ma_noise_config* pConfig, size_t* pHeapSizeInBytes)
62102 {
62103     ma_result result;
62104     ma_noise_heap_layout heapLayout;
62105
62106     if (pHeapSizeInBytes == NULL) {
62107         return MA_INVALID_ARGS;
62108     }
62109
62110     *pHeapSizeInBytes = 0;
62111
62112     result = ma_noise_get_heap_layout(pConfig, &heapLayout);
62113     if (result != MA_SUCCESS) {
62114         return result;
62115     }
62116
62117     *pHeapSizeInBytes = heapLayout.sizeInBytes;
62118
62119     return MA_SUCCESS;
62120 }
62121
62122 MA_API ma_result ma_noise_init_preallocated(const ma_noise_config* pConfig, void* pHeap, ma_noise* pNoise)
62123 {
62124     ma_result result;
62125     ma_noise_heap_layout heapLayout;
62126     ma_data_source_config dataSourceConfig;
62127     ma_uint32 iChannel;
62128
62129     if (pNoise == NULL) {
62130         return MA_INVALID_ARGS;
62131     }
62132
62133     MA_ZERO_OBJECT(pNoise);
62134
62135     result = ma_noise_get_heap_layout(pConfig, &heapLayout);
62136     if (result != MA_SUCCESS) {
62137         return result;
62138     }
62139
62140     pNoise->_pHeap = pHeap;
62141     MA_ZERO_MEMORY(pNoise->_pHeap, heapLayout.sizeInBytes);
62142
62143     dataSourceConfig = ma_data_source_config_init();
62144     dataSourceConfig.vtable = &g_ma_noise_data_source_vtable;
62145
62146     result = ma_data_source_init(&dataSourceConfig, &pNoise->ds);
62147     if (result != MA_SUCCESS) {
62148         return result;
62149     }
62150
62151     pNoise->config = *pConfig;
62152     ma_lcg_seed(&pNoise->lcg, pConfig->seed);
62153
62154     if (pNoise->config.type == ma_noise_type_pink) {
62155         pNoise->state.pink.bin          = (double**  )ma_offset_ptr(pHeap, heapLayout.pink.binOffset);
62156         pNoise->state.pink.accumulation = (double*   )ma_offset_ptr(pHeap, heapLayout.pink.accumulationOffset);
62157         pNoise->state.pink.counter      = (ma_uint32*)ma_offset_ptr(pHeap, heapLayout.pink.counterOffset);
62158
62159         for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) {
62160             pNoise->state.pink.bin[iChannel]          = (double*)ma_offset_ptr(pHeap, heapLayout.pink.binOffset + (sizeof(double*) * pConfig->channels) + (sizeof(double) * MA_PINK_NOISE_BIN_SIZE * iChannel));
62161             pNoise->state.pink.accumulation[iChannel] = 0;
62162             pNoise->state.pink.counter[iChannel]      = 1;
62163         }
62164     }
62165
62166     if (pNoise->config.type == ma_noise_type_brownian) {
62167         pNoise->state.brownian.accumulation = (double*)ma_offset_ptr(pHeap, heapLayout.brownian.accumulationOffset);
62168
62169         for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) {
62170             pNoise->state.brownian.accumulation[iChannel] = 0;
62171         }
62172     }
62173
62174     return MA_SUCCESS;
62175 }
62176
62177 MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_noise* pNoise)
62178 {
62179     ma_result result;
62180     size_t heapSizeInBytes;
62181     void* pHeap;
62182
62183     result = ma_noise_get_heap_size(pConfig, &heapSizeInBytes);
62184     if (result != MA_SUCCESS) {
62185         return result;
62186     }
62187
62188     if (heapSizeInBytes > 0) {
62189         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
62190         if (pHeap == NULL) {
62191             return MA_OUT_OF_MEMORY;
62192         }
62193     } else {
62194         pHeap = NULL;
62195     }
62196
62197     result = ma_noise_init_preallocated(pConfig, pHeap, pNoise);
62198     if (result != MA_SUCCESS) {
62199         ma_free(pHeap, pAllocationCallbacks);
62200         return result;
62201     }
62202
62203     pNoise->_ownsHeap = MA_TRUE;
62204     return MA_SUCCESS;
62205 }
62206
62207 MA_API void ma_noise_uninit(ma_noise* pNoise, const ma_allocation_callbacks* pAllocationCallbacks)
62208 {
62209     if (pNoise == NULL) {
62210         return;
62211     }
62212
62213     ma_data_source_uninit(&pNoise->ds);
62214
62215     if (pNoise->_ownsHeap) {
62216         ma_free(pNoise->_pHeap, pAllocationCallbacks);
62217     }
62218 }
62219
62220 MA_API ma_result ma_noise_set_amplitude(ma_noise* pNoise, double amplitude)
62221 {
62222     if (pNoise == NULL) {
62223         return MA_INVALID_ARGS;
62224     }
62225
62226     pNoise->config.amplitude = amplitude;
62227     return MA_SUCCESS;
62228 }
62229
62230 MA_API ma_result ma_noise_set_seed(ma_noise* pNoise, ma_int32 seed)
62231 {
62232     if (pNoise == NULL) {
62233         return MA_INVALID_ARGS;
62234     }
62235
62236     pNoise->lcg.state = seed;
62237     return MA_SUCCESS;
62238 }
62239
62240
62241 MA_API ma_result ma_noise_set_type(ma_noise* pNoise, ma_noise_type type)
62242 {
62243     if (pNoise == NULL) {
62244         return MA_INVALID_ARGS;
62245     }
62246
62247     pNoise->config.type = type;
62248     return MA_SUCCESS;
62249 }
62250
62251 static MA_INLINE float ma_noise_f32_white(ma_noise* pNoise)
62252 {
62253     return (float)(ma_lcg_rand_f64(&pNoise->lcg) * pNoise->config.amplitude);
62254 }
62255
62256 static MA_INLINE ma_int16 ma_noise_s16_white(ma_noise* pNoise)
62257 {
62258     return ma_pcm_sample_f32_to_s16(ma_noise_f32_white(pNoise));
62259 }
62260
62261 static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
62262 {
62263     ma_uint64 iFrame;
62264     ma_uint32 iChannel;
62265     const ma_uint32 channels = pNoise->config.channels;
62266     MA_ASSUME(channels > 0);
62267
62268     if (pNoise->config.format == ma_format_f32) {
62269         float* pFramesOutF32 = (float*)pFramesOut;
62270         if (pNoise->config.duplicateChannels) {
62271             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62272                 float s = ma_noise_f32_white(pNoise);
62273                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62274                     pFramesOutF32[iFrame*channels + iChannel] = s;
62275                 }
62276             }
62277         } else {
62278             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62279                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62280                     pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_white(pNoise);
62281                 }
62282             }
62283         }
62284     } else if (pNoise->config.format == ma_format_s16) {
62285         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
62286         if (pNoise->config.duplicateChannels) {
62287             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62288                 ma_int16 s = ma_noise_s16_white(pNoise);
62289                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62290                     pFramesOutS16[iFrame*channels + iChannel] = s;
62291                 }
62292             }
62293         } else {
62294             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62295                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62296                     pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_white(pNoise);
62297                 }
62298             }
62299         }
62300     } else {
62301         const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format);
62302         const ma_uint32 bpf = bps * channels;
62303
62304         if (pNoise->config.duplicateChannels) {
62305             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62306                 float s = ma_noise_f32_white(pNoise);
62307                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62308                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
62309                 }
62310             }
62311         } else {
62312             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62313                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62314                     float s = ma_noise_f32_white(pNoise);
62315                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
62316                 }
62317             }
62318         }
62319     }
62320
62321     return frameCount;
62322 }
62323
62324
62325 static MA_INLINE unsigned int ma_tzcnt32(unsigned int x)
62326 {
62327     unsigned int n;
62328
62329     /* Special case for odd numbers since they should happen about half the time. */
62330     if (x & 0x1)  {
62331         return 0;
62332     }
62333
62334     if (x == 0) {
62335         return sizeof(x) << 3;
62336     }
62337
62338     n = 1;
62339     if ((x & 0x0000FFFF) == 0) { x >>= 16; n += 16; }
62340     if ((x & 0x000000FF) == 0) { x >>=  8; n +=  8; }
62341     if ((x & 0x0000000F) == 0) { x >>=  4; n +=  4; }
62342     if ((x & 0x00000003) == 0) { x >>=  2; n +=  2; }
62343     n -= x & 0x00000001;
62344
62345     return n;
62346 }
62347
62348 /*
62349 Pink noise generation based on Tonic (public domain) with modifications. https://github.com/TonicAudio/Tonic/blob/master/src/Tonic/Noise.h
62350
62351 This is basically _the_ reference for pink noise from what I've found: http://www.firstpr.com.au/dsp/pink-noise/
62352 */
62353 static MA_INLINE float ma_noise_f32_pink(ma_noise* pNoise, ma_uint32 iChannel)
62354 {
62355     double result;
62356     double binPrev;
62357     double binNext;
62358     unsigned int ibin;
62359
62360     ibin = ma_tzcnt32(pNoise->state.pink.counter[iChannel]) & (MA_PINK_NOISE_BIN_SIZE - 1);
62361
62362     binPrev = pNoise->state.pink.bin[iChannel][ibin];
62363     binNext = ma_lcg_rand_f64(&pNoise->lcg);
62364     pNoise->state.pink.bin[iChannel][ibin] = binNext;
62365
62366     pNoise->state.pink.accumulation[iChannel] += (binNext - binPrev);
62367     pNoise->state.pink.counter[iChannel]      += 1;
62368
62369     result = (ma_lcg_rand_f64(&pNoise->lcg) + pNoise->state.pink.accumulation[iChannel]);
62370     result /= 10;
62371
62372     return (float)(result * pNoise->config.amplitude);
62373 }
62374
62375 static MA_INLINE ma_int16 ma_noise_s16_pink(ma_noise* pNoise, ma_uint32 iChannel)
62376 {
62377     return ma_pcm_sample_f32_to_s16(ma_noise_f32_pink(pNoise, iChannel));
62378 }
62379
62380 static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
62381 {
62382     ma_uint64 iFrame;
62383     ma_uint32 iChannel;
62384     const ma_uint32 channels = pNoise->config.channels;
62385     MA_ASSUME(channels > 0);
62386
62387     if (pNoise->config.format == ma_format_f32) {
62388         float* pFramesOutF32 = (float*)pFramesOut;
62389         if (pNoise->config.duplicateChannels) {
62390             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62391                 float s = ma_noise_f32_pink(pNoise, 0);
62392                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62393                     pFramesOutF32[iFrame*channels + iChannel] = s;
62394                 }
62395             }
62396         } else {
62397             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62398                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62399                     pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_pink(pNoise, iChannel);
62400                 }
62401             }
62402         }
62403     } else if (pNoise->config.format == ma_format_s16) {
62404         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
62405         if (pNoise->config.duplicateChannels) {
62406             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62407                 ma_int16 s = ma_noise_s16_pink(pNoise, 0);
62408                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62409                     pFramesOutS16[iFrame*channels + iChannel] = s;
62410                 }
62411             }
62412         } else {
62413             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62414                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62415                     pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_pink(pNoise, iChannel);
62416                 }
62417             }
62418         }
62419     } else {
62420         const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format);
62421         const ma_uint32 bpf = bps * channels;
62422
62423         if (pNoise->config.duplicateChannels) {
62424             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62425                 float s = ma_noise_f32_pink(pNoise, 0);
62426                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62427                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
62428                 }
62429             }
62430         } else {
62431             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62432                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62433                     float s = ma_noise_f32_pink(pNoise, iChannel);
62434                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
62435                 }
62436             }
62437         }
62438     }
62439
62440     return frameCount;
62441 }
62442
62443
62444 static MA_INLINE float ma_noise_f32_brownian(ma_noise* pNoise, ma_uint32 iChannel)
62445 {
62446     double result;
62447
62448     result = (ma_lcg_rand_f64(&pNoise->lcg) + pNoise->state.brownian.accumulation[iChannel]);
62449     result /= 1.005; /* Don't escape the -1..1 range on average. */
62450
62451     pNoise->state.brownian.accumulation[iChannel] = result;
62452     result /= 20;
62453
62454     return (float)(result * pNoise->config.amplitude);
62455 }
62456
62457 static MA_INLINE ma_int16 ma_noise_s16_brownian(ma_noise* pNoise, ma_uint32 iChannel)
62458 {
62459     return ma_pcm_sample_f32_to_s16(ma_noise_f32_brownian(pNoise, iChannel));
62460 }
62461
62462 static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
62463 {
62464     ma_uint64 iFrame;
62465     ma_uint32 iChannel;
62466     const ma_uint32 channels = pNoise->config.channels;
62467     MA_ASSUME(channels > 0);
62468
62469     if (pNoise->config.format == ma_format_f32) {
62470         float* pFramesOutF32 = (float*)pFramesOut;
62471         if (pNoise->config.duplicateChannels) {
62472             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62473                 float s = ma_noise_f32_brownian(pNoise, 0);
62474                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62475                     pFramesOutF32[iFrame*channels + iChannel] = s;
62476                 }
62477             }
62478         } else {
62479             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62480                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62481                     pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_brownian(pNoise, iChannel);
62482                 }
62483             }
62484         }
62485     } else if (pNoise->config.format == ma_format_s16) {
62486         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
62487         if (pNoise->config.duplicateChannels) {
62488             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62489                 ma_int16 s = ma_noise_s16_brownian(pNoise, 0);
62490                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62491                     pFramesOutS16[iFrame*channels + iChannel] = s;
62492                 }
62493             }
62494         } else {
62495             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62496                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62497                     pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_brownian(pNoise, iChannel);
62498                 }
62499             }
62500         }
62501     } else {
62502         const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format);
62503         const ma_uint32 bpf = bps * channels;
62504
62505         if (pNoise->config.duplicateChannels) {
62506             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62507                 float s = ma_noise_f32_brownian(pNoise, 0);
62508                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62509                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
62510                 }
62511             }
62512         } else {
62513             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
62514                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
62515                     float s = ma_noise_f32_brownian(pNoise, iChannel);
62516                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
62517                 }
62518             }
62519         }
62520     }
62521
62522     return frameCount;
62523 }
62524
62525 MA_API ma_result ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
62526 {
62527     ma_uint64 framesRead = 0;
62528
62529     if (pFramesRead != NULL) {
62530         *pFramesRead = 0;
62531     }
62532
62533     if (frameCount == 0) {
62534         return MA_INVALID_ARGS;
62535     }
62536
62537     if (pNoise == NULL) {
62538         return MA_INVALID_ARGS;
62539     }
62540
62541     /* The output buffer is allowed to be NULL. Since we aren't tracking cursors or anything we can just do nothing and pretend to be successful. */
62542     if (pFramesOut == NULL) {
62543         framesRead = frameCount;
62544     } else {
62545         switch (pNoise->config.type) {
62546             case ma_noise_type_white:    framesRead = ma_noise_read_pcm_frames__white   (pNoise, pFramesOut, frameCount); break;
62547             case ma_noise_type_pink:     framesRead = ma_noise_read_pcm_frames__pink    (pNoise, pFramesOut, frameCount); break;
62548             case ma_noise_type_brownian: framesRead = ma_noise_read_pcm_frames__brownian(pNoise, pFramesOut, frameCount); break;
62549             default: return MA_INVALID_OPERATION;   /* Unknown noise type. */
62550         }
62551     }
62552
62553     if (pFramesRead != NULL) {
62554         *pFramesRead = framesRead;
62555     }
62556
62557     return MA_SUCCESS;
62558 }
62559 #endif /* MA_NO_GENERATION */
62560
62561
62562
62563 #ifndef MA_NO_RESOURCE_MANAGER
62564 #ifndef MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS
62565 #define MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS   1000
62566 #endif
62567
62568 #ifndef MA_RESOURCE_MANAGER_JOB_QUEUE_CAPACITY
62569 #define MA_RESOURCE_MANAGER_JOB_QUEUE_CAPACITY          1024
62570 #endif
62571
62572 MA_API ma_resource_manager_pipeline_notifications ma_resource_manager_pipeline_notifications_init(void)
62573 {
62574     ma_resource_manager_pipeline_notifications notifications;
62575
62576     MA_ZERO_OBJECT(&notifications);
62577
62578     return notifications;
62579 }
62580
62581 static void ma_resource_manager_pipeline_notifications_signal_all_notifications(const ma_resource_manager_pipeline_notifications* pPipelineNotifications)
62582 {
62583     if (pPipelineNotifications == NULL) {
62584         return;
62585     }
62586
62587     if (pPipelineNotifications->init.pNotification) { ma_async_notification_signal(pPipelineNotifications->init.pNotification); }
62588     if (pPipelineNotifications->done.pNotification) { ma_async_notification_signal(pPipelineNotifications->done.pNotification); }
62589 }
62590
62591 static void ma_resource_manager_pipeline_notifications_acquire_all_fences(const ma_resource_manager_pipeline_notifications* pPipelineNotifications)
62592 {
62593     if (pPipelineNotifications == NULL) {
62594         return;
62595     }
62596
62597     if (pPipelineNotifications->init.pFence != NULL) { ma_fence_acquire(pPipelineNotifications->init.pFence); }
62598     if (pPipelineNotifications->done.pFence != NULL) { ma_fence_acquire(pPipelineNotifications->done.pFence); }
62599 }
62600
62601 static void ma_resource_manager_pipeline_notifications_release_all_fences(const ma_resource_manager_pipeline_notifications* pPipelineNotifications)
62602 {
62603     if (pPipelineNotifications == NULL) {
62604         return;
62605     }
62606
62607     if (pPipelineNotifications->init.pFence != NULL) { ma_fence_release(pPipelineNotifications->init.pFence); }
62608     if (pPipelineNotifications->done.pFence != NULL) { ma_fence_release(pPipelineNotifications->done.pFence); }
62609 }
62610
62611
62612
62613 #define MA_RESOURCE_MANAGER_JOB_ID_NONE      ~((ma_uint64)0)
62614 #define MA_RESOURCE_MANAGER_JOB_SLOT_NONE    (ma_uint16)(~0)
62615
62616 static MA_INLINE ma_uint32 ma_resource_manager_job_extract_refcount(ma_uint64 toc)
62617 {
62618     return (ma_uint32)(toc >> 32);
62619 }
62620
62621 static MA_INLINE ma_uint16 ma_resource_manager_job_extract_slot(ma_uint64 toc)
62622 {
62623     return (ma_uint16)(toc & 0x0000FFFF);
62624 }
62625
62626 static MA_INLINE ma_uint16 ma_resource_manager_job_extract_code(ma_uint64 toc)
62627 {
62628     return (ma_uint16)((toc & 0xFFFF0000) >> 16);
62629 }
62630
62631 static MA_INLINE ma_uint64 ma_resource_manager_job_toc_to_allocation(ma_uint64 toc)
62632 {
62633     return ((ma_uint64)ma_resource_manager_job_extract_refcount(toc) << 32) | (ma_uint64)ma_resource_manager_job_extract_slot(toc);
62634 }
62635
62636 static MA_INLINE ma_uint64 ma_resource_manager_job_set_refcount(ma_uint64 toc, ma_uint32 refcount)
62637 {
62638     /* Clear the reference count first. */
62639     toc = toc & ~((ma_uint64)0xFFFFFFFF << 32);
62640     toc = toc |  ((ma_uint64)refcount   << 32);
62641
62642     return toc;
62643 }
62644
62645
62646 MA_API ma_resource_manager_job ma_resource_manager_job_init(ma_uint16 code)
62647 {
62648     ma_resource_manager_job job;
62649
62650     MA_ZERO_OBJECT(&job);
62651     job.toc.breakup.code = code;
62652     job.toc.breakup.slot = MA_RESOURCE_MANAGER_JOB_SLOT_NONE;    /* Temp value. Will be allocated when posted to a queue. */
62653     job.next             = MA_RESOURCE_MANAGER_JOB_ID_NONE;
62654
62655     return job;
62656 }
62657
62658
62659
62660 MA_API ma_resource_manager_job_queue_config ma_resource_manager_job_queue_config_init(ma_uint32 flags, ma_uint32 capacity)
62661 {
62662     ma_resource_manager_job_queue_config config;
62663
62664     config.flags    = flags;
62665     config.capacity = capacity;
62666
62667     return config;
62668 }
62669
62670
62671 typedef struct
62672 {
62673     size_t sizeInBytes;
62674     size_t allocatorOffset;
62675     size_t jobsOffset;
62676 } ma_resource_manager_job_queue_heap_layout;
62677
62678 static ma_result ma_resource_manager_job_queue_get_heap_layout(const ma_resource_manager_job_queue_config* pConfig, ma_resource_manager_job_queue_heap_layout* pHeapLayout)
62679 {
62680     ma_result result;
62681
62682     MA_ASSERT(pHeapLayout != NULL);
62683
62684     MA_ZERO_OBJECT(pHeapLayout);
62685
62686     if (pConfig == NULL) {
62687         return MA_INVALID_ARGS;
62688     }
62689
62690     if (pConfig->capacity == 0) {
62691         return MA_INVALID_ARGS;
62692     }
62693
62694     pHeapLayout->sizeInBytes = 0;
62695
62696     /* Allocator. */
62697     {
62698         ma_slot_allocator_config allocatorConfig;
62699         size_t allocatorHeapSizeInBytes;
62700
62701         allocatorConfig = ma_slot_allocator_config_init(pConfig->capacity);
62702         result = ma_slot_allocator_get_heap_size(&allocatorConfig, &allocatorHeapSizeInBytes);
62703         if (result != MA_SUCCESS) {
62704             return result;
62705         }
62706
62707         pHeapLayout->allocatorOffset = pHeapLayout->sizeInBytes;
62708         pHeapLayout->sizeInBytes    += allocatorHeapSizeInBytes;
62709     }
62710
62711     /* Jobs. */
62712     pHeapLayout->jobsOffset   = pHeapLayout->sizeInBytes;
62713     pHeapLayout->sizeInBytes += ma_align_64(pConfig->capacity * sizeof(ma_resource_manager_job));
62714
62715     return MA_SUCCESS;
62716 }
62717
62718 MA_API ma_result ma_resource_manager_job_queue_get_heap_size(const ma_resource_manager_job_queue_config* pConfig, size_t* pHeapSizeInBytes)
62719 {
62720     ma_result result;
62721     ma_resource_manager_job_queue_heap_layout layout;
62722
62723     if (pHeapSizeInBytes == NULL) {
62724         return MA_INVALID_ARGS;
62725     }
62726
62727     *pHeapSizeInBytes = 0;
62728
62729     result = ma_resource_manager_job_queue_get_heap_layout(pConfig, &layout);
62730     if (result != MA_SUCCESS) {
62731         return result;
62732     }
62733
62734     *pHeapSizeInBytes = layout.sizeInBytes;
62735
62736     return MA_SUCCESS;
62737 }
62738
62739 MA_API ma_result ma_resource_manager_job_queue_init_preallocated(const ma_resource_manager_job_queue_config* pConfig, void* pHeap, ma_resource_manager_job_queue* pQueue)
62740 {
62741     ma_result result;
62742     ma_resource_manager_job_queue_heap_layout heapLayout;
62743     ma_slot_allocator_config allocatorConfig;
62744
62745     if (pQueue == NULL) {
62746         return MA_INVALID_ARGS;
62747     }
62748
62749     MA_ZERO_OBJECT(pQueue);
62750
62751     result = ma_resource_manager_job_queue_get_heap_layout(pConfig, &heapLayout);
62752     if (result != MA_SUCCESS) {
62753         return result;
62754     }
62755
62756     pQueue->_pHeap = pHeap;
62757     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
62758
62759     pQueue->flags    = pConfig->flags;
62760     pQueue->capacity = pConfig->capacity;
62761     pQueue->pJobs    = (ma_resource_manager_job*)ma_offset_ptr(pHeap, heapLayout.jobsOffset);
62762
62763     allocatorConfig = ma_slot_allocator_config_init(pConfig->capacity);
62764     result = ma_slot_allocator_init_preallocated(&allocatorConfig, ma_offset_ptr(pHeap, heapLayout.allocatorOffset), &pQueue->allocator);
62765     if (result != MA_SUCCESS) {
62766         return result;
62767     }
62768
62769     /* We need a semaphore if we're running in non-blocking mode. If threading is disabled we need to return an error. */
62770     if ((pQueue->flags & MA_RESOURCE_MANAGER_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) {
62771         #ifndef MA_NO_THREADING
62772         {
62773             ma_semaphore_init(0, &pQueue->sem);
62774         }
62775         #else
62776         {
62777             /* Threading is disabled and we've requested non-blocking mode. */
62778             return MA_INVALID_OPERATION;
62779         }
62780         #endif
62781     }
62782
62783     /*
62784     Our queue needs to be initialized with a free standing node. This should always be slot 0. Required for the lock free algorithm. The first job in the queue is
62785     just a dummy item for giving us the first item in the list which is stored in the "next" member.
62786     */
62787     ma_slot_allocator_alloc(&pQueue->allocator, &pQueue->head);  /* Will never fail. */
62788     pQueue->pJobs[ma_resource_manager_job_extract_slot(pQueue->head)].next = MA_RESOURCE_MANAGER_JOB_ID_NONE;
62789     pQueue->tail = pQueue->head;
62790
62791     return MA_SUCCESS;
62792 }
62793
62794 MA_API ma_result ma_resource_manager_job_queue_init(const ma_resource_manager_job_queue_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_resource_manager_job_queue* pQueue)
62795 {
62796     ma_result result;
62797     size_t heapSizeInBytes;
62798     void* pHeap;
62799
62800     result = ma_resource_manager_job_queue_get_heap_size(pConfig, &heapSizeInBytes);
62801     if (result != MA_SUCCESS) {
62802         return result;
62803     }
62804
62805     if (heapSizeInBytes > 0) {
62806         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
62807         if (pHeap == NULL) {
62808             return MA_OUT_OF_MEMORY;
62809         }
62810     } else {
62811         pHeap = NULL;
62812     }
62813
62814     result = ma_resource_manager_job_queue_init_preallocated(pConfig, pHeap, pQueue);
62815     if (result != MA_SUCCESS) {
62816         ma_free(pHeap, pAllocationCallbacks);
62817         return result;
62818     }
62819
62820     pQueue->_ownsHeap = MA_TRUE;
62821     return MA_SUCCESS;
62822 }
62823
62824 MA_API void ma_resource_manager_job_queue_uninit(ma_resource_manager_job_queue* pQueue, const ma_allocation_callbacks* pAllocationCallbacks)
62825 {
62826     if (pQueue == NULL) {
62827         return;
62828     }
62829
62830     /* All we need to do is uninitialize the semaphore. */
62831     if ((pQueue->flags & MA_RESOURCE_MANAGER_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) {
62832         #ifndef MA_NO_THREADING
62833         {
62834             ma_semaphore_uninit(&pQueue->sem);
62835         }
62836         #else
62837         {
62838             MA_ASSERT(MA_FALSE);    /* Should never get here. Should have been checked at initialization time. */
62839         }
62840         #endif
62841     }
62842
62843     ma_slot_allocator_uninit(&pQueue->allocator, pAllocationCallbacks);
62844
62845     if (pQueue->_ownsHeap) {
62846         ma_free(pQueue->_pHeap, pAllocationCallbacks);
62847     }
62848 }
62849
62850 static ma_bool32 ma_resource_manager_job_queue_cas(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired)
62851 {
62852     /* The new counter is taken from the expected value. */
62853     return c89atomic_compare_and_swap_64(dst, expected, ma_resource_manager_job_set_refcount(desired, ma_resource_manager_job_extract_refcount(expected) + 1)) == expected;
62854 }
62855
62856 MA_API ma_result ma_resource_manager_job_queue_post(ma_resource_manager_job_queue* pQueue, const ma_resource_manager_job* pJob)
62857 {
62858     /*
62859     Lock free queue implementation based on the paper by Michael and Scott: Nonblocking Algorithms and Preemption-Safe Locking on Multiprogrammed Shared Memory Multiprocessors
62860     */
62861     ma_result result;
62862     ma_uint64 slot;
62863     ma_uint64 tail;
62864     ma_uint64 next;
62865
62866     if (pQueue == NULL || pJob == NULL) {
62867         return MA_INVALID_ARGS;
62868     }
62869
62870     /* We need a new slot. */
62871     result = ma_slot_allocator_alloc(&pQueue->allocator, &slot);
62872     if (result != MA_SUCCESS) {
62873         return result;  /* Probably ran out of slots. If so, MA_OUT_OF_MEMORY will be returned. */
62874     }
62875
62876     /* At this point we should have a slot to place the job. */
62877     MA_ASSERT(ma_resource_manager_job_extract_slot(slot) < pQueue->capacity);
62878
62879     /* We need to put the job into memory before we do anything. */
62880     pQueue->pJobs[ma_resource_manager_job_extract_slot(slot)]                  = *pJob;
62881     pQueue->pJobs[ma_resource_manager_job_extract_slot(slot)].toc.allocation   = slot;                    /* This will overwrite the job code. */
62882     pQueue->pJobs[ma_resource_manager_job_extract_slot(slot)].toc.breakup.code = pJob->toc.breakup.code;  /* The job code needs to be applied again because the line above overwrote it. */
62883     pQueue->pJobs[ma_resource_manager_job_extract_slot(slot)].next             = MA_RESOURCE_MANAGER_JOB_ID_NONE;          /* Reset for safety. */
62884
62885     #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
62886     ma_spinlock_lock(&pQueue->lock);
62887     #endif
62888     {
62889         /* The job is stored in memory so now we need to add it to our linked list. We only ever add items to the end of the list. */
62890         for (;;) {
62891             tail = c89atomic_load_64(&pQueue->tail);
62892             next = c89atomic_load_64(&pQueue->pJobs[ma_resource_manager_job_extract_slot(tail)].next);
62893
62894             if (ma_resource_manager_job_toc_to_allocation(tail) == ma_resource_manager_job_toc_to_allocation(c89atomic_load_64(&pQueue->tail))) {
62895                 if (ma_resource_manager_job_extract_slot(next) == 0xFFFF) {
62896                     if (ma_resource_manager_job_queue_cas(&pQueue->pJobs[ma_resource_manager_job_extract_slot(tail)].next, next, slot)) {
62897                         break;
62898                     }
62899                 } else {
62900                     ma_resource_manager_job_queue_cas(&pQueue->tail, tail, ma_resource_manager_job_extract_slot(next));
62901                 }
62902             }
62903         }
62904         ma_resource_manager_job_queue_cas(&pQueue->tail, tail, slot);
62905     }
62906     #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
62907     ma_spinlock_unlock(&pQueue->lock);
62908     #endif
62909
62910
62911     /* Signal the semaphore as the last step if we're using synchronous mode. */
62912     if ((pQueue->flags & MA_RESOURCE_MANAGER_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) {
62913         #ifndef MA_NO_THREADING
62914         {
62915             ma_semaphore_release(&pQueue->sem);
62916         }
62917         #else
62918         {
62919             MA_ASSERT(MA_FALSE);    /* Should never get here. Should have been checked at initialization time. */
62920         }
62921         #endif
62922     }
62923
62924     return MA_SUCCESS;
62925 }
62926
62927 MA_API ma_result ma_resource_manager_job_queue_next(ma_resource_manager_job_queue* pQueue, ma_resource_manager_job* pJob)
62928 {
62929     ma_uint64 head;
62930     ma_uint64 tail;
62931     ma_uint64 next;
62932
62933     if (pQueue == NULL || pJob == NULL) {
62934         return MA_INVALID_ARGS;
62935     }
62936
62937     /* If we're running in synchronous mode we'll need to wait on a semaphore. */
62938     if ((pQueue->flags & MA_RESOURCE_MANAGER_JOB_QUEUE_FLAG_NON_BLOCKING) == 0) {
62939         #ifndef MA_NO_THREADING
62940         {
62941             ma_semaphore_wait(&pQueue->sem);
62942         }
62943         #else
62944         {
62945             MA_ASSERT(MA_FALSE);    /* Should never get here. Should have been checked at initialization time. */
62946         }
62947         #endif
62948     }
62949
62950     #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
62951     ma_spinlock_lock(&pQueue->lock);
62952     #endif
62953     {
62954         /*
62955         BUG: In lock-free mode, multiple threads can be in this section of code. The "head" variable in the loop below
62956         is stored. One thread can fall through to the freeing of this item while another is still using "head" for the
62957         retrieval of the "next" variable.
62958
62959         The slot allocator might need to make use of some reference counting to ensure it's only truely freed when
62960         there are no more references to the item. This must be fixed before removing these locks.
62961         */
62962
62963         /* Now we need to remove the root item from the list. */
62964         for (;;) {
62965             head = c89atomic_load_64(&pQueue->head);
62966             tail = c89atomic_load_64(&pQueue->tail);
62967             next = c89atomic_load_64(&pQueue->pJobs[ma_resource_manager_job_extract_slot(head)].next);
62968
62969             if (ma_resource_manager_job_toc_to_allocation(head) == ma_resource_manager_job_toc_to_allocation(c89atomic_load_64(&pQueue->head))) {
62970                 if (ma_resource_manager_job_extract_slot(head) == ma_resource_manager_job_extract_slot(tail)) {
62971                     if (ma_resource_manager_job_extract_slot(next) == 0xFFFF) {
62972                         #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
62973                         ma_spinlock_unlock(&pQueue->lock);
62974                         #endif
62975                         return MA_NO_DATA_AVAILABLE;
62976                     }
62977                     ma_resource_manager_job_queue_cas(&pQueue->tail, tail, ma_resource_manager_job_extract_slot(next));
62978                 } else {
62979                     *pJob = pQueue->pJobs[ma_resource_manager_job_extract_slot(next)];
62980                     if (ma_resource_manager_job_queue_cas(&pQueue->head, head, ma_resource_manager_job_extract_slot(next))) {
62981                         break;
62982                     }
62983                 }
62984             }
62985         }
62986     }
62987     #ifndef MA_USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE
62988     ma_spinlock_unlock(&pQueue->lock);
62989     #endif
62990
62991     ma_slot_allocator_free(&pQueue->allocator, head);
62992
62993     /*
62994     If it's a quit job make sure it's put back on the queue to ensure other threads have an opportunity to detect it and terminate naturally. We
62995     could instead just leave it on the queue, but that would involve fiddling with the lock-free code above and I want to keep that as simple as
62996     possible.
62997     */
62998     if (pJob->toc.breakup.code == MA_RESOURCE_MANAGER_JOB_QUIT) {
62999         ma_resource_manager_job_queue_post(pQueue, pJob);
63000         return MA_CANCELLED;    /* Return a cancelled status just in case the thread is checking return codes and not properly checking for a quit job. */
63001     }
63002
63003     return MA_SUCCESS;
63004 }
63005
63006 MA_API ma_result ma_resource_manager_job_queue_free(ma_resource_manager_job_queue* pQueue, ma_resource_manager_job* pJob)
63007 {
63008     if (pQueue == NULL || pJob == NULL) {
63009         return MA_INVALID_ARGS;
63010     }
63011
63012     return ma_slot_allocator_free(&pQueue->allocator, ma_resource_manager_job_toc_to_allocation(pJob->toc.allocation));
63013 }
63014
63015
63016
63017
63018
63019 #ifndef MA_DEFAULT_HASH_SEED
63020 #define MA_DEFAULT_HASH_SEED    42
63021 #endif
63022
63023 /* MurmurHash3. Based on code from https://github.com/PeterScott/murmur3/blob/master/murmur3.c (public domain). */
63024 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
63025     #pragma GCC diagnostic push
63026     #if __GNUC__ >= 7
63027     #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
63028     #endif
63029 #endif
63030
63031 static MA_INLINE ma_uint32 ma_rotl32(ma_uint32 x, ma_int8 r)
63032 {
63033     return (x << r) | (x >> (32 - r));
63034 }
63035
63036 static MA_INLINE ma_uint32 ma_hash_getblock(const ma_uint32* blocks, int i)
63037 {
63038     if (ma_is_little_endian()) {
63039         return blocks[i];
63040     } else {
63041         return ma_swap_endian_uint32(blocks[i]);
63042     }
63043 }
63044
63045 static MA_INLINE ma_uint32 ma_hash_fmix32(ma_uint32 h)
63046 {
63047     h ^= h >> 16;
63048     h *= 0x85ebca6b;
63049     h ^= h >> 13;
63050     h *= 0xc2b2ae35;
63051     h ^= h >> 16;
63052
63053     return h;
63054 }
63055
63056 static ma_uint32 ma_hash_32(const void* key, int len, ma_uint32 seed)
63057 {
63058     const ma_uint8* data = (const ma_uint8*)key;
63059     const ma_uint32* blocks;
63060     const ma_uint8* tail;
63061     const int nblocks = len / 4;
63062     ma_uint32 h1 = seed;
63063     ma_uint32 c1 = 0xcc9e2d51;
63064     ma_uint32 c2 = 0x1b873593;
63065     ma_uint32 k1;
63066     int i;
63067
63068     blocks = (const ma_uint32 *)(data + nblocks*4);
63069
63070     for(i = -nblocks; i; i++) {
63071         k1 = ma_hash_getblock(blocks,i);
63072
63073         k1 *= c1;
63074         k1 = ma_rotl32(k1, 15);
63075         k1 *= c2;
63076
63077         h1 ^= k1;
63078         h1 = ma_rotl32(h1, 13);
63079         h1 = h1*5 + 0xe6546b64;
63080     }
63081
63082
63083     tail = (const ma_uint8*)(data + nblocks*4);
63084
63085     k1 = 0;
63086     switch(len & 3) {
63087         case 3: k1 ^= tail[2] << 16;
63088         case 2: k1 ^= tail[1] << 8;
63089         case 1: k1 ^= tail[0];
63090                 k1 *= c1; k1 = ma_rotl32(k1, 15); k1 *= c2; h1 ^= k1;
63091     };
63092
63093
63094     h1 ^= len;
63095     h1  = ma_hash_fmix32(h1);
63096
63097     return h1;
63098 }
63099
63100 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
63101     #pragma GCC diagnostic push
63102 #endif
63103 /* End MurmurHash3 */
63104
63105 static ma_uint32 ma_hash_string_32(const char* str)
63106 {
63107     return ma_hash_32(str, (int)strlen(str), MA_DEFAULT_HASH_SEED);
63108 }
63109
63110 static ma_uint32 ma_hash_string_w_32(const wchar_t* str)
63111 {
63112     return ma_hash_32(str, (int)wcslen(str) * sizeof(*str), MA_DEFAULT_HASH_SEED);
63113 }
63114
63115
63116
63117
63118 /*
63119 Basic BST Functions
63120 */
63121 static ma_result ma_resource_manager_data_buffer_node_search(ma_resource_manager* pResourceManager, ma_uint32 hashedName32, ma_resource_manager_data_buffer_node** ppDataBufferNode)
63122 {
63123     ma_resource_manager_data_buffer_node* pCurrentNode;
63124
63125     MA_ASSERT(pResourceManager != NULL);
63126     MA_ASSERT(ppDataBufferNode != NULL);
63127
63128     pCurrentNode = pResourceManager->pRootDataBufferNode;
63129     while (pCurrentNode != NULL) {
63130         if (hashedName32 == pCurrentNode->hashedName32) {
63131             break;  /* Found. */
63132         } else if (hashedName32 < pCurrentNode->hashedName32) {
63133             pCurrentNode = pCurrentNode->pChildLo;
63134         } else {
63135             pCurrentNode = pCurrentNode->pChildHi;
63136         }
63137     }
63138
63139     *ppDataBufferNode = pCurrentNode;
63140
63141     if (pCurrentNode == NULL) {
63142         return MA_DOES_NOT_EXIST;
63143     } else {
63144         return MA_SUCCESS;
63145     }
63146 }
63147
63148 static ma_result ma_resource_manager_data_buffer_node_insert_point(ma_resource_manager* pResourceManager, ma_uint32 hashedName32, ma_resource_manager_data_buffer_node** ppInsertPoint)
63149 {
63150     ma_result result = MA_SUCCESS;
63151     ma_resource_manager_data_buffer_node* pCurrentNode;
63152
63153     MA_ASSERT(pResourceManager != NULL);
63154     MA_ASSERT(ppInsertPoint    != NULL);
63155
63156     *ppInsertPoint = NULL;
63157
63158     if (pResourceManager->pRootDataBufferNode == NULL) {
63159         return MA_SUCCESS;  /* No items. */
63160     }
63161
63162     /* We need to find the node that will become the parent of the new node. If a node is found that already has the same hashed name we need to return MA_ALREADY_EXISTS. */
63163     pCurrentNode = pResourceManager->pRootDataBufferNode;
63164     while (pCurrentNode != NULL) {
63165         if (hashedName32 == pCurrentNode->hashedName32) {
63166             result = MA_ALREADY_EXISTS;
63167             break;
63168         } else {
63169             if (hashedName32 < pCurrentNode->hashedName32) {
63170                 if (pCurrentNode->pChildLo == NULL) {
63171                     result = MA_SUCCESS;
63172                     break;
63173                 } else {
63174                     pCurrentNode = pCurrentNode->pChildLo;
63175                 }
63176             } else {
63177                 if (pCurrentNode->pChildHi == NULL) {
63178                     result = MA_SUCCESS;
63179                     break;
63180                 } else {
63181                     pCurrentNode = pCurrentNode->pChildHi;
63182                 }
63183             }
63184         }
63185     }
63186
63187     *ppInsertPoint = pCurrentNode;
63188     return result;
63189 }
63190
63191 static ma_result ma_resource_manager_data_buffer_node_insert_at(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_resource_manager_data_buffer_node* pInsertPoint)
63192 {
63193     MA_ASSERT(pResourceManager != NULL);
63194     MA_ASSERT(pDataBufferNode  != NULL);
63195
63196     /* The key must have been set before calling this function. */
63197     MA_ASSERT(pDataBufferNode->hashedName32 != 0);
63198
63199     if (pInsertPoint == NULL) {
63200         /* It's the first node. */
63201         pResourceManager->pRootDataBufferNode = pDataBufferNode;
63202     } else {
63203         /* It's not the first node. It needs to be inserted. */
63204         if (pDataBufferNode->hashedName32 < pInsertPoint->hashedName32) {
63205             MA_ASSERT(pInsertPoint->pChildLo == NULL);
63206             pInsertPoint->pChildLo = pDataBufferNode;
63207         } else {
63208             MA_ASSERT(pInsertPoint->pChildHi == NULL);
63209             pInsertPoint->pChildHi = pDataBufferNode;
63210         }
63211     }
63212
63213     pDataBufferNode->pParent = pInsertPoint;
63214
63215     return MA_SUCCESS;
63216 }
63217
63218 #if 0   /* Unused for now. */
63219 static ma_result ma_resource_manager_data_buffer_node_insert(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode)
63220 {
63221     ma_result result;
63222     ma_resource_manager_data_buffer_node* pInsertPoint;
63223
63224     MA_ASSERT(pResourceManager != NULL);
63225     MA_ASSERT(pDataBufferNode  != NULL);
63226
63227     result = ma_resource_manager_data_buffer_node_insert_point(pResourceManager, pDataBufferNode->hashedName32, &pInsertPoint);
63228     if (result != MA_SUCCESS) {
63229         return MA_INVALID_ARGS;
63230     }
63231
63232     return ma_resource_manager_data_buffer_node_insert_at(pResourceManager, pDataBufferNode, pInsertPoint);
63233 }
63234 #endif
63235
63236 static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_min(ma_resource_manager_data_buffer_node* pDataBufferNode)
63237 {
63238     ma_resource_manager_data_buffer_node* pCurrentNode;
63239
63240     MA_ASSERT(pDataBufferNode != NULL);
63241
63242     pCurrentNode = pDataBufferNode;
63243     while (pCurrentNode->pChildLo != NULL) {
63244         pCurrentNode = pCurrentNode->pChildLo;
63245     }
63246
63247     return pCurrentNode;
63248 }
63249
63250 static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_max(ma_resource_manager_data_buffer_node* pDataBufferNode)
63251 {
63252     ma_resource_manager_data_buffer_node* pCurrentNode;
63253
63254     MA_ASSERT(pDataBufferNode != NULL);
63255
63256     pCurrentNode = pDataBufferNode;
63257     while (pCurrentNode->pChildHi != NULL) {
63258         pCurrentNode = pCurrentNode->pChildHi;
63259     }
63260
63261     return pCurrentNode;
63262 }
63263
63264 static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_inorder_successor(ma_resource_manager_data_buffer_node* pDataBufferNode)
63265 {
63266     MA_ASSERT(pDataBufferNode           != NULL);
63267     MA_ASSERT(pDataBufferNode->pChildHi != NULL);
63268
63269     return ma_resource_manager_data_buffer_node_find_min(pDataBufferNode->pChildHi);
63270 }
63271
63272 static MA_INLINE ma_resource_manager_data_buffer_node* ma_resource_manager_data_buffer_node_find_inorder_predecessor(ma_resource_manager_data_buffer_node* pDataBufferNode)
63273 {
63274     MA_ASSERT(pDataBufferNode           != NULL);
63275     MA_ASSERT(pDataBufferNode->pChildLo != NULL);
63276
63277     return ma_resource_manager_data_buffer_node_find_max(pDataBufferNode->pChildLo);
63278 }
63279
63280 static ma_result ma_resource_manager_data_buffer_node_remove(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode)
63281 {
63282     MA_ASSERT(pResourceManager != NULL);
63283     MA_ASSERT(pDataBufferNode  != NULL);
63284
63285     if (pDataBufferNode->pChildLo == NULL) {
63286         if (pDataBufferNode->pChildHi == NULL) {
63287             /* Simple case - deleting a buffer with no children. */
63288             if (pDataBufferNode->pParent == NULL) {
63289                 MA_ASSERT(pResourceManager->pRootDataBufferNode == pDataBufferNode);    /* There is only a single buffer in the tree which should be equal to the root node. */
63290                 pResourceManager->pRootDataBufferNode = NULL;
63291             } else {
63292                 if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) {
63293                     pDataBufferNode->pParent->pChildLo = NULL;
63294                 } else {
63295                     pDataBufferNode->pParent->pChildHi = NULL;
63296                 }
63297             }
63298         } else {
63299             /* Node has one child - pChildHi != NULL. */
63300             pDataBufferNode->pChildHi->pParent = pDataBufferNode->pParent;
63301
63302             if (pDataBufferNode->pParent == NULL) {
63303                 MA_ASSERT(pResourceManager->pRootDataBufferNode == pDataBufferNode);
63304                 pResourceManager->pRootDataBufferNode = pDataBufferNode->pChildHi;
63305             } else {
63306                 if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) {
63307                     pDataBufferNode->pParent->pChildLo = pDataBufferNode->pChildHi;
63308                 } else {
63309                     pDataBufferNode->pParent->pChildHi = pDataBufferNode->pChildHi;
63310                 }
63311             }
63312         }
63313     } else {
63314         if (pDataBufferNode->pChildHi == NULL) {
63315             /* Node has one child - pChildLo != NULL. */
63316             pDataBufferNode->pChildLo->pParent = pDataBufferNode->pParent;
63317
63318             if (pDataBufferNode->pParent == NULL) {
63319                 MA_ASSERT(pResourceManager->pRootDataBufferNode == pDataBufferNode);
63320                 pResourceManager->pRootDataBufferNode = pDataBufferNode->pChildLo;
63321             } else {
63322                 if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) {
63323                     pDataBufferNode->pParent->pChildLo = pDataBufferNode->pChildLo;
63324                 } else {
63325                     pDataBufferNode->pParent->pChildHi = pDataBufferNode->pChildLo;
63326                 }
63327             }
63328         } else {
63329             /* Complex case - deleting a node with two children. */
63330             ma_resource_manager_data_buffer_node* pReplacementDataBufferNode;
63331
63332             /* For now we are just going to use the in-order successor as the replacement, but we may want to try to keep this balanced by switching between the two. */
63333             pReplacementDataBufferNode = ma_resource_manager_data_buffer_node_find_inorder_successor(pDataBufferNode);
63334             MA_ASSERT(pReplacementDataBufferNode != NULL);
63335
63336             /*
63337             Now that we have our replacement node we can make the change. The simple way to do this would be to just exchange the values, and then remove the replacement
63338             node, however we track specific nodes via pointers which means we can't just swap out the values. We need to instead just change the pointers around. The
63339             replacement node should have at most 1 child. Therefore, we can detach it in terms of our simpler cases above. What we're essentially doing is detaching the
63340             replacement node and reinserting it into the same position as the deleted node.
63341             */
63342             MA_ASSERT(pReplacementDataBufferNode->pParent  != NULL);  /* The replacement node should never be the root which means it should always have a parent. */
63343             MA_ASSERT(pReplacementDataBufferNode->pChildLo == NULL);  /* Because we used in-order successor. This would be pChildHi == NULL if we used in-order predecessor. */
63344
63345             if (pReplacementDataBufferNode->pChildHi == NULL) {
63346                 if (pReplacementDataBufferNode->pParent->pChildLo == pReplacementDataBufferNode) {
63347                     pReplacementDataBufferNode->pParent->pChildLo = NULL;
63348                 } else {
63349                     pReplacementDataBufferNode->pParent->pChildHi = NULL;
63350                 }
63351             } else {
63352                 pReplacementDataBufferNode->pChildHi->pParent = pReplacementDataBufferNode->pParent;
63353                 if (pReplacementDataBufferNode->pParent->pChildLo == pReplacementDataBufferNode) {
63354                     pReplacementDataBufferNode->pParent->pChildLo = pReplacementDataBufferNode->pChildHi;
63355                 } else {
63356                     pReplacementDataBufferNode->pParent->pChildHi = pReplacementDataBufferNode->pChildHi;
63357                 }
63358             }
63359
63360
63361             /* The replacement node has essentially been detached from the binary tree, so now we need to replace the old data buffer with it. The first thing to update is the parent */
63362             if (pDataBufferNode->pParent != NULL) {
63363                 if (pDataBufferNode->pParent->pChildLo == pDataBufferNode) {
63364                     pDataBufferNode->pParent->pChildLo = pReplacementDataBufferNode;
63365                 } else {
63366                     pDataBufferNode->pParent->pChildHi = pReplacementDataBufferNode;
63367                 }
63368             }
63369
63370             /* Now need to update the replacement node's pointers. */
63371             pReplacementDataBufferNode->pParent  = pDataBufferNode->pParent;
63372             pReplacementDataBufferNode->pChildLo = pDataBufferNode->pChildLo;
63373             pReplacementDataBufferNode->pChildHi = pDataBufferNode->pChildHi;
63374
63375             /* Now the children of the replacement node need to have their parent pointers updated. */
63376             if (pReplacementDataBufferNode->pChildLo != NULL) {
63377                 pReplacementDataBufferNode->pChildLo->pParent = pReplacementDataBufferNode;
63378             }
63379             if (pReplacementDataBufferNode->pChildHi != NULL) {
63380                 pReplacementDataBufferNode->pChildHi->pParent = pReplacementDataBufferNode;
63381             }
63382
63383             /* Now the root node needs to be updated. */
63384             if (pResourceManager->pRootDataBufferNode == pDataBufferNode) {
63385                 pResourceManager->pRootDataBufferNode = pReplacementDataBufferNode;
63386             }
63387         }
63388     }
63389
63390     return MA_SUCCESS;
63391 }
63392
63393 #if 0   /* Unused for now. */
63394 static ma_result ma_resource_manager_data_buffer_node_remove_by_key(ma_resource_manager* pResourceManager, ma_uint32 hashedName32)
63395 {
63396     ma_result result;
63397     ma_resource_manager_data_buffer_node* pDataBufferNode;
63398
63399     result = ma_resource_manager_data_buffer_search(pResourceManager, hashedName32, &pDataBufferNode);
63400     if (result != MA_SUCCESS) {
63401         return result;  /* Could not find the data buffer. */
63402     }
63403
63404     return ma_resource_manager_data_buffer_remove(pResourceManager, pDataBufferNode);
63405 }
63406 #endif
63407
63408 static ma_resource_manager_data_supply_type ma_resource_manager_data_buffer_node_get_data_supply_type(ma_resource_manager_data_buffer_node* pDataBufferNode)
63409 {
63410     return (ma_resource_manager_data_supply_type)c89atomic_load_i32(&pDataBufferNode->data.type);
63411 }
63412
63413 static void ma_resource_manager_data_buffer_node_set_data_supply_type(ma_resource_manager_data_buffer_node* pDataBufferNode, ma_resource_manager_data_supply_type supplyType)
63414 {
63415     c89atomic_exchange_i32(&pDataBufferNode->data.type, supplyType);
63416 }
63417
63418 static ma_result ma_resource_manager_data_buffer_node_increment_ref(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_uint32* pNewRefCount)
63419 {
63420     ma_uint32 refCount;
63421
63422     MA_ASSERT(pResourceManager != NULL);
63423     MA_ASSERT(pDataBufferNode  != NULL);
63424
63425     (void)pResourceManager;
63426
63427     refCount = c89atomic_fetch_add_32(&pDataBufferNode->refCount, 1) + 1;
63428
63429     if (pNewRefCount != NULL) {
63430         *pNewRefCount = refCount;
63431     }
63432
63433     return MA_SUCCESS;
63434 }
63435
63436 static ma_result ma_resource_manager_data_buffer_node_decrement_ref(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_uint32* pNewRefCount)
63437 {
63438     ma_uint32 refCount;
63439
63440     MA_ASSERT(pResourceManager != NULL);
63441     MA_ASSERT(pDataBufferNode  != NULL);
63442
63443     (void)pResourceManager;
63444
63445     refCount = c89atomic_fetch_sub_32(&pDataBufferNode->refCount, 1) - 1;
63446
63447     if (pNewRefCount != NULL) {
63448         *pNewRefCount = refCount;
63449     }
63450
63451     return MA_SUCCESS;
63452 }
63453
63454 static void ma_resource_manager_data_buffer_node_free(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode)
63455 {
63456     MA_ASSERT(pResourceManager != NULL);
63457     MA_ASSERT(pDataBufferNode  != NULL);
63458
63459     if (pDataBufferNode->isDataOwnedByResourceManager) {
63460         if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode) == ma_resource_manager_data_supply_type_encoded) {
63461             ma_free((void*)pDataBufferNode->data.backend.encoded.pData, &pResourceManager->config.allocationCallbacks);
63462             pDataBufferNode->data.backend.encoded.pData       = NULL;
63463             pDataBufferNode->data.backend.encoded.sizeInBytes = 0;
63464         } else if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode) == ma_resource_manager_data_supply_type_decoded) {
63465             ma_free((void*)pDataBufferNode->data.backend.decoded.pData, &pResourceManager->config.allocationCallbacks);
63466             pDataBufferNode->data.backend.decoded.pData           = NULL;
63467             pDataBufferNode->data.backend.decoded.totalFrameCount = 0;
63468         } else if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode) == ma_resource_manager_data_supply_type_decoded_paged) {
63469             ma_paged_audio_buffer_data_uninit(&pDataBufferNode->data.backend.decodedPaged.data, &pResourceManager->config.allocationCallbacks);
63470         } else {
63471             /* Should never hit this if the node was successfully initialized. */
63472             MA_ASSERT(pDataBufferNode->result != MA_SUCCESS);
63473         }
63474     }
63475
63476     /* The data buffer itself needs to be freed. */
63477     ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks);
63478 }
63479
63480 static ma_result ma_resource_manager_data_buffer_node_result(const ma_resource_manager_data_buffer_node* pDataBufferNode)
63481 {
63482     MA_ASSERT(pDataBufferNode != NULL);
63483
63484     return (ma_result)c89atomic_load_i32((ma_result*)&pDataBufferNode->result);    /* Need a naughty const-cast here. */
63485 }
63486
63487
63488 static ma_bool32 ma_resource_manager_is_threading_enabled(const ma_resource_manager* pResourceManager)
63489 {
63490     MA_ASSERT(pResourceManager != NULL);
63491
63492     return (pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) == 0;
63493 }
63494
63495
63496 typedef struct
63497 {
63498     union
63499     {
63500         ma_async_notification_event e;
63501         ma_async_notification_poll p;
63502     } backend;  /* Must be the first member. */
63503     ma_resource_manager* pResourceManager;
63504 } ma_resource_manager_inline_notification;
63505
63506 static ma_result ma_resource_manager_inline_notification_init(ma_resource_manager* pResourceManager, ma_resource_manager_inline_notification* pNotification)
63507 {
63508     MA_ASSERT(pResourceManager != NULL);
63509     MA_ASSERT(pNotification    != NULL);
63510
63511     pNotification->pResourceManager = pResourceManager;
63512
63513     if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
63514         return ma_async_notification_event_init(&pNotification->backend.e);
63515     } else {
63516         return ma_async_notification_poll_init(&pNotification->backend.p);
63517     }
63518 }
63519
63520 static void ma_resource_manager_inline_notification_uninit(ma_resource_manager_inline_notification* pNotification)
63521 {
63522     MA_ASSERT(pNotification != NULL);
63523
63524     if (ma_resource_manager_is_threading_enabled(pNotification->pResourceManager)) {
63525         ma_async_notification_event_uninit(&pNotification->backend.e);
63526     } else {
63527         /* No need to uninitialize a polling notification. */
63528     }
63529 }
63530
63531 static void ma_resource_manager_inline_notification_wait(ma_resource_manager_inline_notification* pNotification)
63532 {
63533     MA_ASSERT(pNotification != NULL);
63534
63535     if (ma_resource_manager_is_threading_enabled(pNotification->pResourceManager)) {
63536         ma_async_notification_event_wait(&pNotification->backend.e);
63537     } else {
63538         while (ma_async_notification_poll_is_signalled(&pNotification->backend.p) == MA_FALSE) {
63539             ma_result result = ma_resource_manager_process_next_job(pNotification->pResourceManager);
63540             if (result == MA_NO_DATA_AVAILABLE || result == MA_CANCELLED) {
63541                 break;
63542             }
63543         }
63544     }
63545 }
63546
63547 static void ma_resource_manager_inline_notification_wait_and_uninit(ma_resource_manager_inline_notification* pNotification)
63548 {
63549     ma_resource_manager_inline_notification_wait(pNotification);
63550     ma_resource_manager_inline_notification_uninit(pNotification);
63551 }
63552
63553
63554 static void ma_resource_manager_data_buffer_bst_lock(ma_resource_manager* pResourceManager)
63555 {
63556     MA_ASSERT(pResourceManager != NULL);
63557
63558     if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
63559         #ifndef MA_NO_THREADING
63560         {
63561             ma_mutex_lock(&pResourceManager->dataBufferBSTLock);
63562         }
63563         #else
63564         {
63565             MA_ASSERT(MA_FALSE);    /* Should never hit this. */
63566         }
63567         #endif
63568     } else {
63569         /* Threading not enabled. Do nothing. */
63570     }
63571 }
63572
63573 static void ma_resource_manager_data_buffer_bst_unlock(ma_resource_manager* pResourceManager)
63574 {
63575     MA_ASSERT(pResourceManager != NULL);
63576
63577     if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
63578         #ifndef MA_NO_THREADING
63579         {
63580             ma_mutex_unlock(&pResourceManager->dataBufferBSTLock);
63581         }
63582         #else
63583         {
63584             MA_ASSERT(MA_FALSE);    /* Should never hit this. */
63585         }
63586         #endif
63587     } else {
63588         /* Threading not enabled. Do nothing. */
63589     }
63590 }
63591
63592 #ifndef MA_NO_THREADING
63593 static ma_thread_result MA_THREADCALL ma_resource_manager_job_thread(void* pUserData)
63594 {
63595     ma_resource_manager* pResourceManager = (ma_resource_manager*)pUserData;
63596     MA_ASSERT(pResourceManager != NULL);
63597
63598     for (;;) {
63599         ma_result result;
63600         ma_resource_manager_job job;
63601
63602         result = ma_resource_manager_next_job(pResourceManager, &job);
63603         if (result != MA_SUCCESS) {
63604             break;
63605         }
63606
63607         /* Terminate if we got a quit message. */
63608         if (job.toc.breakup.code == MA_RESOURCE_MANAGER_JOB_QUIT) {
63609             break;
63610         }
63611
63612         ma_resource_manager_process_job(pResourceManager, &job);
63613     }
63614
63615     return (ma_thread_result)0;
63616 }
63617 #endif
63618
63619 MA_API ma_resource_manager_config ma_resource_manager_config_init(void)
63620 {
63621     ma_resource_manager_config config;
63622
63623     MA_ZERO_OBJECT(&config);
63624     config.decodedFormat     = ma_format_unknown;
63625     config.decodedChannels   = 0;
63626     config.decodedSampleRate = 0;
63627     config.jobThreadCount    = 1;   /* A single miniaudio-managed job thread by default. */
63628     config.jobQueueCapacity  = MA_RESOURCE_MANAGER_JOB_QUEUE_CAPACITY;
63629
63630     /* Flags. */
63631     config.flags = 0;
63632     #ifdef MA_NO_THREADING
63633     {
63634         /* Threading is disabled at compile time so disable threading at runtime as well by default. */
63635         config.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING;
63636         config.jobThreadCount = 0;
63637     }
63638     #endif
63639
63640     return config;
63641 }
63642
63643
63644 MA_API ma_result ma_resource_manager_init(const ma_resource_manager_config* pConfig, ma_resource_manager* pResourceManager)
63645 {
63646     ma_result result;
63647     ma_resource_manager_job_queue_config jobQueueConfig;
63648
63649     if (pResourceManager == NULL) {
63650         return MA_INVALID_ARGS;
63651     }
63652
63653     MA_ZERO_OBJECT(pResourceManager);
63654
63655     if (pConfig == NULL) {
63656         return MA_INVALID_ARGS;
63657     }
63658
63659     #ifndef MA_NO_THREADING
63660     {
63661         if (pConfig->jobThreadCount > ma_countof(pResourceManager->jobThreads)) {
63662             return MA_INVALID_ARGS; /* Requesting too many job threads. */
63663         }
63664     }
63665     #endif
63666
63667     pResourceManager->config = *pConfig;
63668     ma_allocation_callbacks_init_copy(&pResourceManager->config.allocationCallbacks, &pConfig->allocationCallbacks);
63669
63670     /* Get the log set up early so we can start using it as soon as possible. */
63671     if (pResourceManager->config.pLog == NULL) {
63672         result = ma_log_init(&pResourceManager->config.allocationCallbacks, &pResourceManager->log);
63673         if (result == MA_SUCCESS) {
63674             pResourceManager->config.pLog = &pResourceManager->log;
63675         } else {
63676             pResourceManager->config.pLog = NULL;   /* Logging is unavailable. */
63677         }
63678     }
63679
63680     if (pResourceManager->config.pVFS == NULL) {
63681         result = ma_default_vfs_init(&pResourceManager->defaultVFS, &pResourceManager->config.allocationCallbacks);
63682         if (result != MA_SUCCESS) {
63683             return result;  /* Failed to initialize the default file system. */
63684         }
63685
63686         pResourceManager->config.pVFS = &pResourceManager->defaultVFS;
63687     }
63688
63689     /* If threading has been disabled at compile time, enfore it at run time as well. */
63690     #ifdef MA_NO_THREADING
63691     {
63692         pResourceManager->config.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING;
63693     }
63694     #endif
63695
63696     /* We need to force MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING if MA_RESOURCE_MANAGER_FLAG_NO_THREADING is set. */
63697     if ((pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) != 0) {
63698         pResourceManager->config.flags |= MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING;
63699
63700         /* We cannot allow job threads when MA_RESOURCE_MANAGER_FLAG_NO_THREADING has been set. This is an invalid use case. */
63701         if (pResourceManager->config.jobThreadCount > 0) {
63702             return MA_INVALID_ARGS;
63703         }
63704     }
63705
63706     /* Job queue. */
63707     jobQueueConfig.capacity = pResourceManager->config.jobQueueCapacity;
63708     jobQueueConfig.flags    = 0;
63709     if ((pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING) != 0) {
63710         if (pResourceManager->config.jobThreadCount > 0) {
63711             return MA_INVALID_ARGS; /* Non-blocking mode is only valid for self-managed job threads. */
63712         }
63713
63714         jobQueueConfig.flags |= MA_RESOURCE_MANAGER_JOB_QUEUE_FLAG_NON_BLOCKING;
63715     }
63716
63717     result = ma_resource_manager_job_queue_init(&jobQueueConfig, &pResourceManager->config.allocationCallbacks, &pResourceManager->jobQueue);
63718     if (result != MA_SUCCESS) {
63719         return result;
63720     }
63721
63722
63723     /* Custom decoding backends. */
63724     if (pConfig->ppCustomDecodingBackendVTables != NULL && pConfig->customDecodingBackendCount > 0) {
63725         size_t sizeInBytes = sizeof(*pResourceManager->config.ppCustomDecodingBackendVTables) * pConfig->customDecodingBackendCount;
63726
63727         pResourceManager->config.ppCustomDecodingBackendVTables = (ma_decoding_backend_vtable**)ma_malloc(sizeInBytes, &pResourceManager->config.allocationCallbacks);
63728         if (pResourceManager->config.ppCustomDecodingBackendVTables == NULL) {
63729             ma_resource_manager_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks);
63730             return MA_OUT_OF_MEMORY;
63731         }
63732
63733         MA_COPY_MEMORY(pResourceManager->config.ppCustomDecodingBackendVTables, pConfig->ppCustomDecodingBackendVTables, sizeInBytes);
63734
63735         pResourceManager->config.customDecodingBackendCount     = pConfig->customDecodingBackendCount;
63736         pResourceManager->config.pCustomDecodingBackendUserData = pConfig->pCustomDecodingBackendUserData;
63737     }
63738
63739
63740
63741     /* Here is where we initialize our threading stuff. We don't do this if we don't support threading. */
63742     if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
63743         #ifndef MA_NO_THREADING
63744         {
63745             ma_uint32 iJobThread;
63746
63747             /* Data buffer lock. */
63748             result = ma_mutex_init(&pResourceManager->dataBufferBSTLock);
63749             if (result != MA_SUCCESS) {
63750                 ma_resource_manager_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks);
63751                 return result;
63752             }
63753
63754             /* Create the job threads last to ensure the threads has access to valid data. */
63755             for (iJobThread = 0; iJobThread < pResourceManager->config.jobThreadCount; iJobThread += 1) {
63756                 result = ma_thread_create(&pResourceManager->jobThreads[iJobThread], ma_thread_priority_normal, 0, ma_resource_manager_job_thread, pResourceManager, &pResourceManager->config.allocationCallbacks);
63757                 if (result != MA_SUCCESS) {
63758                     ma_mutex_uninit(&pResourceManager->dataBufferBSTLock);
63759                     ma_resource_manager_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks);
63760                     return result;
63761                 }
63762             }
63763         }
63764         #else
63765         {
63766             /* Threading is disabled at compile time. We should never get here because validation checks should have already been performed. */
63767             MA_ASSERT(MA_FALSE);
63768         }
63769         #endif
63770     }
63771
63772     return MA_SUCCESS;
63773 }
63774
63775
63776 static void ma_resource_manager_delete_all_data_buffer_nodes(ma_resource_manager* pResourceManager)
63777 {
63778     MA_ASSERT(pResourceManager);
63779
63780     /* If everything was done properly, there shouldn't be any active data buffers. */
63781     while (pResourceManager->pRootDataBufferNode != NULL) {
63782         ma_resource_manager_data_buffer_node* pDataBufferNode = pResourceManager->pRootDataBufferNode;
63783         ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode);
63784
63785         /* The data buffer has been removed from the BST, so now we need to free it's data. */
63786         ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode);
63787     }
63788 }
63789
63790 MA_API void ma_resource_manager_uninit(ma_resource_manager* pResourceManager)
63791 {
63792     if (pResourceManager == NULL) {
63793         return;
63794     }
63795
63796     /*
63797     Job threads need to be killed first. To do this we need to post a quit message to the message queue and then wait for the thread. The quit message will never be removed from the
63798     queue which means it will never not be returned after being encounted for the first time which means all threads will eventually receive it.
63799     */
63800     ma_resource_manager_post_job_quit(pResourceManager);
63801
63802     /* Wait for every job to finish before continuing to ensure nothing is sill trying to access any of our objects below. */
63803     if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
63804         #ifndef MA_NO_THREADING
63805         {
63806             ma_uint32 iJobThread;
63807
63808             for (iJobThread = 0; iJobThread < pResourceManager->config.jobThreadCount; iJobThread += 1) {
63809                 ma_thread_wait(&pResourceManager->jobThreads[iJobThread]);
63810             }
63811         }
63812         #else
63813         {
63814             MA_ASSERT(MA_FALSE);    /* Should never hit this. */
63815         }
63816         #endif
63817     }
63818
63819     /* At this point the thread should have returned and no other thread should be accessing our data. We can now delete all data buffers. */
63820     ma_resource_manager_delete_all_data_buffer_nodes(pResourceManager);
63821
63822     /* The job queue is no longer needed. */
63823     ma_resource_manager_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks);
63824
63825     /* We're no longer doing anything with data buffers so the lock can now be uninitialized. */
63826     if (ma_resource_manager_is_threading_enabled(pResourceManager)) {
63827         #ifndef MA_NO_THREADING
63828         {
63829             ma_mutex_uninit(&pResourceManager->dataBufferBSTLock);
63830         }
63831         #else
63832         {
63833             MA_ASSERT(MA_FALSE);    /* Should never hit this. */
63834         }
63835         #endif
63836     }
63837
63838     ma_free(pResourceManager->config.ppCustomDecodingBackendVTables, &pResourceManager->config.allocationCallbacks);
63839
63840     if (pResourceManager->config.pLog == &pResourceManager->log) {
63841         ma_log_uninit(&pResourceManager->log);
63842     }
63843 }
63844
63845 MA_API ma_log* ma_resource_manager_get_log(ma_resource_manager* pResourceManager)
63846 {
63847     if (pResourceManager == NULL) {
63848         return NULL;
63849     }
63850
63851     return pResourceManager->config.pLog;
63852 }
63853
63854
63855
63856 MA_API ma_resource_manager_data_source_config ma_resource_manager_data_source_config_init(void)
63857 {
63858     ma_resource_manager_data_source_config config;
63859
63860     MA_ZERO_OBJECT(&config);
63861     config.rangeEndInPCMFrames     = ~((ma_uint64)0);
63862     config.loopPointEndInPCMFrames = ~((ma_uint64)0);
63863
63864     return config;
63865 }
63866
63867
63868 static ma_decoder_config ma_resource_manager__init_decoder_config(ma_resource_manager* pResourceManager)
63869 {
63870     ma_decoder_config config;
63871
63872     config = ma_decoder_config_init(pResourceManager->config.decodedFormat, pResourceManager->config.decodedChannels, pResourceManager->config.decodedSampleRate);
63873     config.allocationCallbacks    = pResourceManager->config.allocationCallbacks;
63874     config.ppCustomBackendVTables = pResourceManager->config.ppCustomDecodingBackendVTables;
63875     config.customBackendCount     = pResourceManager->config.customDecodingBackendCount;
63876     config.pCustomBackendUserData = pResourceManager->config.pCustomDecodingBackendUserData;
63877
63878     return config;
63879 }
63880
63881 static ma_result ma_resource_manager__init_decoder(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_decoder* pDecoder)
63882 {
63883     ma_result result;
63884     ma_decoder_config config;
63885
63886     MA_ASSERT(pResourceManager != NULL);
63887     MA_ASSERT(pFilePath        != NULL || pFilePathW != NULL);
63888     MA_ASSERT(pDecoder         != NULL);
63889
63890     config = ma_resource_manager__init_decoder_config(pResourceManager);
63891
63892     if (pFilePath != NULL) {
63893         result = ma_decoder_init_vfs(pResourceManager->config.pVFS, pFilePath, &config, pDecoder);
63894         if (result != MA_SUCCESS) {
63895             ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%s\". %s.\n", pFilePath, ma_result_description(result));
63896             return result;
63897         }
63898     } else {
63899         result = ma_decoder_init_vfs_w(pResourceManager->config.pVFS, pFilePathW, &config, pDecoder);
63900         if (result != MA_SUCCESS) {
63901             #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER)
63902                 ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%ls\". %s.\n", pFilePathW, ma_result_description(result));
63903             #endif
63904             return result;
63905         }
63906     }
63907
63908     return MA_SUCCESS;
63909 }
63910
63911 static ma_data_source* ma_resource_manager_data_buffer_get_connector(ma_resource_manager_data_buffer* pDataBuffer)
63912 {
63913     switch (pDataBuffer->pNode->data.type)
63914     {
63915         case ma_resource_manager_data_supply_type_encoded:       return &pDataBuffer->connector.decoder;
63916         case ma_resource_manager_data_supply_type_decoded:       return &pDataBuffer->connector.buffer;
63917         case ma_resource_manager_data_supply_type_decoded_paged: return &pDataBuffer->connector.pagedBuffer;
63918
63919         case ma_resource_manager_data_supply_type_unknown:
63920         default:
63921         {
63922             ma_log_postf(ma_resource_manager_get_log(pDataBuffer->pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to retrieve data buffer connector. Unknown data supply type.\n");
63923             return NULL;
63924         };
63925     };
63926 }
63927
63928 static ma_result ma_resource_manager_data_buffer_init_connector(ma_resource_manager_data_buffer* pDataBuffer, ma_async_notification* pInitNotification, ma_fence* pInitFence)
63929 {
63930     ma_result result;
63931
63932     MA_ASSERT(pDataBuffer != NULL);
63933     MA_ASSERT(pDataBuffer->isConnectorInitialized == MA_FALSE);
63934
63935     /* The underlying data buffer must be initialized before we'll be able to know how to initialize the backend. */
63936     result = ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode);
63937     if (result != MA_SUCCESS && result != MA_BUSY) {
63938         return result;  /* The data buffer is in an erroneous state. */
63939     }
63940
63941     /*
63942     We need to initialize either a ma_decoder or an ma_audio_buffer depending on whether or not the backing data is encoded or decoded. These act as the
63943     "instance" to the data and are used to form the connection between underlying data buffer and the data source. If the data buffer is decoded, we can use
63944     an ma_audio_buffer. This enables us to use memory mapping when mixing which saves us a bit of data movement overhead.
63945     */
63946     switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode))
63947     {
63948         case ma_resource_manager_data_supply_type_encoded:          /* Connector is a decoder. */
63949         {
63950             ma_decoder_config config;
63951             config = ma_resource_manager__init_decoder_config(pDataBuffer->pResourceManager);
63952             result = ma_decoder_init_memory(pDataBuffer->pNode->data.backend.encoded.pData, pDataBuffer->pNode->data.backend.encoded.sizeInBytes, &config, &pDataBuffer->connector.decoder);
63953         } break;
63954
63955         case ma_resource_manager_data_supply_type_decoded:          /* Connector is an audio buffer. */
63956         {
63957             ma_audio_buffer_config config;
63958             config = ma_audio_buffer_config_init(pDataBuffer->pNode->data.backend.decoded.format, pDataBuffer->pNode->data.backend.decoded.channels, pDataBuffer->pNode->data.backend.decoded.totalFrameCount, pDataBuffer->pNode->data.backend.decoded.pData, NULL);
63959             result = ma_audio_buffer_init(&config, &pDataBuffer->connector.buffer);
63960         } break;
63961
63962         case ma_resource_manager_data_supply_type_decoded_paged:    /* Connector is a paged audio buffer. */
63963         {
63964             ma_paged_audio_buffer_config config;
63965             config = ma_paged_audio_buffer_config_init(&pDataBuffer->pNode->data.backend.decodedPaged.data);
63966             result = ma_paged_audio_buffer_init(&config, &pDataBuffer->connector.pagedBuffer);
63967         } break;
63968
63969         case ma_resource_manager_data_supply_type_unknown:
63970         default:
63971         {
63972             /* Unknown data supply type. Should never happen. Need to post an error here. */
63973             return MA_INVALID_ARGS;
63974         };
63975     }
63976
63977     /*
63978     Initialization of the connector is when we can fire the init notification. This will give the application access to
63979     the format/channels/rate of the data source.
63980     */
63981     if (result == MA_SUCCESS) {
63982         /*
63983         Make sure the looping state is set before returning in order to handle the case where the
63984         loop state was set on the data buffer before the connector was initialized.
63985         */
63986         ma_data_source_set_looping(ma_resource_manager_data_buffer_get_connector(pDataBuffer), ma_resource_manager_data_buffer_is_looping(pDataBuffer));
63987
63988         pDataBuffer->isConnectorInitialized = MA_TRUE;
63989
63990         if (pInitNotification != NULL) {
63991             ma_async_notification_signal(pInitNotification);
63992         }
63993
63994         if (pInitFence != NULL) {
63995             ma_fence_release(pInitFence);
63996         }
63997     }
63998
63999     /* At this point the backend should be initialized. We do *not* want to set pDataSource->result here - that needs to be done at a higher level to ensure it's done as the last step. */
64000     return result;
64001 }
64002
64003 static ma_result ma_resource_manager_data_buffer_uninit_connector(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer* pDataBuffer)
64004 {
64005     MA_ASSERT(pResourceManager != NULL);
64006     MA_ASSERT(pDataBuffer      != NULL);
64007
64008     switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode))
64009     {
64010         case ma_resource_manager_data_supply_type_encoded:          /* Connector is a decoder. */
64011         {
64012             ma_decoder_uninit(&pDataBuffer->connector.decoder);
64013         } break;
64014
64015         case ma_resource_manager_data_supply_type_decoded:          /* Connector is an audio buffer. */
64016         {
64017             ma_audio_buffer_uninit(&pDataBuffer->connector.buffer);
64018         } break;
64019
64020         case ma_resource_manager_data_supply_type_decoded_paged:    /* Connector is a paged audio buffer. */
64021         {
64022             ma_paged_audio_buffer_uninit(&pDataBuffer->connector.pagedBuffer);
64023         } break;
64024
64025         case ma_resource_manager_data_supply_type_unknown:
64026         default:
64027         {
64028             /* Unknown data supply type. Should never happen. Need to post an error here. */
64029             return MA_INVALID_ARGS;
64030         };
64031     }
64032
64033     return MA_SUCCESS;
64034 }
64035
64036 static ma_uint32 ma_resource_manager_data_buffer_node_next_execution_order(ma_resource_manager_data_buffer_node* pDataBufferNode)
64037 {
64038     MA_ASSERT(pDataBufferNode != NULL);
64039     return c89atomic_fetch_add_32(&pDataBufferNode->executionCounter, 1);
64040 }
64041
64042 static ma_result ma_resource_manager_data_buffer_node_init_supply_encoded(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, const char* pFilePath, const wchar_t* pFilePathW)
64043 {
64044     ma_result result;
64045     size_t dataSizeInBytes;
64046     void* pData;
64047
64048     MA_ASSERT(pResourceManager != NULL);
64049     MA_ASSERT(pDataBufferNode  != NULL);
64050     MA_ASSERT(pFilePath != NULL || pFilePathW != NULL);
64051
64052     result = ma_vfs_open_and_read_file_ex(pResourceManager->config.pVFS, pFilePath, pFilePathW, &pData, &dataSizeInBytes, &pResourceManager->config.allocationCallbacks);
64053     if (result != MA_SUCCESS) {
64054         if (pFilePath != NULL) {
64055             ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%s\". %s.\n", pFilePath, ma_result_description(result));
64056         } else {
64057             #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER)
64058                 ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to load file \"%ls\". %s.\n", pFilePathW, ma_result_description(result));
64059             #endif
64060         }
64061
64062         return result;
64063     }
64064
64065     pDataBufferNode->data.backend.encoded.pData       = pData;
64066     pDataBufferNode->data.backend.encoded.sizeInBytes = dataSizeInBytes;
64067     ma_resource_manager_data_buffer_node_set_data_supply_type(pDataBufferNode, ma_resource_manager_data_supply_type_encoded);  /* <-- Must be set last. */
64068
64069     return MA_SUCCESS;
64070 }
64071
64072 static ma_result ma_resource_manager_data_buffer_node_init_supply_decoded(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, const char* pFilePath, const wchar_t* pFilePathW, ma_decoder** ppDecoder)
64073 {
64074     ma_result result = MA_SUCCESS;
64075     ma_decoder* pDecoder;
64076     ma_uint64 totalFrameCount;
64077
64078     MA_ASSERT(pResourceManager != NULL);
64079     MA_ASSERT(pDataBufferNode  != NULL);
64080     MA_ASSERT(ppDecoder         != NULL);
64081     MA_ASSERT(pFilePath != NULL || pFilePathW != NULL);
64082
64083     *ppDecoder = NULL;  /* For safety. */
64084
64085     pDecoder = (ma_decoder*)ma_malloc(sizeof(*pDecoder), &pResourceManager->config.allocationCallbacks);
64086     if (pDecoder == NULL) {
64087         return MA_OUT_OF_MEMORY;
64088     }
64089
64090     result = ma_resource_manager__init_decoder(pResourceManager, pFilePath, pFilePathW, pDecoder);
64091     if (result != MA_SUCCESS) {
64092         ma_free(pDecoder, &pResourceManager->config.allocationCallbacks);
64093         return result;
64094     }
64095
64096     /*
64097     At this point we have the decoder and we now need to initialize the data supply. This will
64098     be either a decoded buffer, or a decoded paged buffer. A regular buffer is just one big heap
64099     allocated buffer, whereas a paged buffer is a linked list of paged-sized buffers. The latter
64100     is used when the length of a sound is unknown until a full decode has been performed.
64101     */
64102     result = ma_decoder_get_length_in_pcm_frames(pDecoder, &totalFrameCount);
64103     if (result != MA_SUCCESS) {
64104         return result;
64105     }
64106
64107     if (totalFrameCount > 0) {
64108         /* It's a known length. The data supply is a regular decoded buffer. */
64109         ma_uint64 dataSizeInBytes;
64110         void* pData;
64111
64112         dataSizeInBytes = totalFrameCount * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels);
64113         if (dataSizeInBytes > MA_SIZE_MAX) {
64114             ma_decoder_uninit(pDecoder);
64115             ma_free(pDecoder, &pResourceManager->config.allocationCallbacks);
64116             return MA_TOO_BIG;
64117         }
64118
64119         pData = ma_malloc((size_t)dataSizeInBytes, &pResourceManager->config.allocationCallbacks);
64120         if (pData == NULL) {
64121             ma_decoder_uninit(pDecoder);
64122             ma_free(pDecoder, &pResourceManager->config.allocationCallbacks);
64123             return MA_OUT_OF_MEMORY;
64124         }
64125
64126         /* The buffer needs to be initialized to silence in case the caller reads from it. */
64127         ma_silence_pcm_frames(pData, totalFrameCount, pDecoder->outputFormat, pDecoder->outputChannels);
64128
64129         /* Data has been allocated and the data supply can now be initialized. */
64130         pDataBufferNode->data.backend.decoded.pData             = pData;
64131         pDataBufferNode->data.backend.decoded.totalFrameCount   = totalFrameCount;
64132         pDataBufferNode->data.backend.decoded.format            = pDecoder->outputFormat;
64133         pDataBufferNode->data.backend.decoded.channels          = pDecoder->outputChannels;
64134         pDataBufferNode->data.backend.decoded.sampleRate        = pDecoder->outputSampleRate;
64135         pDataBufferNode->data.backend.decoded.decodedFrameCount = 0;
64136         ma_resource_manager_data_buffer_node_set_data_supply_type(pDataBufferNode, ma_resource_manager_data_supply_type_decoded);  /* <-- Must be set last. */
64137     } else {
64138         /*
64139         It's an unknown length. The data supply is a paged decoded buffer. Setting this up is
64140         actually easier than the non-paged decoded buffer because we just need to initialize
64141         a ma_paged_audio_buffer object.
64142         */
64143         result = ma_paged_audio_buffer_data_init(pDecoder->outputFormat, pDecoder->outputChannels, &pDataBufferNode->data.backend.decodedPaged.data);
64144         if (result != MA_SUCCESS) {
64145             ma_decoder_uninit(pDecoder);
64146             ma_free(pDecoder, &pResourceManager->config.allocationCallbacks);
64147             return result;
64148         }
64149
64150         pDataBufferNode->data.backend.decodedPaged.sampleRate        = pDecoder->outputSampleRate;
64151         pDataBufferNode->data.backend.decodedPaged.decodedFrameCount = 0;
64152         ma_resource_manager_data_buffer_node_set_data_supply_type(pDataBufferNode, ma_resource_manager_data_supply_type_decoded_paged);  /* <-- Must be set last. */
64153     }
64154
64155     *ppDecoder = pDecoder;
64156
64157     return MA_SUCCESS;
64158 }
64159
64160 static ma_result ma_resource_manager_data_buffer_node_decode_next_page(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, ma_decoder* pDecoder)
64161 {
64162     ma_result result = MA_SUCCESS;
64163     ma_uint64 pageSizeInFrames;
64164     ma_uint64 framesToTryReading;
64165     ma_uint64 framesRead;
64166
64167     MA_ASSERT(pResourceManager != NULL);
64168     MA_ASSERT(pDataBufferNode  != NULL);
64169     MA_ASSERT(pDecoder         != NULL);
64170
64171     /* We need to know the size of a page in frames to know how many frames to decode. */
64172     pageSizeInFrames = MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS * (pDecoder->outputSampleRate/1000);
64173     framesToTryReading = pageSizeInFrames;
64174
64175     /*
64176     Here is where we do the decoding of the next page. We'll run a slightly different path depending
64177     on whether or not we're using a flat or paged buffer because the allocation of the page differs
64178     between the two. For a flat buffer it's an offset to an already-allocated buffer. For a paged
64179     buffer, we need to allocate a new page and attach it to the linked list.
64180     */
64181     switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode))
64182     {
64183         case ma_resource_manager_data_supply_type_decoded:
64184         {
64185             /* The destination buffer is an offset to the existing buffer. Don't read more than we originally retrieved when we first initialized the decoder. */
64186             void* pDst;
64187             ma_uint64 framesRemaining = pDataBufferNode->data.backend.decoded.totalFrameCount - pDataBufferNode->data.backend.decoded.decodedFrameCount;
64188             if (framesToTryReading > framesRemaining) {
64189                 framesToTryReading = framesRemaining;
64190             }
64191
64192             if (framesToTryReading > 0) {
64193                 pDst = ma_offset_ptr(
64194                     pDataBufferNode->data.backend.decoded.pData,
64195                     pDataBufferNode->data.backend.decoded.decodedFrameCount * ma_get_bytes_per_frame(pDataBufferNode->data.backend.decoded.format, pDataBufferNode->data.backend.decoded.channels)
64196                 );
64197                 MA_ASSERT(pDst != NULL);
64198
64199                 result = ma_decoder_read_pcm_frames(pDecoder, pDst, framesToTryReading, &framesRead);
64200                 if (framesRead > 0) {
64201                     pDataBufferNode->data.backend.decoded.decodedFrameCount += framesRead;
64202                 }
64203             } else {
64204                 framesRead = 0;
64205             }
64206         } break;
64207
64208         case ma_resource_manager_data_supply_type_decoded_paged:
64209         {
64210             /* The destination buffer is a freshly allocated page. */
64211             ma_paged_audio_buffer_page* pPage;
64212
64213             result = ma_paged_audio_buffer_data_allocate_page(&pDataBufferNode->data.backend.decodedPaged.data, framesToTryReading, NULL, &pResourceManager->config.allocationCallbacks, &pPage);
64214             if (result != MA_SUCCESS) {
64215                 return result;
64216             }
64217
64218             result = ma_decoder_read_pcm_frames(pDecoder, pPage->pAudioData, framesToTryReading, &framesRead);
64219             if (framesRead > 0) {
64220                 pPage->sizeInFrames = framesRead;
64221
64222                 result = ma_paged_audio_buffer_data_append_page(&pDataBufferNode->data.backend.decodedPaged.data, pPage);
64223                 if (result == MA_SUCCESS) {
64224                     pDataBufferNode->data.backend.decodedPaged.decodedFrameCount += framesRead;
64225                 } else {
64226                     /* Failed to append the page. Just abort and set the status to MA_AT_END. */
64227                     ma_paged_audio_buffer_data_free_page(&pDataBufferNode->data.backend.decodedPaged.data, pPage, &pResourceManager->config.allocationCallbacks);
64228                     result = MA_AT_END;
64229                 }
64230             } else {
64231                 /* No frames were read. Free the page and just set the status to MA_AT_END. */
64232                 ma_paged_audio_buffer_data_free_page(&pDataBufferNode->data.backend.decodedPaged.data, pPage, &pResourceManager->config.allocationCallbacks);
64233                 result = MA_AT_END;
64234             }
64235         } break;
64236
64237         case ma_resource_manager_data_supply_type_encoded:
64238         case ma_resource_manager_data_supply_type_unknown:
64239         default:
64240         {
64241             /* Unexpected data supply type. */
64242             ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Unexpected data supply type (%d) when decoding page.", ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBufferNode));
64243             return MA_ERROR;
64244         };
64245     }
64246
64247     if (result == MA_SUCCESS && framesRead == 0) {
64248         result = MA_AT_END;
64249     }
64250
64251     return result;
64252 }
64253
64254 static ma_result ma_resource_manager_data_buffer_node_acquire_critical_section(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 hashedName32, ma_uint32 flags, const ma_resource_manager_data_supply* pExistingData, ma_fence* pInitFence, ma_fence* pDoneFence, ma_resource_manager_inline_notification* pInitNotification, ma_resource_manager_data_buffer_node** ppDataBufferNode)
64255 {
64256     ma_result result = MA_SUCCESS;
64257     ma_resource_manager_data_buffer_node* pDataBufferNode = NULL;
64258     ma_resource_manager_data_buffer_node* pInsertPoint;
64259
64260     if (ppDataBufferNode != NULL) {
64261         *ppDataBufferNode = NULL;
64262     }
64263
64264     result = ma_resource_manager_data_buffer_node_insert_point(pResourceManager, hashedName32, &pInsertPoint);
64265     if (result == MA_ALREADY_EXISTS) {
64266         /* The node already exists. We just need to increment the reference count. */
64267         pDataBufferNode = pInsertPoint;
64268
64269         result = ma_resource_manager_data_buffer_node_increment_ref(pResourceManager, pDataBufferNode, NULL);
64270         if (result != MA_SUCCESS) {
64271             return result;  /* Should never happen. Failed to increment the reference count. */
64272         }
64273
64274         result = MA_ALREADY_EXISTS;
64275         goto done;
64276     } else {
64277         /*
64278         The node does not already exist. We need to post a LOAD_DATA_BUFFER_NODE job here. This
64279         needs to be done inside the critical section to ensure an uninitialization of the node
64280         does not occur before initialization on another thread.
64281         */
64282         pDataBufferNode = (ma_resource_manager_data_buffer_node*)ma_malloc(sizeof(*pDataBufferNode), &pResourceManager->config.allocationCallbacks);
64283         if (pDataBufferNode == NULL) {
64284             return MA_OUT_OF_MEMORY;
64285         }
64286
64287         MA_ZERO_OBJECT(pDataBufferNode);
64288         pDataBufferNode->hashedName32 = hashedName32;
64289         pDataBufferNode->refCount     = 1;        /* Always set to 1 by default (this is our first reference). */
64290
64291         if (pExistingData == NULL) {
64292             pDataBufferNode->data.type    = ma_resource_manager_data_supply_type_unknown;    /* <-- We won't know this until we start decoding. */
64293             pDataBufferNode->result       = MA_BUSY;  /* Must be set to MA_BUSY before we leave the critical section, so might as well do it now. */
64294             pDataBufferNode->isDataOwnedByResourceManager = MA_TRUE;
64295         } else {
64296             pDataBufferNode->data         = *pExistingData;
64297             pDataBufferNode->result       = MA_SUCCESS;   /* Not loading asynchronously, so just set the status */
64298             pDataBufferNode->isDataOwnedByResourceManager = MA_FALSE;
64299         }
64300
64301         result = ma_resource_manager_data_buffer_node_insert_at(pResourceManager, pDataBufferNode, pInsertPoint);
64302         if (result != MA_SUCCESS) {
64303             ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks);
64304             return result;  /* Should never happen. Failed to insert the data buffer into the BST. */
64305         }
64306
64307         /*
64308         Here is where we'll post the job, but only if we're loading asynchronously. If we're
64309         loading synchronously we'll defer loading to a later stage, outside of the critical
64310         section.
64311         */
64312         if (pDataBufferNode->isDataOwnedByResourceManager && (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0) {
64313             /* Loading asynchronously. Post the job. */
64314             ma_resource_manager_job job;
64315             char* pFilePathCopy = NULL;
64316             wchar_t* pFilePathWCopy = NULL;
64317
64318             /* We need a copy of the file path. We should probably make this more efficient, but for now we'll do a transient memory allocation. */
64319             if (pFilePath != NULL) {
64320                 pFilePathCopy = ma_copy_string(pFilePath, &pResourceManager->config.allocationCallbacks);
64321             } else {
64322                 pFilePathWCopy = ma_copy_string_w(pFilePathW, &pResourceManager->config.allocationCallbacks);
64323             }
64324
64325             if (pFilePathCopy == NULL && pFilePathWCopy == NULL) {
64326                 ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode);
64327                 ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks);
64328                 return MA_OUT_OF_MEMORY;
64329             }
64330
64331             if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
64332                 ma_resource_manager_inline_notification_init(pResourceManager, pInitNotification);
64333             }
64334
64335             /* Acquire init and done fences before posting the job. These will be unacquired by the job thread. */
64336             if (pInitFence != NULL) { ma_fence_acquire(pInitFence); }
64337             if (pDoneFence != NULL) { ma_fence_acquire(pDoneFence); }
64338
64339             /* We now have everything we need to post the job to the job thread. */
64340             job = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE);
64341             job.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode);
64342             job.data.loadDataBufferNode.pDataBufferNode   = pDataBufferNode;
64343             job.data.loadDataBufferNode.pFilePath         = pFilePathCopy;
64344             job.data.loadDataBufferNode.pFilePathW        = pFilePathWCopy;
64345             job.data.loadDataBufferNode.decode            =  (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE   ) != 0;
64346             job.data.loadDataBufferNode.pInitNotification = ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) ? pInitNotification : NULL;
64347             job.data.loadDataBufferNode.pDoneNotification = NULL;
64348             job.data.loadDataBufferNode.pInitFence        = pInitFence;
64349             job.data.loadDataBufferNode.pDoneFence        = pDoneFence;
64350
64351             result = ma_resource_manager_post_job(pResourceManager, &job);
64352             if (result != MA_SUCCESS) {
64353                 /* Failed to post job. Probably ran out of memory. */
64354                 ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result));
64355
64356                 /*
64357                 Fences were acquired before posting the job, but since the job was not able to
64358                 be posted, we need to make sure we release them so nothing gets stuck waiting.
64359                 */
64360                 if (pInitFence != NULL) { ma_fence_release(pInitFence); }
64361                 if (pDoneFence != NULL) { ma_fence_release(pDoneFence); }
64362
64363                 if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
64364                     ma_resource_manager_inline_notification_init(pResourceManager, pInitNotification);
64365                 }
64366
64367                 ma_free(pFilePathCopy,  &pResourceManager->config.allocationCallbacks);
64368                 ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks);
64369
64370                 ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode);
64371                 ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks);
64372
64373                 return result;
64374             }
64375         }
64376     }
64377
64378 done:
64379     if (ppDataBufferNode != NULL) {
64380         *ppDataBufferNode = pDataBufferNode;
64381     }
64382
64383     return result;
64384 }
64385
64386 static ma_result ma_resource_manager_data_buffer_node_acquire(ma_resource_manager* pResourceManager, const char* pFilePath, const wchar_t* pFilePathW, ma_uint32 hashedName32, ma_uint32 flags, const ma_resource_manager_data_supply* pExistingData, ma_fence* pInitFence, ma_fence* pDoneFence, ma_resource_manager_data_buffer_node** ppDataBufferNode)
64387 {
64388     ma_result result = MA_SUCCESS;
64389     ma_bool32 nodeAlreadyExists = MA_FALSE;
64390     ma_resource_manager_data_buffer_node* pDataBufferNode = NULL;
64391     ma_resource_manager_inline_notification initNotification;   /* Used when the WAIT_INIT flag is set. */
64392
64393     if (ppDataBufferNode != NULL) {
64394         *ppDataBufferNode = NULL;   /* Safety. */
64395     }
64396
64397     if (pResourceManager == NULL || (pFilePath == NULL && pFilePathW == NULL && hashedName32 == 0)) {
64398         return MA_INVALID_ARGS;
64399     }
64400
64401     /* If we're specifying existing data, it must be valid. */
64402     if (pExistingData != NULL && pExistingData->type == ma_resource_manager_data_supply_type_unknown) {
64403         return MA_INVALID_ARGS;
64404     }
64405
64406     /* If we don't support threading, remove the ASYNC flag to make the rest of this a bit simpler. */
64407     if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) {
64408         flags &= ~MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC;
64409     }
64410
64411     if (hashedName32 == 0) {
64412         if (pFilePath != NULL) {
64413             hashedName32 = ma_hash_string_32(pFilePath);
64414         } else {
64415             hashedName32 = ma_hash_string_w_32(pFilePathW);
64416         }
64417     }
64418
64419     /*
64420     Here is where we either increment the node's reference count or allocate a new one and add it
64421     to the BST. When allocating a new node, we need to make sure the LOAD_DATA_BUFFER_NODE job is
64422     posted inside the critical section just in case the caller immediately uninitializes the node
64423     as this will ensure the FREE_DATA_BUFFER_NODE job is given an execution order such that the
64424     node is not uninitialized before initialization.
64425     */
64426     ma_resource_manager_data_buffer_bst_lock(pResourceManager);
64427     {
64428         result = ma_resource_manager_data_buffer_node_acquire_critical_section(pResourceManager, pFilePath, pFilePathW, hashedName32, flags, pExistingData, pInitFence, pDoneFence, &initNotification, &pDataBufferNode);
64429     }
64430     ma_resource_manager_data_buffer_bst_unlock(pResourceManager);
64431
64432     if (result == MA_ALREADY_EXISTS) {
64433         nodeAlreadyExists = MA_TRUE;
64434         result = MA_SUCCESS;
64435     } else {
64436         if (result != MA_SUCCESS) {
64437             return result;
64438         }
64439     }
64440
64441     /*
64442     If we're loading synchronously, we'll need to load everything now. When loading asynchronously,
64443     a job will have been posted inside the BST critical section so that an uninitialization can be
64444     allocated an appropriate execution order thereby preventing it from being uninitialized before
64445     the node is initialized by the decoding thread(s).
64446     */
64447     if (nodeAlreadyExists == MA_FALSE) {    /* Don't need to try loading anything if the node already exists. */
64448         if (pFilePath == NULL && pFilePathW == NULL) {
64449             /*
64450             If this path is hit, it means a buffer is being copied (i.e. initialized from only the
64451             hashed name), but that node has been freed in the meantime, probably from some other
64452             thread. This is an invalid operation.
64453             */
64454             ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Cloning data buffer node failed because the source node was released. The source node must remain valid until the cloning has completed.\n");
64455             result = MA_INVALID_OPERATION;
64456             goto done;
64457         }
64458
64459         if (pDataBufferNode->isDataOwnedByResourceManager) {
64460             if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) == 0) {
64461                 /* Loading synchronously. Load the sound in it's entirety here. */
64462                 if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE) == 0) {
64463                     /* No decoding. This is the simple case - just store the file contents in memory. */
64464                     result = ma_resource_manager_data_buffer_node_init_supply_encoded(pResourceManager, pDataBufferNode, pFilePath, pFilePathW);
64465                     if (result != MA_SUCCESS) {
64466                         goto done;
64467                     }
64468                 } else {
64469                     /* Decoding. We do this the same way as we do when loading asynchronously. */
64470                     ma_decoder* pDecoder;
64471                     result = ma_resource_manager_data_buffer_node_init_supply_decoded(pResourceManager, pDataBufferNode, pFilePath, pFilePathW, &pDecoder);
64472                     if (result != MA_SUCCESS) {
64473                         goto done;
64474                     }
64475
64476                     /* We have the decoder, now decode page by page just like we do when loading asynchronously. */
64477                     for (;;) {
64478                         /* Decode next page. */
64479                         result = ma_resource_manager_data_buffer_node_decode_next_page(pResourceManager, pDataBufferNode, pDecoder);
64480                         if (result != MA_SUCCESS) {
64481                             break;  /* Will return MA_AT_END when the last page has been decoded. */
64482                         }
64483                     }
64484
64485                     /* Reaching the end needs to be considered successful. */
64486                     if (result == MA_AT_END) {
64487                         result  = MA_SUCCESS;
64488                     }
64489
64490                     /*
64491                     At this point the data buffer is either fully decoded or some error occurred. Either
64492                     way, the decoder is no longer necessary.
64493                     */
64494                     ma_decoder_uninit(pDecoder);
64495                     ma_free(pDecoder, &pResourceManager->config.allocationCallbacks);
64496                 }
64497
64498                 /* Getting here means we were successful. Make sure the status of the node is updated accordingly. */
64499                 c89atomic_exchange_i32(&pDataBufferNode->result, result);
64500             } else {
64501                 /* Loading asynchronously. We may need to wait for initialization. */
64502                 if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
64503                     ma_resource_manager_inline_notification_wait(&initNotification);
64504                 }
64505             }
64506         } else {
64507             /* The data is not managed by the resource manager so there's nothing else to do. */
64508             MA_ASSERT(pExistingData != NULL);
64509         }
64510     }
64511
64512 done:
64513     /* If we failed to initialize the data buffer we need to free it. */
64514     if (result != MA_SUCCESS) {
64515         if (nodeAlreadyExists == MA_FALSE) {
64516             ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode);
64517             ma_free(pDataBufferNode, &pResourceManager->config.allocationCallbacks);
64518         }
64519     }
64520
64521     /*
64522     The init notification needs to be uninitialized. This will be used if the node does not already
64523     exist, and we've specified ASYNC | WAIT_INIT.
64524     */
64525     if (nodeAlreadyExists == MA_FALSE && pDataBufferNode->isDataOwnedByResourceManager && (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0) {
64526         if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
64527             ma_resource_manager_inline_notification_uninit(&initNotification);
64528         }
64529     }
64530
64531     if (ppDataBufferNode != NULL) {
64532         *ppDataBufferNode = pDataBufferNode;
64533     }
64534
64535     return result;
64536 }
64537
64538 static ma_result ma_resource_manager_data_buffer_node_unacquire(ma_resource_manager* pResourceManager, ma_resource_manager_data_buffer_node* pDataBufferNode, const char* pName, const wchar_t* pNameW)
64539 {
64540     ma_result result = MA_SUCCESS;
64541     ma_uint32 refCount = 0xFFFFFFFF; /* The new reference count of the node after decrementing. Initialize to non-0 to be safe we don't fall into the freeing path. */
64542     ma_uint32 hashedName32 = 0;
64543
64544     if (pResourceManager == NULL) {
64545         return MA_INVALID_ARGS;
64546     }
64547
64548     if (pDataBufferNode == NULL) {
64549         if (pName == NULL && pNameW == NULL) {
64550             return MA_INVALID_ARGS;
64551         }
64552
64553         if (pName != NULL) {
64554             hashedName32 = ma_hash_string_32(pName);
64555         } else {
64556             hashedName32 = ma_hash_string_w_32(pNameW);
64557         }
64558     }
64559
64560     /*
64561     The first thing to do is decrement the reference counter of the node. Then, if the reference
64562     count is zero, we need to free the node. If the node is still in the process of loading, we'll
64563     need to post a job to the job queue to free the node. Otherwise we'll just do it here.
64564     */
64565     ma_resource_manager_data_buffer_bst_lock(pResourceManager);
64566     {
64567         /* Might need to find the node. Must be done inside the critical section. */
64568         if (pDataBufferNode == NULL) {
64569             result = ma_resource_manager_data_buffer_node_search(pResourceManager, hashedName32, &pDataBufferNode);
64570             if (result != MA_SUCCESS) {
64571                 goto stage2;    /* Couldn't find the node. */
64572             }
64573         }
64574
64575         result = ma_resource_manager_data_buffer_node_decrement_ref(pResourceManager, pDataBufferNode, &refCount);
64576         if (result != MA_SUCCESS) {
64577             goto stage2;    /* Should never happen. */
64578         }
64579
64580         if (refCount == 0) {
64581             result = ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode);
64582             if (result != MA_SUCCESS) {
64583                 goto stage2;  /* An error occurred when trying to remove the data buffer. This should never happen. */
64584             }
64585         }
64586     }
64587     ma_resource_manager_data_buffer_bst_unlock(pResourceManager);
64588
64589 stage2:
64590     if (result != MA_SUCCESS) {
64591         return result;
64592     }
64593
64594     /*
64595     Here is where we need to free the node. We don't want to do this inside the critical section
64596     above because we want to keep that as small as possible for multi-threaded efficiency.
64597     */
64598     if (refCount == 0) {
64599         if (ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_BUSY) {
64600             /* The sound is still loading. We need to delay the freeing of the node to a safe time. */
64601             ma_resource_manager_job job;
64602
64603             /* We need to mark the node as unavailable for the sake of the resource manager worker threads. */
64604             c89atomic_exchange_i32(&pDataBufferNode->result, MA_UNAVAILABLE);
64605
64606             job = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER_NODE);
64607             job.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode);
64608             job.data.freeDataBufferNode.pDataBufferNode = pDataBufferNode;
64609
64610             result = ma_resource_manager_post_job(pResourceManager, &job);
64611             if (result != MA_SUCCESS) {
64612                 ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER_NODE job. %s.\n", ma_result_description(result));
64613                 return result;
64614             }
64615
64616             /* If we don't support threading, process the job queue here. */
64617             if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) {
64618                 while (ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_BUSY) {
64619                     result = ma_resource_manager_process_next_job(pResourceManager);
64620                     if (result == MA_NO_DATA_AVAILABLE || result == MA_CANCELLED) {
64621                         result = MA_SUCCESS;
64622                         break;
64623                     }
64624                 }
64625             } else {
64626                 /* Threading is enabled. The job queue will deal with the rest of the cleanup from here. */
64627             }
64628         } else {
64629             /* The sound isn't loading so we can just free the node here. */
64630             ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode);
64631         }
64632     }
64633
64634     return result;
64635 }
64636
64637
64638
64639 static ma_uint32 ma_resource_manager_data_buffer_next_execution_order(ma_resource_manager_data_buffer* pDataBuffer)
64640 {
64641     MA_ASSERT(pDataBuffer != NULL);
64642     return c89atomic_fetch_add_32(&pDataBuffer->executionCounter, 1);
64643 }
64644
64645 static ma_result ma_resource_manager_data_buffer_cb__read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
64646 {
64647     return ma_resource_manager_data_buffer_read_pcm_frames((ma_resource_manager_data_buffer*)pDataSource, pFramesOut, frameCount, pFramesRead);
64648 }
64649
64650 static ma_result ma_resource_manager_data_buffer_cb__seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex)
64651 {
64652     return ma_resource_manager_data_buffer_seek_to_pcm_frame((ma_resource_manager_data_buffer*)pDataSource, frameIndex);
64653 }
64654
64655 static ma_result ma_resource_manager_data_buffer_cb__get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
64656 {
64657     return ma_resource_manager_data_buffer_get_data_format((ma_resource_manager_data_buffer*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
64658 }
64659
64660 static ma_result ma_resource_manager_data_buffer_cb__get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor)
64661 {
64662     return ma_resource_manager_data_buffer_get_cursor_in_pcm_frames((ma_resource_manager_data_buffer*)pDataSource, pCursor);
64663 }
64664
64665 static ma_result ma_resource_manager_data_buffer_cb__get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength)
64666 {
64667     return ma_resource_manager_data_buffer_get_length_in_pcm_frames((ma_resource_manager_data_buffer*)pDataSource, pLength);
64668 }
64669
64670 static ma_result ma_resource_manager_data_buffer_cb__set_looping(ma_data_source* pDataSource, ma_bool32 isLooping)
64671 {
64672     return ma_resource_manager_data_buffer_set_looping((ma_resource_manager_data_buffer*)pDataSource, isLooping);
64673 }
64674
64675 static ma_data_source_vtable g_ma_resource_manager_data_buffer_vtable =
64676 {
64677     ma_resource_manager_data_buffer_cb__read_pcm_frames,
64678     ma_resource_manager_data_buffer_cb__seek_to_pcm_frame,
64679     ma_resource_manager_data_buffer_cb__get_data_format,
64680     ma_resource_manager_data_buffer_cb__get_cursor_in_pcm_frames,
64681     ma_resource_manager_data_buffer_cb__get_length_in_pcm_frames,
64682     ma_resource_manager_data_buffer_cb__set_looping,
64683     0
64684 };
64685
64686 static ma_result ma_resource_manager_data_buffer_init_ex_internal(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_uint32 hashedName32, ma_resource_manager_data_buffer* pDataBuffer)
64687 {
64688     ma_result result = MA_SUCCESS;
64689     ma_resource_manager_data_buffer_node* pDataBufferNode;
64690     ma_data_source_config dataSourceConfig;
64691     ma_bool32 async;
64692     ma_uint32 flags;
64693     ma_resource_manager_pipeline_notifications notifications;
64694
64695     if (pDataBuffer == NULL) {
64696         if (pConfig != NULL && pConfig->pNotifications != NULL) {
64697             ma_resource_manager_pipeline_notifications_signal_all_notifications(&notifications);
64698         }
64699
64700         return MA_INVALID_ARGS;
64701     }
64702
64703     MA_ZERO_OBJECT(pDataBuffer);
64704
64705     if (pConfig == NULL) {
64706         return MA_INVALID_ARGS;
64707     }
64708
64709     if (pConfig->pNotifications != NULL) {
64710         notifications = *pConfig->pNotifications;   /* From here on out we should be referencing `notifications` instead of `pNotifications`. Set this to NULL to catch errors at testing time. */
64711     } else {
64712         MA_ZERO_OBJECT(&notifications);
64713     }
64714
64715     /* For safety, always remove the ASYNC flag if threading is disabled on the resource manager. */
64716     flags = pConfig->flags;
64717     if (ma_resource_manager_is_threading_enabled(pResourceManager) == MA_FALSE) {
64718         flags &= ~MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC;
64719     }
64720
64721     async = (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0;
64722
64723     /*
64724     Fences need to be acquired before doing anything. These must be aquired and released outside of
64725     the node to ensure there's no holes where ma_fence_wait() could prematurely return before the
64726     data buffer has completed initialization.
64727
64728     When loading asynchronously, the node acquisition routine below will acquire the fences on this
64729     thread and then release them on the async thread when the operation is complete.
64730
64731     These fences are always released at the "done" tag at the end of this function. They'll be
64732     acquired a second if loading asynchronously. This double acquisition system is just done to
64733     simplify code maintanence.
64734     */
64735     ma_resource_manager_pipeline_notifications_acquire_all_fences(&notifications);
64736     {
64737         /* We first need to acquire a node. If ASYNC is not set, this will not return until the entire sound has been loaded. */
64738         result = ma_resource_manager_data_buffer_node_acquire(pResourceManager, pConfig->pFilePath, pConfig->pFilePathW, hashedName32, flags, NULL, notifications.init.pFence, notifications.done.pFence, &pDataBufferNode);
64739         if (result != MA_SUCCESS) {
64740             ma_resource_manager_pipeline_notifications_signal_all_notifications(&notifications);
64741             goto done;
64742         }
64743
64744         dataSourceConfig = ma_data_source_config_init();
64745         dataSourceConfig.vtable = &g_ma_resource_manager_data_buffer_vtable;
64746
64747         result = ma_data_source_init(&dataSourceConfig, &pDataBuffer->ds);
64748         if (result != MA_SUCCESS) {
64749             ma_resource_manager_data_buffer_node_unacquire(pResourceManager, pDataBufferNode, NULL, NULL);
64750             ma_resource_manager_pipeline_notifications_signal_all_notifications(&notifications);
64751             goto done;
64752         }
64753
64754         pDataBuffer->pResourceManager = pResourceManager;
64755         pDataBuffer->pNode  = pDataBufferNode;
64756         pDataBuffer->flags  = flags;
64757         pDataBuffer->result = MA_BUSY;  /* Always default to MA_BUSY for safety. It'll be overwritten when loading completes or an error occurs. */
64758
64759         /* If we're loading asynchronously we need to post a job to the job queue to initialize the connector. */
64760         if (async == MA_FALSE || ma_resource_manager_data_buffer_node_result(pDataBufferNode) == MA_SUCCESS) {
64761             /* Loading synchronously or the data has already been fully loaded. We can just initialize the connector from here without a job. */
64762             result = ma_resource_manager_data_buffer_init_connector(pDataBuffer, NULL, NULL);
64763             c89atomic_exchange_i32(&pDataBuffer->result, result);
64764
64765             ma_resource_manager_pipeline_notifications_signal_all_notifications(&notifications);
64766             goto done;
64767         } else {
64768             /* The node's data supply isn't initialized yet. The caller has requested that we load asynchronously so we need to post a job to do this. */
64769             ma_resource_manager_job job;
64770             ma_resource_manager_inline_notification initNotification;   /* Used when the WAIT_INIT flag is set. */
64771
64772             if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
64773                 ma_resource_manager_inline_notification_init(pResourceManager, &initNotification);
64774             }
64775
64776             /*
64777             The status of the data buffer needs to be set to MA_BUSY before posting the job so that the
64778             worker thread is aware of it's busy state. If the LOAD_DATA_BUFFER job sees a status other
64779             than MA_BUSY, it'll assume an error and fall through to an early exit.
64780             */
64781             c89atomic_exchange_i32(&pDataBuffer->result, MA_BUSY);
64782
64783             /* Acquire fences a second time. These will be released by the async thread. */
64784             ma_resource_manager_pipeline_notifications_acquire_all_fences(&notifications);
64785
64786             job = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER);
64787             job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer);
64788             job.data.loadDataBuffer.pDataBuffer       = pDataBuffer;
64789             job.data.loadDataBuffer.pInitNotification = ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) ? &initNotification : notifications.init.pNotification;
64790             job.data.loadDataBuffer.pDoneNotification = notifications.done.pNotification;
64791             job.data.loadDataBuffer.pInitFence        = notifications.init.pFence;
64792             job.data.loadDataBuffer.pDoneFence        = notifications.done.pFence;
64793
64794             result = ma_resource_manager_post_job(pResourceManager, &job);
64795             if (result != MA_SUCCESS) {
64796                 /* We failed to post the job. Most likely there isn't enough room in the queue's buffer. */
64797                 ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER job. %s.\n", ma_result_description(result));
64798                 c89atomic_exchange_i32(&pDataBuffer->result, result);
64799
64800                 /* Release the fences after the result has been set on the data buffer. */
64801                 ma_resource_manager_pipeline_notifications_release_all_fences(&notifications);
64802             } else {
64803                 if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
64804                     ma_resource_manager_inline_notification_wait(&initNotification);
64805
64806                     if (notifications.init.pNotification != NULL) {
64807                         ma_async_notification_signal(notifications.init.pNotification);
64808                     }
64809
64810                     /* NOTE: Do not release the init fence here. It will have been done by the job. */
64811
64812                     /* Make sure we return an error if initialization failed on the async thread. */
64813                     result = ma_resource_manager_data_buffer_result(pDataBuffer);
64814                     if (result == MA_BUSY) {
64815                         result  = MA_SUCCESS;
64816                     }
64817                 }
64818             }
64819
64820             if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
64821                 ma_resource_manager_inline_notification_uninit(&initNotification);
64822             }
64823         }
64824
64825         if (result != MA_SUCCESS) {
64826             ma_resource_manager_data_buffer_node_unacquire(pResourceManager, pDataBufferNode, NULL, NULL);
64827             goto done;
64828         }
64829     }
64830 done:
64831     if (result == MA_SUCCESS) {
64832         if (pConfig->initialSeekPointInPCMFrames > 0) {
64833             ma_resource_manager_data_buffer_seek_to_pcm_frame(pDataBuffer, pConfig->initialSeekPointInPCMFrames);
64834         }
64835     }
64836
64837     ma_resource_manager_pipeline_notifications_release_all_fences(&notifications);
64838
64839     return result;
64840 }
64841
64842 MA_API ma_result ma_resource_manager_data_buffer_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_buffer* pDataBuffer)
64843 {
64844     return ma_resource_manager_data_buffer_init_ex_internal(pResourceManager, pConfig, 0, pDataBuffer);
64845 }
64846
64847 MA_API ma_result ma_resource_manager_data_buffer_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer)
64848 {
64849     ma_resource_manager_data_source_config config;
64850
64851     config = ma_resource_manager_data_source_config_init();
64852     config.pFilePath      = pFilePath;
64853     config.flags          = flags;
64854     config.pNotifications = pNotifications;
64855
64856     return ma_resource_manager_data_buffer_init_ex(pResourceManager, &config, pDataBuffer);
64857 }
64858
64859 MA_API ma_result ma_resource_manager_data_buffer_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_buffer* pDataBuffer)
64860 {
64861     ma_resource_manager_data_source_config config;
64862
64863     config = ma_resource_manager_data_source_config_init();
64864     config.pFilePathW     = pFilePath;
64865     config.flags          = flags;
64866     config.pNotifications = pNotifications;
64867
64868     return ma_resource_manager_data_buffer_init_ex(pResourceManager, &config, pDataBuffer);
64869 }
64870
64871 MA_API ma_result ma_resource_manager_data_buffer_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_buffer* pExistingDataBuffer, ma_resource_manager_data_buffer* pDataBuffer)
64872 {
64873     ma_resource_manager_data_source_config config;
64874
64875     if (pExistingDataBuffer == NULL) {
64876         return MA_INVALID_ARGS;
64877     }
64878
64879     MA_ASSERT(pExistingDataBuffer->pNode != NULL);  /* <-- If you've triggered this, you've passed in an invalid existing data buffer. */
64880
64881     config = ma_resource_manager_data_source_config_init();
64882     config.flags = pExistingDataBuffer->flags;
64883
64884     return ma_resource_manager_data_buffer_init_ex_internal(pResourceManager, &config, pExistingDataBuffer->pNode->hashedName32, pDataBuffer);
64885 }
64886
64887 static ma_result ma_resource_manager_data_buffer_uninit_internal(ma_resource_manager_data_buffer* pDataBuffer)
64888 {
64889     MA_ASSERT(pDataBuffer != NULL);
64890
64891     /* The connector should be uninitialized first. */
64892     ma_resource_manager_data_buffer_uninit_connector(pDataBuffer->pResourceManager, pDataBuffer);
64893
64894     /* With the connector uninitialized we can unacquire the node. */
64895     ma_resource_manager_data_buffer_node_unacquire(pDataBuffer->pResourceManager, pDataBuffer->pNode, NULL, NULL);
64896
64897     /* The base data source needs to be uninitialized as well. */
64898     ma_data_source_uninit(&pDataBuffer->ds);
64899
64900     return MA_SUCCESS;
64901 }
64902
64903 MA_API ma_result ma_resource_manager_data_buffer_uninit(ma_resource_manager_data_buffer* pDataBuffer)
64904 {
64905     ma_result result;
64906
64907     if (pDataBuffer == NULL) {
64908         return MA_INVALID_ARGS;
64909     }
64910
64911     if (ma_resource_manager_data_buffer_result(pDataBuffer) == MA_SUCCESS) {
64912         /* The data buffer can be deleted synchronously. */
64913         return ma_resource_manager_data_buffer_uninit_internal(pDataBuffer);
64914     } else {
64915         /*
64916         The data buffer needs to be deleted asynchronously because it's still loading. With the status set to MA_UNAVAILABLE, no more pages will
64917         be loaded and the uninitialization should happen fairly quickly. Since the caller owns the data buffer, we need to wait for this event
64918         to get processed before returning.
64919         */
64920         ma_resource_manager_inline_notification notification;
64921         ma_resource_manager_job job;
64922
64923         /*
64924         We need to mark the node as unavailable so we don't try reading from it anymore, but also to
64925         let the loading thread know that it needs to abort it's loading procedure.
64926         */
64927         c89atomic_exchange_i32(&pDataBuffer->result, MA_UNAVAILABLE);
64928
64929         result = ma_resource_manager_inline_notification_init(pDataBuffer->pResourceManager, &notification);
64930         if (result != MA_SUCCESS) {
64931             return result;  /* Failed to create the notification. This should rarely, if ever, happen. */
64932         }
64933
64934         job = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER);
64935         job.order = ma_resource_manager_data_buffer_next_execution_order(pDataBuffer);
64936         job.data.freeDataBuffer.pDataBuffer       = pDataBuffer;
64937         job.data.freeDataBuffer.pDoneNotification = &notification;
64938         job.data.freeDataBuffer.pDoneFence        = NULL;
64939
64940         result = ma_resource_manager_post_job(pDataBuffer->pResourceManager, &job);
64941         if (result != MA_SUCCESS) {
64942             ma_resource_manager_inline_notification_uninit(&notification);
64943             return result;
64944         }
64945
64946         ma_resource_manager_inline_notification_wait_and_uninit(&notification);
64947     }
64948
64949     return result;
64950 }
64951
64952 MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
64953 {
64954     ma_result result = MA_SUCCESS;
64955     ma_uint64 framesRead = 0;
64956     ma_bool32 isDecodedBufferBusy = MA_FALSE;
64957
64958     /* Safety. */
64959     if (pFramesRead != NULL) {
64960         *pFramesRead = 0;
64961     }
64962
64963     if (frameCount == 0) {
64964         return MA_INVALID_ARGS;
64965     }
64966
64967     /*
64968     We cannot be using the data buffer after it's been uninitialized. If you trigger this assert it means you're trying to read from the data buffer after
64969     it's been uninitialized or is in the process of uninitializing.
64970     */
64971     MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE);
64972
64973     /* If the node is not initialized we need to abort with a busy code. */
64974     if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) {
64975         return MA_BUSY; /* Still loading. */
64976     }
64977
64978     if (pDataBuffer->seekToCursorOnNextRead) {
64979         pDataBuffer->seekToCursorOnNextRead = MA_FALSE;
64980
64981         result = ma_data_source_seek_to_pcm_frame(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pDataBuffer->seekTargetInPCMFrames);
64982         if (result != MA_SUCCESS) {
64983             return result;
64984         }
64985     }
64986
64987     /*
64988     For decoded buffers (not paged) we need to check beforehand how many frames we have available. We cannot
64989     exceed this amount. We'll read as much as we can, and then return MA_BUSY.
64990     */
64991     if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_decoded) {
64992         ma_uint64 availableFrames;
64993
64994         isDecodedBufferBusy = (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY);
64995
64996         if (ma_resource_manager_data_buffer_get_available_frames(pDataBuffer, &availableFrames) == MA_SUCCESS) {
64997             /* Don't try reading more than the available frame count. */
64998             if (frameCount > availableFrames) {
64999                 frameCount = availableFrames;
65000
65001                 /*
65002                 If there's no frames available we want to set the status to MA_AT_END. The logic below
65003                 will check if the node is busy, and if so, change it to MA_BUSY. The reason we do this
65004                 is because we don't want to call `ma_data_source_read_pcm_frames()` if the frame count
65005                 is 0 because that'll result in a situation where it's possible MA_AT_END won't get
65006                 returned.
65007                 */
65008                 if (frameCount == 0) {
65009                     result = MA_AT_END;
65010                 }
65011             } else {
65012                 isDecodedBufferBusy = MA_FALSE; /* We have enough frames available in the buffer to avoid a MA_BUSY status. */
65013             }
65014         }
65015     }
65016
65017     /* Don't attempt to read anything if we've got no frames available. */
65018     if (frameCount > 0) {
65019         result = ma_data_source_read_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pFramesOut, frameCount, &framesRead);
65020     }
65021
65022     /*
65023     If we returned MA_AT_END, but the node is still loading, we don't want to return that code or else the caller will interpret the sound
65024     as at the end and terminate decoding.
65025     */
65026     if (result == MA_AT_END) {
65027         if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY) {
65028             result = MA_BUSY;
65029         }
65030     }
65031
65032     if (isDecodedBufferBusy) {
65033         result = MA_BUSY;
65034     }
65035
65036     if (pFramesRead != NULL) {
65037         *pFramesRead = framesRead;
65038     }
65039
65040     if (result == MA_SUCCESS && framesRead == 0) {
65041         result  = MA_AT_END;
65042     }
65043
65044     return result;
65045 }
65046
65047 MA_API ma_result ma_resource_manager_data_buffer_seek_to_pcm_frame(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64 frameIndex)
65048 {
65049     ma_result result;
65050
65051     /* We cannot be using the data source after it's been uninitialized. */
65052     MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE);
65053
65054     /* If we haven't yet got a connector we need to abort. */
65055     if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) {
65056         pDataBuffer->seekTargetInPCMFrames = frameIndex;
65057         pDataBuffer->seekToCursorOnNextRead = MA_TRUE;
65058         return MA_BUSY; /* Still loading. */
65059     }
65060
65061     result = ma_data_source_seek_to_pcm_frame(ma_resource_manager_data_buffer_get_connector(pDataBuffer), frameIndex);
65062     if (result != MA_SUCCESS) {
65063         return result;
65064     }
65065
65066     pDataBuffer->seekTargetInPCMFrames = ~(ma_uint64)0; /* <-- For identification purposes. */
65067     pDataBuffer->seekToCursorOnNextRead = MA_FALSE;
65068
65069     return MA_SUCCESS;
65070 }
65071
65072 MA_API ma_result ma_resource_manager_data_buffer_get_data_format(ma_resource_manager_data_buffer* pDataBuffer, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
65073 {
65074     /* We cannot be using the data source after it's been uninitialized. */
65075     MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE);
65076
65077     switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode))
65078     {
65079         case ma_resource_manager_data_supply_type_encoded:
65080         {
65081             return ma_data_source_get_data_format(&pDataBuffer->connector.decoder, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
65082         };
65083
65084         case ma_resource_manager_data_supply_type_decoded:
65085         {
65086             *pFormat     = pDataBuffer->pNode->data.backend.decoded.format;
65087             *pChannels   = pDataBuffer->pNode->data.backend.decoded.channels;
65088             *pSampleRate = pDataBuffer->pNode->data.backend.decoded.sampleRate;
65089             ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pDataBuffer->pNode->data.backend.decoded.channels);
65090             return MA_SUCCESS;
65091         };
65092
65093         case ma_resource_manager_data_supply_type_decoded_paged:
65094         {
65095             *pFormat     = pDataBuffer->pNode->data.backend.decodedPaged.data.format;
65096             *pChannels   = pDataBuffer->pNode->data.backend.decodedPaged.data.channels;
65097             *pSampleRate = pDataBuffer->pNode->data.backend.decodedPaged.sampleRate;
65098             ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, pDataBuffer->pNode->data.backend.decoded.channels);
65099             return MA_SUCCESS;
65100         };
65101
65102         case ma_resource_manager_data_supply_type_unknown:
65103         {
65104             return MA_BUSY; /* Still loading. */
65105         };
65106
65107         default:
65108         {
65109             /* Unknown supply type. Should never hit this. */
65110             return MA_INVALID_ARGS;
65111         }
65112     }
65113 }
65114
65115 MA_API ma_result ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pCursor)
65116 {
65117     /* We cannot be using the data source after it's been uninitialized. */
65118     MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE);
65119
65120     if (pDataBuffer == NULL || pCursor == NULL) {
65121         return MA_INVALID_ARGS;
65122     }
65123
65124     *pCursor = 0;
65125
65126     switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode))
65127     {
65128         case ma_resource_manager_data_supply_type_encoded:
65129         {
65130             return ma_decoder_get_cursor_in_pcm_frames(&pDataBuffer->connector.decoder, pCursor);
65131         };
65132
65133         case ma_resource_manager_data_supply_type_decoded:
65134         {
65135             return ma_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.buffer, pCursor);
65136         };
65137
65138         case ma_resource_manager_data_supply_type_decoded_paged:
65139         {
65140             return ma_paged_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.pagedBuffer, pCursor);
65141         };
65142
65143         case ma_resource_manager_data_supply_type_unknown:
65144         {
65145             return MA_BUSY;
65146         };
65147
65148         default:
65149         {
65150             return MA_INVALID_ARGS;
65151         }
65152     }
65153 }
65154
65155 MA_API ma_result ma_resource_manager_data_buffer_get_length_in_pcm_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pLength)
65156 {
65157     /* We cannot be using the data source after it's been uninitialized. */
65158     MA_ASSERT(ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) != MA_UNAVAILABLE);
65159
65160     if (pDataBuffer == NULL || pLength == NULL) {
65161         return MA_INVALID_ARGS;
65162     }
65163
65164     if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) {
65165         return MA_BUSY; /* Still loading. */
65166     }
65167
65168     return ma_data_source_get_length_in_pcm_frames(ma_resource_manager_data_buffer_get_connector(pDataBuffer), pLength);
65169 }
65170
65171 MA_API ma_result ma_resource_manager_data_buffer_result(const ma_resource_manager_data_buffer* pDataBuffer)
65172 {
65173     if (pDataBuffer == NULL) {
65174         return MA_INVALID_ARGS;
65175     }
65176
65177     return (ma_result)c89atomic_load_i32((ma_result*)&pDataBuffer->result);    /* Need a naughty const-cast here. */
65178 }
65179
65180 MA_API ma_result ma_resource_manager_data_buffer_set_looping(ma_resource_manager_data_buffer* pDataBuffer, ma_bool32 isLooping)
65181 {
65182     if (pDataBuffer == NULL) {
65183         return MA_INVALID_ARGS;
65184     }
65185
65186     c89atomic_exchange_32(&pDataBuffer->isLooping, isLooping);
65187
65188     /* The looping state needs to be set on the connector as well or else looping won't work when we read audio data. */
65189     ma_data_source_set_looping(ma_resource_manager_data_buffer_get_connector(pDataBuffer), isLooping);
65190
65191     return MA_SUCCESS;
65192 }
65193
65194 MA_API ma_bool32 ma_resource_manager_data_buffer_is_looping(const ma_resource_manager_data_buffer* pDataBuffer)
65195 {
65196     if (pDataBuffer == NULL) {
65197         return MA_FALSE;
65198     }
65199
65200     return c89atomic_load_32((ma_bool32*)&pDataBuffer->isLooping);
65201 }
65202
65203 MA_API ma_result ma_resource_manager_data_buffer_get_available_frames(ma_resource_manager_data_buffer* pDataBuffer, ma_uint64* pAvailableFrames)
65204 {
65205     if (pAvailableFrames == NULL) {
65206         return MA_INVALID_ARGS;
65207     }
65208
65209     *pAvailableFrames = 0;
65210
65211     if (pDataBuffer == NULL) {
65212         return MA_INVALID_ARGS;
65213     }
65214
65215     if (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode) == ma_resource_manager_data_supply_type_unknown) {
65216         if (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY) {
65217             return MA_BUSY;
65218         } else {
65219             return MA_INVALID_OPERATION;    /* No connector. */
65220         }
65221     }
65222
65223     switch (ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode))
65224     {
65225         case ma_resource_manager_data_supply_type_encoded:
65226         {
65227             return ma_decoder_get_available_frames(&pDataBuffer->connector.decoder, pAvailableFrames);
65228         };
65229
65230         case ma_resource_manager_data_supply_type_decoded:
65231         {
65232             return ma_audio_buffer_get_available_frames(&pDataBuffer->connector.buffer, pAvailableFrames);
65233         };
65234
65235         case ma_resource_manager_data_supply_type_decoded_paged:
65236         {
65237             ma_uint64 cursor;
65238             ma_paged_audio_buffer_get_cursor_in_pcm_frames(&pDataBuffer->connector.pagedBuffer, &cursor);
65239
65240             if (pDataBuffer->pNode->data.backend.decodedPaged.decodedFrameCount > cursor) {
65241                 *pAvailableFrames = pDataBuffer->pNode->data.backend.decodedPaged.decodedFrameCount - cursor;
65242             } else {
65243                 *pAvailableFrames = 0;
65244             }
65245
65246             return MA_SUCCESS;
65247         };
65248
65249         case ma_resource_manager_data_supply_type_unknown:
65250         default:
65251         {
65252             /* Unknown supply type. Should never hit this. */
65253             return MA_INVALID_ARGS;
65254         }
65255     }
65256 }
65257
65258 MA_API ma_result ma_resource_manager_register_file(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags)
65259 {
65260     return ma_resource_manager_data_buffer_node_acquire(pResourceManager, pFilePath, NULL, 0, flags, NULL, NULL, NULL, NULL);
65261 }
65262
65263 MA_API ma_result ma_resource_manager_register_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags)
65264 {
65265     return ma_resource_manager_data_buffer_node_acquire(pResourceManager, NULL, pFilePath, 0, flags, NULL, NULL, NULL, NULL);
65266 }
65267
65268
65269 static ma_result ma_resource_manager_register_data(ma_resource_manager* pResourceManager, const char* pName, const wchar_t* pNameW, ma_resource_manager_data_supply* pExistingData)
65270 {
65271     return ma_resource_manager_data_buffer_node_acquire(pResourceManager, pName, pNameW, 0, 0, pExistingData, NULL, NULL, NULL);
65272 }
65273
65274 static ma_result ma_resource_manager_register_decoded_data_internal(ma_resource_manager* pResourceManager, const char* pName, const wchar_t* pNameW, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
65275 {
65276     ma_resource_manager_data_supply data;
65277     data.type                            = ma_resource_manager_data_supply_type_decoded;
65278     data.backend.decoded.pData           = pData;
65279     data.backend.decoded.totalFrameCount = frameCount;
65280     data.backend.decoded.format          = format;
65281     data.backend.decoded.channels        = channels;
65282     data.backend.decoded.sampleRate      = sampleRate;
65283
65284     return ma_resource_manager_register_data(pResourceManager, pName, pNameW, &data);
65285 }
65286
65287 MA_API ma_result ma_resource_manager_register_decoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
65288 {
65289     return ma_resource_manager_register_decoded_data_internal(pResourceManager, pName, NULL, pData, frameCount, format, channels, sampleRate);
65290 }
65291
65292 MA_API ma_result ma_resource_manager_register_decoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, ma_uint64 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
65293 {
65294     return ma_resource_manager_register_decoded_data_internal(pResourceManager, NULL, pName, pData, frameCount, format, channels, sampleRate);
65295 }
65296
65297
65298 static ma_result ma_resource_manager_register_encoded_data_internal(ma_resource_manager* pResourceManager, const char* pName, const wchar_t* pNameW, const void* pData, size_t sizeInBytes)
65299 {
65300     ma_resource_manager_data_supply data;
65301     data.type                        = ma_resource_manager_data_supply_type_encoded;
65302     data.backend.encoded.pData       = pData;
65303     data.backend.encoded.sizeInBytes = sizeInBytes;
65304
65305     return ma_resource_manager_register_data(pResourceManager, pName, pNameW, &data);
65306 }
65307
65308 MA_API ma_result ma_resource_manager_register_encoded_data(ma_resource_manager* pResourceManager, const char* pName, const void* pData, size_t sizeInBytes)
65309 {
65310     return ma_resource_manager_register_encoded_data_internal(pResourceManager, pName, NULL, pData, sizeInBytes);
65311 }
65312
65313 MA_API ma_result ma_resource_manager_register_encoded_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName, const void* pData, size_t sizeInBytes)
65314 {
65315     return ma_resource_manager_register_encoded_data_internal(pResourceManager, NULL, pName, pData, sizeInBytes);
65316 }
65317
65318
65319 MA_API ma_result ma_resource_manager_unregister_file(ma_resource_manager* pResourceManager, const char* pFilePath)
65320 {
65321     return ma_resource_manager_unregister_data(pResourceManager, pFilePath);
65322 }
65323
65324 MA_API ma_result ma_resource_manager_unregister_file_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath)
65325 {
65326     return ma_resource_manager_unregister_data_w(pResourceManager, pFilePath);
65327 }
65328
65329 MA_API ma_result ma_resource_manager_unregister_data(ma_resource_manager* pResourceManager, const char* pName)
65330 {
65331     return ma_resource_manager_data_buffer_node_unacquire(pResourceManager, NULL, pName, NULL);
65332 }
65333
65334 MA_API ma_result ma_resource_manager_unregister_data_w(ma_resource_manager* pResourceManager, const wchar_t* pName)
65335 {
65336     return ma_resource_manager_data_buffer_node_unacquire(pResourceManager, NULL, NULL, pName);
65337 }
65338
65339
65340 static ma_uint32 ma_resource_manager_data_stream_next_execution_order(ma_resource_manager_data_stream* pDataStream)
65341 {
65342     MA_ASSERT(pDataStream != NULL);
65343     return c89atomic_fetch_add_32(&pDataStream->executionCounter, 1);
65344 }
65345
65346 static ma_bool32 ma_resource_manager_data_stream_is_decoder_at_end(const ma_resource_manager_data_stream* pDataStream)
65347 {
65348     MA_ASSERT(pDataStream != NULL);
65349     return c89atomic_load_32((ma_bool32*)&pDataStream->isDecoderAtEnd);
65350 }
65351
65352 static ma_uint32 ma_resource_manager_data_stream_seek_counter(const ma_resource_manager_data_stream* pDataStream)
65353 {
65354     MA_ASSERT(pDataStream != NULL);
65355     return c89atomic_load_32((ma_uint32*)&pDataStream->seekCounter);
65356 }
65357
65358
65359 static ma_result ma_resource_manager_data_stream_cb__read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
65360 {
65361     return ma_resource_manager_data_stream_read_pcm_frames((ma_resource_manager_data_stream*)pDataSource, pFramesOut, frameCount, pFramesRead);
65362 }
65363
65364 static ma_result ma_resource_manager_data_stream_cb__seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex)
65365 {
65366     return ma_resource_manager_data_stream_seek_to_pcm_frame((ma_resource_manager_data_stream*)pDataSource, frameIndex);
65367 }
65368
65369 static ma_result ma_resource_manager_data_stream_cb__get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
65370 {
65371     return ma_resource_manager_data_stream_get_data_format((ma_resource_manager_data_stream*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
65372 }
65373
65374 static ma_result ma_resource_manager_data_stream_cb__get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor)
65375 {
65376     return ma_resource_manager_data_stream_get_cursor_in_pcm_frames((ma_resource_manager_data_stream*)pDataSource, pCursor);
65377 }
65378
65379 static ma_result ma_resource_manager_data_stream_cb__get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength)
65380 {
65381     return ma_resource_manager_data_stream_get_length_in_pcm_frames((ma_resource_manager_data_stream*)pDataSource, pLength);
65382 }
65383
65384 static ma_result ma_resource_manager_data_stream_cb__set_looping(ma_data_source* pDataSource, ma_bool32 isLooping)
65385 {
65386     return ma_resource_manager_data_stream_set_looping((ma_resource_manager_data_stream*)pDataSource, isLooping);
65387 }
65388
65389 static ma_data_source_vtable g_ma_resource_manager_data_stream_vtable =
65390 {
65391     ma_resource_manager_data_stream_cb__read_pcm_frames,
65392     ma_resource_manager_data_stream_cb__seek_to_pcm_frame,
65393     ma_resource_manager_data_stream_cb__get_data_format,
65394     ma_resource_manager_data_stream_cb__get_cursor_in_pcm_frames,
65395     ma_resource_manager_data_stream_cb__get_length_in_pcm_frames,
65396     ma_resource_manager_data_stream_cb__set_looping,
65397     MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT
65398 };
65399
65400 static void ma_resource_manager_data_stream_set_absolute_cursor(ma_resource_manager_data_stream* pDataStream, ma_uint64 absoluteCursor)
65401 {
65402     /* Loop if possible. */
65403     if (absoluteCursor > pDataStream->totalLengthInPCMFrames && pDataStream->totalLengthInPCMFrames > 0) {
65404         absoluteCursor = absoluteCursor % pDataStream->totalLengthInPCMFrames;
65405     }
65406
65407     c89atomic_exchange_64(&pDataStream->absoluteCursor, absoluteCursor);
65408 }
65409
65410 MA_API ma_result ma_resource_manager_data_stream_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_stream* pDataStream)
65411 {
65412     ma_result result;
65413     ma_data_source_config dataSourceConfig;
65414     char* pFilePathCopy = NULL;
65415     wchar_t* pFilePathWCopy = NULL;
65416     ma_resource_manager_job job;
65417     ma_bool32 waitBeforeReturning = MA_FALSE;
65418     ma_resource_manager_inline_notification waitNotification;
65419     ma_resource_manager_pipeline_notifications notifications;
65420
65421     if (pDataStream == NULL) {
65422         if (pConfig != NULL && pConfig->pNotifications != NULL) {
65423             ma_resource_manager_pipeline_notifications_signal_all_notifications(&notifications);
65424         }
65425
65426         return MA_INVALID_ARGS;
65427     }
65428
65429     MA_ZERO_OBJECT(pDataStream);
65430
65431     if (pConfig == NULL) {
65432         return MA_INVALID_ARGS;
65433     }
65434
65435     if (pConfig->pNotifications != NULL) {
65436         notifications = *pConfig->pNotifications;    /* From here on out, `notifications` should be used instead of `pNotifications`. Setting this to NULL to catch any errors at testing time. */
65437     } else {
65438         MA_ZERO_OBJECT(&notifications);
65439     }
65440
65441     dataSourceConfig = ma_data_source_config_init();
65442     dataSourceConfig.vtable = &g_ma_resource_manager_data_stream_vtable;
65443
65444     result = ma_data_source_init(&dataSourceConfig, &pDataStream->ds);
65445     if (result != MA_SUCCESS) {
65446         ma_resource_manager_pipeline_notifications_signal_all_notifications(&notifications);
65447         return result;
65448     }
65449
65450     pDataStream->pResourceManager = pResourceManager;
65451     pDataStream->flags            = pConfig->flags;
65452     pDataStream->result           = MA_BUSY;
65453
65454     ma_data_source_set_range_in_pcm_frames(pDataStream, pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames);
65455     ma_data_source_set_loop_point_in_pcm_frames(pDataStream, pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames);
65456     ma_data_source_set_looping(pDataStream, pConfig->isLooping);
65457
65458     if (pResourceManager == NULL || (pConfig->pFilePath == NULL && pConfig->pFilePathW == NULL)) {
65459         ma_resource_manager_pipeline_notifications_signal_all_notifications(&notifications);
65460         return MA_INVALID_ARGS;
65461     }
65462
65463     /* We want all access to the VFS and the internal decoder to happen on the job thread just to keep things easier to manage for the VFS.  */
65464
65465     /* We need a copy of the file path. We should probably make this more efficient, but for now we'll do a transient memory allocation. */
65466     if (pConfig->pFilePath != NULL) {
65467         pFilePathCopy  = ma_copy_string(pConfig->pFilePath, &pResourceManager->config.allocationCallbacks);
65468     } else {
65469         pFilePathWCopy = ma_copy_string_w(pConfig->pFilePathW, &pResourceManager->config.allocationCallbacks);
65470     }
65471
65472     if (pFilePathCopy == NULL && pFilePathWCopy == NULL) {
65473         ma_resource_manager_pipeline_notifications_signal_all_notifications(&notifications);
65474         return MA_OUT_OF_MEMORY;
65475     }
65476
65477     /*
65478     We need to check for the presence of MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC. If it's not set, we need to wait before returning. Otherwise we
65479     can return immediately. Likewise, we'll also check for MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT and do the same.
65480     */
65481     if ((pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) == 0 || (pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) {
65482         waitBeforeReturning = MA_TRUE;
65483         ma_resource_manager_inline_notification_init(pResourceManager, &waitNotification);
65484     }
65485
65486     ma_resource_manager_pipeline_notifications_acquire_all_fences(&notifications);
65487
65488     /* Set the absolute cursor to our initial seek position so retrieval of the cursor returns a good value. */
65489     ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, pConfig->initialSeekPointInPCMFrames);
65490
65491     /* We now have everything we need to post the job. This is the last thing we need to do from here. The rest will be done by the job thread. */
65492     job = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_LOAD_DATA_STREAM);
65493     job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream);
65494     job.data.loadDataStream.pDataStream       = pDataStream;
65495     job.data.loadDataStream.pFilePath         = pFilePathCopy;
65496     job.data.loadDataStream.pFilePathW        = pFilePathWCopy;
65497     job.data.loadDataStream.initialSeekPoint  = pConfig->initialSeekPointInPCMFrames;
65498     job.data.loadDataStream.pInitNotification = (waitBeforeReturning == MA_TRUE) ? &waitNotification : notifications.init.pNotification;
65499     job.data.loadDataStream.pInitFence        = notifications.init.pFence;
65500     result = ma_resource_manager_post_job(pResourceManager, &job);
65501     if (result != MA_SUCCESS) {
65502         ma_resource_manager_pipeline_notifications_signal_all_notifications(&notifications);
65503         ma_resource_manager_pipeline_notifications_release_all_fences(&notifications);
65504
65505         if (waitBeforeReturning) {
65506             ma_resource_manager_inline_notification_uninit(&waitNotification);
65507         }
65508
65509         ma_free(pFilePathCopy,  &pResourceManager->config.allocationCallbacks);
65510         ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks);
65511         return result;
65512     }
65513
65514     /* Wait if needed. */
65515     if (waitBeforeReturning) {
65516         ma_resource_manager_inline_notification_wait_and_uninit(&waitNotification);
65517
65518         if (notifications.init.pNotification != NULL) {
65519             ma_async_notification_signal(notifications.init.pNotification);
65520         }
65521
65522         /* NOTE: Do not release pInitFence here. That will be done by the job. */
65523     }
65524
65525     return MA_SUCCESS;
65526 }
65527
65528 MA_API ma_result ma_resource_manager_data_stream_init(ma_resource_manager* pResourceManager, const char* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream)
65529 {
65530     ma_resource_manager_data_source_config config;
65531
65532     config = ma_resource_manager_data_source_config_init();
65533     config.pFilePath      = pFilePath;
65534     config.flags          = flags;
65535     config.pNotifications = pNotifications;
65536     
65537     return ma_resource_manager_data_stream_init_ex(pResourceManager, &config, pDataStream);
65538 }
65539
65540 MA_API ma_result ma_resource_manager_data_stream_init_w(ma_resource_manager* pResourceManager, const wchar_t* pFilePath, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_stream* pDataStream)
65541 {
65542     ma_resource_manager_data_source_config config;
65543
65544     config = ma_resource_manager_data_source_config_init();
65545     config.pFilePathW     = pFilePath;
65546     config.flags          = flags;
65547     config.pNotifications = pNotifications;
65548     
65549     return ma_resource_manager_data_stream_init_ex(pResourceManager, &config, pDataStream);
65550 }
65551
65552 MA_API ma_result ma_resource_manager_data_stream_uninit(ma_resource_manager_data_stream* pDataStream)
65553 {
65554     ma_resource_manager_inline_notification freeEvent;
65555     ma_resource_manager_job job;
65556
65557     if (pDataStream == NULL) {
65558         return MA_INVALID_ARGS;
65559     }
65560
65561     /* The first thing to do is set the result to unavailable. This will prevent future page decoding. */
65562     c89atomic_exchange_i32(&pDataStream->result, MA_UNAVAILABLE);
65563
65564     /*
65565     We need to post a job to ensure we're not in the middle or decoding or anything. Because the object is owned by the caller, we'll need
65566     to wait for it to complete before returning which means we need an event.
65567     */
65568     ma_resource_manager_inline_notification_init(pDataStream->pResourceManager, &freeEvent);
65569
65570     job = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_FREE_DATA_STREAM);
65571     job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream);
65572     job.data.freeDataStream.pDataStream       = pDataStream;
65573     job.data.freeDataStream.pDoneNotification = &freeEvent;
65574     job.data.freeDataStream.pDoneFence        = NULL;
65575     ma_resource_manager_post_job(pDataStream->pResourceManager, &job);
65576
65577     /* We need to wait for the job to finish processing before we return. */
65578     ma_resource_manager_inline_notification_wait_and_uninit(&freeEvent);
65579
65580     return MA_SUCCESS;
65581 }
65582
65583
65584 static ma_uint32 ma_resource_manager_data_stream_get_page_size_in_frames(ma_resource_manager_data_stream* pDataStream)
65585 {
65586     MA_ASSERT(pDataStream != NULL);
65587     MA_ASSERT(pDataStream->isDecoderInitialized == MA_TRUE);
65588
65589     return MA_RESOURCE_MANAGER_PAGE_SIZE_IN_MILLISECONDS * (pDataStream->decoder.outputSampleRate/1000);
65590 }
65591
65592 static void* ma_resource_manager_data_stream_get_page_data_pointer(ma_resource_manager_data_stream* pDataStream, ma_uint32 pageIndex, ma_uint32 relativeCursor)
65593 {
65594     MA_ASSERT(pDataStream != NULL);
65595     MA_ASSERT(pDataStream->isDecoderInitialized == MA_TRUE);
65596     MA_ASSERT(pageIndex == 0 || pageIndex == 1);
65597
65598     return ma_offset_ptr(pDataStream->pPageData, ((ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream) * pageIndex) + relativeCursor) * ma_get_bytes_per_frame(pDataStream->decoder.outputFormat, pDataStream->decoder.outputChannels));
65599 }
65600
65601 static void ma_resource_manager_data_stream_fill_page(ma_resource_manager_data_stream* pDataStream, ma_uint32 pageIndex)
65602 {
65603     ma_result result = MA_SUCCESS;
65604     ma_uint64 pageSizeInFrames;
65605     ma_uint64 totalFramesReadForThisPage = 0;
65606     void* pPageData = ma_resource_manager_data_stream_get_page_data_pointer(pDataStream, pageIndex, 0);
65607
65608     pageSizeInFrames = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream);
65609
65610     /* The decoder needs to inherit the stream's looping and range state. */
65611     {
65612         ma_uint64 rangeBeg;
65613         ma_uint64 rangeEnd;
65614         ma_uint64 loopPointBeg;
65615         ma_uint64 loopPointEnd;
65616
65617         ma_data_source_set_looping(&pDataStream->decoder, ma_resource_manager_data_stream_is_looping(pDataStream));
65618
65619         ma_data_source_get_range_in_pcm_frames(pDataStream, &rangeBeg, &rangeEnd);
65620         ma_data_source_set_range_in_pcm_frames(&pDataStream->decoder, rangeBeg, rangeEnd);
65621
65622         ma_data_source_get_loop_point_in_pcm_frames(pDataStream, &loopPointBeg, &loopPointEnd);
65623         ma_data_source_set_loop_point_in_pcm_frames(&pDataStream->decoder, loopPointBeg, loopPointEnd);
65624     }
65625
65626     /* Just read straight from the decoder. It will deal with ranges and looping for us. */
65627     result = ma_data_source_read_pcm_frames(&pDataStream->decoder, pPageData, pageSizeInFrames, &totalFramesReadForThisPage);
65628     if (result == MA_AT_END || totalFramesReadForThisPage < pageSizeInFrames) {
65629         c89atomic_exchange_32(&pDataStream->isDecoderAtEnd, MA_TRUE);
65630     }
65631
65632     c89atomic_exchange_32(&pDataStream->pageFrameCount[pageIndex], (ma_uint32)totalFramesReadForThisPage);
65633     c89atomic_exchange_32(&pDataStream->isPageValid[pageIndex], MA_TRUE);
65634 }
65635
65636 static void ma_resource_manager_data_stream_fill_pages(ma_resource_manager_data_stream* pDataStream)
65637 {
65638     ma_uint32 iPage;
65639
65640     MA_ASSERT(pDataStream != NULL);
65641
65642     for (iPage = 0; iPage < 2; iPage += 1) {
65643         ma_resource_manager_data_stream_fill_page(pDataStream, iPage);
65644     }
65645 }
65646
65647
65648 static ma_result ma_resource_manager_data_stream_map(ma_resource_manager_data_stream* pDataStream, void** ppFramesOut, ma_uint64* pFrameCount)
65649 {
65650     ma_uint64 framesAvailable;
65651     ma_uint64 frameCount = 0;
65652
65653     /* We cannot be using the data source after it's been uninitialized. */
65654     MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE);
65655
65656     if (pFrameCount != NULL) {
65657         frameCount = *pFrameCount;
65658         *pFrameCount = 0;
65659     }
65660     if (ppFramesOut != NULL) {
65661         *ppFramesOut = NULL;
65662     }
65663
65664     if (pDataStream == NULL || ppFramesOut == NULL || pFrameCount == NULL) {
65665         return MA_INVALID_ARGS;
65666     }
65667
65668     if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) {
65669         return MA_INVALID_OPERATION;
65670     }
65671
65672     /* Don't attempt to read while we're in the middle of seeking. Tell the caller that we're busy. */
65673     if (ma_resource_manager_data_stream_seek_counter(pDataStream) > 0) {
65674         return MA_BUSY;
65675     }
65676
65677     /* If the page we're on is invalid it means we've caught up to the job thread. */
65678     if (c89atomic_load_32(&pDataStream->isPageValid[pDataStream->currentPageIndex]) == MA_FALSE) {
65679         framesAvailable = 0;
65680     } else {
65681         /*
65682         The page we're on is valid so we must have some frames available. We need to make sure that we don't overflow into the next page, even if it's valid. The reason is
65683         that the unmap process will only post an update for one page at a time. Keeping mapping tied to page boundaries makes this simpler.
65684         */
65685         ma_uint32 currentPageFrameCount = c89atomic_load_32(&pDataStream->pageFrameCount[pDataStream->currentPageIndex]);
65686         MA_ASSERT(currentPageFrameCount >= pDataStream->relativeCursor);
65687
65688         framesAvailable = currentPageFrameCount - pDataStream->relativeCursor;
65689     }
65690
65691     /* If there's no frames available and the result is set to MA_AT_END we need to return MA_AT_END. */
65692     if (framesAvailable == 0) {
65693         if (ma_resource_manager_data_stream_is_decoder_at_end(pDataStream)) {
65694             return MA_AT_END;
65695         } else {
65696             return MA_BUSY; /* There are no frames available, but we're not marked as EOF so we might have caught up to the job thread. Need to return MA_BUSY and wait for more data. */
65697         }
65698     }
65699
65700     MA_ASSERT(framesAvailable > 0);
65701
65702     if (frameCount > framesAvailable) {
65703         frameCount = framesAvailable;
65704     }
65705
65706     *ppFramesOut = ma_resource_manager_data_stream_get_page_data_pointer(pDataStream, pDataStream->currentPageIndex, pDataStream->relativeCursor);
65707     *pFrameCount = frameCount;
65708
65709     return MA_SUCCESS;
65710 }
65711
65712 static ma_result ma_resource_manager_data_stream_unmap(ma_resource_manager_data_stream* pDataStream, ma_uint64 frameCount)
65713 {
65714     ma_uint32 newRelativeCursor;
65715     ma_uint32 pageSizeInFrames;
65716     ma_resource_manager_job job;
65717
65718     /* We cannot be using the data source after it's been uninitialized. */
65719     MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE);
65720
65721     if (pDataStream == NULL) {
65722         return MA_INVALID_ARGS;
65723     }
65724
65725     if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) {
65726         return MA_INVALID_OPERATION;
65727     }
65728
65729     /* The frame count should always fit inside a 32-bit integer. */
65730     if (frameCount > 0xFFFFFFFF) {
65731         return MA_INVALID_ARGS;
65732     }
65733
65734     pageSizeInFrames = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream);
65735
65736     /* The absolute cursor needs to be updated for ma_resource_manager_data_stream_get_cursor_in_pcm_frames(). */
65737     ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, c89atomic_load_64(&pDataStream->absoluteCursor) + frameCount);
65738
65739     /* Here is where we need to check if we need to load a new page, and if so, post a job to load it. */
65740     newRelativeCursor = pDataStream->relativeCursor + (ma_uint32)frameCount;
65741
65742     /* If the new cursor has flowed over to the next page we need to mark the old one as invalid and post an event for it. */
65743     if (newRelativeCursor >= pageSizeInFrames) {
65744         newRelativeCursor -= pageSizeInFrames;
65745
65746         /* Here is where we post the job start decoding. */
65747         job = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_PAGE_DATA_STREAM);
65748         job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream);
65749         job.data.pageDataStream.pDataStream = pDataStream;
65750         job.data.pageDataStream.pageIndex   = pDataStream->currentPageIndex;
65751
65752         /* The page needs to be marked as invalid so that the public API doesn't try reading from it. */
65753         c89atomic_exchange_32(&pDataStream->isPageValid[pDataStream->currentPageIndex], MA_FALSE);
65754
65755         /* Before posting the job we need to make sure we set some state. */
65756         pDataStream->relativeCursor   = newRelativeCursor;
65757         pDataStream->currentPageIndex = (pDataStream->currentPageIndex + 1) & 0x01;
65758         return ma_resource_manager_post_job(pDataStream->pResourceManager, &job);
65759     } else {
65760         /* We haven't moved into a new page so we can just move the cursor forward. */
65761         pDataStream->relativeCursor = newRelativeCursor;
65762         return MA_SUCCESS;
65763     }
65764 }
65765
65766
65767 MA_API ma_result ma_resource_manager_data_stream_read_pcm_frames(ma_resource_manager_data_stream* pDataStream, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
65768 {
65769     ma_result result = MA_SUCCESS;
65770     ma_uint64 totalFramesProcessed;
65771     ma_format format;
65772     ma_uint32 channels;
65773
65774     /* Safety. */
65775     if (pFramesRead != NULL) {
65776         *pFramesRead = 0;
65777     }
65778
65779     if (frameCount == 0) {
65780         return MA_INVALID_ARGS;
65781     }
65782
65783     /* We cannot be using the data source after it's been uninitialized. */
65784     MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE);
65785
65786     if (pDataStream == NULL) {
65787         return MA_INVALID_ARGS;
65788     }
65789
65790     if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) {
65791         return MA_INVALID_OPERATION;
65792     }
65793
65794     /* Don't attempt to read while we're in the middle of seeking. Tell the caller that we're busy. */
65795     if (ma_resource_manager_data_stream_seek_counter(pDataStream) > 0) {
65796         return MA_BUSY;
65797     }
65798
65799     ma_resource_manager_data_stream_get_data_format(pDataStream, &format, &channels, NULL, NULL, 0);
65800
65801     /* Reading is implemented in terms of map/unmap. We need to run this in a loop because mapping is clamped against page boundaries. */
65802     totalFramesProcessed = 0;
65803     while (totalFramesProcessed < frameCount) {
65804         void* pMappedFrames;
65805         ma_uint64 mappedFrameCount;
65806
65807         mappedFrameCount = frameCount - totalFramesProcessed;
65808         result = ma_resource_manager_data_stream_map(pDataStream, &pMappedFrames, &mappedFrameCount);
65809         if (result != MA_SUCCESS) {
65810             break;
65811         }
65812
65813         /* Copy the mapped data to the output buffer if we have one. It's allowed for pFramesOut to be NULL in which case a relative forward seek is performed. */
65814         if (pFramesOut != NULL) {
65815             ma_copy_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesProcessed, format, channels), pMappedFrames, mappedFrameCount, format, channels);
65816         }
65817
65818         totalFramesProcessed += mappedFrameCount;
65819
65820         result = ma_resource_manager_data_stream_unmap(pDataStream, mappedFrameCount);
65821         if (result != MA_SUCCESS) {
65822             break;  /* This is really bad - will only get an error here if we failed to post a job to the queue for loading the next page. */
65823         }
65824     }
65825
65826     if (pFramesRead != NULL) {
65827         *pFramesRead = totalFramesProcessed;
65828     }
65829
65830     if (result == MA_SUCCESS && totalFramesProcessed == 0) {
65831         result  = MA_AT_END;
65832     }
65833
65834     return result;
65835 }
65836
65837 MA_API ma_result ma_resource_manager_data_stream_seek_to_pcm_frame(ma_resource_manager_data_stream* pDataStream, ma_uint64 frameIndex)
65838 {
65839     ma_resource_manager_job job;
65840     ma_result streamResult;
65841
65842     streamResult = ma_resource_manager_data_stream_result(pDataStream);
65843
65844     /* We cannot be using the data source after it's been uninitialized. */
65845     MA_ASSERT(streamResult != MA_UNAVAILABLE);
65846
65847     if (pDataStream == NULL) {
65848         return MA_INVALID_ARGS;
65849     }
65850
65851     if (streamResult != MA_SUCCESS && streamResult != MA_BUSY) {
65852         return MA_INVALID_OPERATION;
65853     }
65854
65855     /* Increment the seek counter first to indicate to read_paged_pcm_frames() and map_paged_pcm_frames() that we are in the middle of a seek and MA_BUSY should be returned. */
65856     c89atomic_fetch_add_32(&pDataStream->seekCounter, 1);
65857
65858     /* Update the absolute cursor so that ma_resource_manager_data_stream_get_cursor_in_pcm_frames() returns the new position. */
65859     ma_resource_manager_data_stream_set_absolute_cursor(pDataStream, frameIndex);
65860
65861     /*
65862     We need to clear our currently loaded pages so that the stream starts playback from the new seek point as soon as possible. These are for the purpose of the public
65863     API and will be ignored by the seek job. The seek job will operate on the assumption that both pages have been marked as invalid and the cursor is at the start of
65864     the first page.
65865     */
65866     pDataStream->relativeCursor   = 0;
65867     pDataStream->currentPageIndex = 0;
65868     c89atomic_exchange_32(&pDataStream->isPageValid[0], MA_FALSE);
65869     c89atomic_exchange_32(&pDataStream->isPageValid[1], MA_FALSE);
65870
65871     /* Make sure the data stream is not marked as at the end or else if we seek in response to hitting the end, we won't be able to read any more data. */
65872     c89atomic_exchange_32(&pDataStream->isDecoderAtEnd, MA_FALSE);
65873
65874     /*
65875     The public API is not allowed to touch the internal decoder so we need to use a job to perform the seek. When seeking, the job thread will assume both pages
65876     are invalid and any content contained within them will be discarded and replaced with newly decoded data.
65877     */
65878     job = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_SEEK_DATA_STREAM);
65879     job.order = ma_resource_manager_data_stream_next_execution_order(pDataStream);
65880     job.data.seekDataStream.pDataStream = pDataStream;
65881     job.data.seekDataStream.frameIndex  = frameIndex;
65882     return ma_resource_manager_post_job(pDataStream->pResourceManager, &job);
65883 }
65884
65885 MA_API ma_result ma_resource_manager_data_stream_get_data_format(ma_resource_manager_data_stream* pDataStream, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
65886 {
65887     /* We cannot be using the data source after it's been uninitialized. */
65888     MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE);
65889
65890     if (pFormat != NULL) {
65891         *pFormat = ma_format_unknown;
65892     }
65893
65894     if (pChannels != NULL) {
65895         *pChannels = 0;
65896     }
65897
65898     if (pSampleRate != NULL) {
65899         *pSampleRate = 0;
65900     }
65901
65902     if (pChannelMap != NULL) {
65903         MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
65904     }
65905
65906     if (pDataStream == NULL) {
65907         return MA_INVALID_ARGS;
65908     }
65909
65910     if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) {
65911         return MA_INVALID_OPERATION;
65912     }
65913
65914     /*
65915     We're being a little bit naughty here and accessing the internal decoder from the public API. The output data format is constant, and we've defined this function
65916     such that the application is responsible for ensuring it's not called while uninitializing so it should be safe.
65917     */
65918     return ma_data_source_get_data_format(&pDataStream->decoder, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
65919 }
65920
65921 MA_API ma_result ma_resource_manager_data_stream_get_cursor_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pCursor)
65922 {
65923     ma_result result;
65924
65925     if (pCursor == NULL) {
65926         return MA_INVALID_ARGS;
65927     }
65928
65929     *pCursor = 0;
65930
65931     /* We cannot be using the data source after it's been uninitialized. */
65932     MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) != MA_UNAVAILABLE);
65933
65934     if (pDataStream == NULL) {
65935         return MA_INVALID_ARGS;
65936     }
65937
65938     /*
65939     If the stream is in an erroneous state we need to return an invalid operation. We can allow
65940     this to be called when the data stream is in a busy state because the caller may have asked
65941     for an initial seek position and it's convenient to return that as the cursor position.
65942     */
65943     result = ma_resource_manager_data_stream_result(pDataStream);
65944     if (result != MA_SUCCESS && result != MA_BUSY) {
65945         return MA_INVALID_OPERATION;
65946     }
65947
65948     *pCursor = c89atomic_load_64(&pDataStream->absoluteCursor);
65949
65950     return MA_SUCCESS;
65951 }
65952
65953 MA_API ma_result ma_resource_manager_data_stream_get_length_in_pcm_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pLength)
65954 {
65955     ma_result streamResult;
65956
65957     if (pLength == NULL) {
65958         return MA_INVALID_ARGS;
65959     }
65960
65961     *pLength = 0;
65962
65963     streamResult = ma_resource_manager_data_stream_result(pDataStream);
65964
65965     /* We cannot be using the data source after it's been uninitialized. */
65966     MA_ASSERT(streamResult != MA_UNAVAILABLE);
65967
65968     if (pDataStream == NULL) {
65969         return MA_INVALID_ARGS;
65970     }
65971
65972     if (streamResult != MA_SUCCESS) {
65973         return streamResult;
65974     }
65975
65976     /*
65977     We most definitely do not want to be calling ma_decoder_get_length_in_pcm_frames() directly. Instead we want to use a cached value that we
65978     calculated when we initialized it on the job thread.
65979     */
65980     *pLength = pDataStream->totalLengthInPCMFrames;
65981     if (*pLength == 0) {
65982         return MA_NOT_IMPLEMENTED;  /* Some decoders may not have a known length. */
65983     }
65984
65985     return MA_SUCCESS;
65986 }
65987
65988 MA_API ma_result ma_resource_manager_data_stream_result(const ma_resource_manager_data_stream* pDataStream)
65989 {
65990     if (pDataStream == NULL) {
65991         return MA_INVALID_ARGS;
65992     }
65993
65994     return (ma_result)c89atomic_load_i32(&pDataStream->result);
65995 }
65996
65997 MA_API ma_result ma_resource_manager_data_stream_set_looping(ma_resource_manager_data_stream* pDataStream, ma_bool32 isLooping)
65998 {
65999     if (pDataStream == NULL) {
66000         return MA_INVALID_ARGS;
66001     }
66002
66003     c89atomic_exchange_32(&pDataStream->isLooping, isLooping);
66004
66005     return MA_SUCCESS;
66006 }
66007
66008 MA_API ma_bool32 ma_resource_manager_data_stream_is_looping(const ma_resource_manager_data_stream* pDataStream)
66009 {
66010     if (pDataStream == NULL) {
66011         return MA_FALSE;
66012     }
66013
66014     return c89atomic_load_32((ma_bool32*)&pDataStream->isLooping);   /* Naughty const-cast. Value won't change from here in practice (maybe from another thread). */
66015 }
66016
66017 MA_API ma_result ma_resource_manager_data_stream_get_available_frames(ma_resource_manager_data_stream* pDataStream, ma_uint64* pAvailableFrames)
66018 {
66019     ma_uint32 pageIndex0;
66020     ma_uint32 pageIndex1;
66021     ma_uint32 relativeCursor;
66022     ma_uint64 availableFrames;
66023
66024     if (pAvailableFrames == NULL) {
66025         return MA_INVALID_ARGS;
66026     }
66027
66028     *pAvailableFrames = 0;
66029
66030     if (pDataStream == NULL) {
66031         return MA_INVALID_ARGS;
66032     }
66033
66034     pageIndex0     =  pDataStream->currentPageIndex;
66035     pageIndex1     = (pDataStream->currentPageIndex + 1) & 0x01;
66036     relativeCursor =  pDataStream->relativeCursor;
66037
66038     availableFrames = 0;
66039     if (c89atomic_load_32(&pDataStream->isPageValid[pageIndex0])) {
66040         availableFrames += c89atomic_load_32(&pDataStream->pageFrameCount[pageIndex0]) - relativeCursor;
66041         if (c89atomic_load_32(&pDataStream->isPageValid[pageIndex1])) {
66042             availableFrames += c89atomic_load_32(&pDataStream->pageFrameCount[pageIndex1]);
66043         }
66044     }
66045
66046     *pAvailableFrames = availableFrames;
66047     return MA_SUCCESS;
66048 }
66049
66050
66051 static ma_result ma_resource_manager_data_source_preinit(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_source* pDataSource)
66052 {
66053     if (pDataSource == NULL) {
66054         return MA_INVALID_ARGS;
66055     }
66056
66057     MA_ZERO_OBJECT(pDataSource);
66058
66059     if (pConfig == NULL) {
66060         return MA_INVALID_ARGS;
66061     }
66062
66063     if (pResourceManager == NULL) {
66064         return MA_INVALID_ARGS;
66065     }
66066
66067     pDataSource->flags = pConfig->flags;
66068
66069     return MA_SUCCESS;
66070 }
66071
66072 MA_API ma_result ma_resource_manager_data_source_init_ex(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source_config* pConfig, ma_resource_manager_data_source* pDataSource)
66073 {
66074     ma_result result;
66075
66076     result = ma_resource_manager_data_source_preinit(pResourceManager, pConfig, pDataSource);
66077     if (result != MA_SUCCESS) {
66078         return result;
66079     }
66080
66081     /* The data source itself is just a data stream or a data buffer. */
66082     if ((pConfig->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66083         return ma_resource_manager_data_stream_init_ex(pResourceManager, pConfig, &pDataSource->backend.stream);
66084     } else {
66085         return ma_resource_manager_data_buffer_init_ex(pResourceManager, pConfig, &pDataSource->backend.buffer);
66086     }
66087 }
66088
66089 MA_API ma_result ma_resource_manager_data_source_init(ma_resource_manager* pResourceManager, const char* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource)
66090 {
66091     ma_resource_manager_data_source_config config;
66092
66093     config = ma_resource_manager_data_source_config_init();
66094     config.pFilePath      = pName;
66095     config.flags          = flags;
66096     config.pNotifications = pNotifications;
66097
66098     return ma_resource_manager_data_source_init_ex(pResourceManager, &config, pDataSource);
66099 }
66100
66101 MA_API ma_result ma_resource_manager_data_source_init_w(ma_resource_manager* pResourceManager, const wchar_t* pName, ma_uint32 flags, const ma_resource_manager_pipeline_notifications* pNotifications, ma_resource_manager_data_source* pDataSource)
66102 {
66103     ma_resource_manager_data_source_config config;
66104
66105     config = ma_resource_manager_data_source_config_init();
66106     config.pFilePathW     = pName;
66107     config.flags          = flags;
66108     config.pNotifications = pNotifications;
66109
66110     return ma_resource_manager_data_source_init_ex(pResourceManager, &config, pDataSource);
66111 }
66112
66113 MA_API ma_result ma_resource_manager_data_source_init_copy(ma_resource_manager* pResourceManager, const ma_resource_manager_data_source* pExistingDataSource, ma_resource_manager_data_source* pDataSource)
66114 {
66115     ma_result result;
66116     ma_resource_manager_data_source_config config;
66117
66118     if (pExistingDataSource == NULL) {
66119         return MA_INVALID_ARGS;
66120     }
66121
66122     config = ma_resource_manager_data_source_config_init();
66123     config.flags = pExistingDataSource->flags;
66124
66125     result = ma_resource_manager_data_source_preinit(pResourceManager, &config, pDataSource);
66126     if (result != MA_SUCCESS) {
66127         return result;
66128     }
66129
66130     /* Copying can only be done from data buffers. Streams cannot be copied. */
66131     if ((pExistingDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66132         return MA_INVALID_OPERATION;
66133     }
66134
66135     return ma_resource_manager_data_buffer_init_copy(pResourceManager, &pExistingDataSource->backend.buffer, &pDataSource->backend.buffer);
66136 }
66137
66138 MA_API ma_result ma_resource_manager_data_source_uninit(ma_resource_manager_data_source* pDataSource)
66139 {
66140     if (pDataSource == NULL) {
66141         return MA_INVALID_ARGS;
66142     }
66143
66144     /* All we need to is uninitialize the underlying data buffer or data stream. */
66145     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66146         return ma_resource_manager_data_stream_uninit(&pDataSource->backend.stream);
66147     } else {
66148         return ma_resource_manager_data_buffer_uninit(&pDataSource->backend.buffer);
66149     }
66150 }
66151
66152 MA_API ma_result ma_resource_manager_data_source_read_pcm_frames(ma_resource_manager_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
66153 {
66154     /* Safety. */
66155     if (pFramesRead != NULL) {
66156         *pFramesRead = 0;
66157     }
66158
66159     if (pDataSource == NULL) {
66160         return MA_INVALID_ARGS;
66161     }
66162
66163     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66164         return ma_resource_manager_data_stream_read_pcm_frames(&pDataSource->backend.stream, pFramesOut, frameCount, pFramesRead);
66165     } else {
66166         return ma_resource_manager_data_buffer_read_pcm_frames(&pDataSource->backend.buffer, pFramesOut, frameCount, pFramesRead);
66167     }
66168 }
66169
66170 MA_API ma_result ma_resource_manager_data_source_seek_to_pcm_frame(ma_resource_manager_data_source* pDataSource, ma_uint64 frameIndex)
66171 {
66172     if (pDataSource == NULL) {
66173         return MA_INVALID_ARGS;
66174     }
66175
66176     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66177         return ma_resource_manager_data_stream_seek_to_pcm_frame(&pDataSource->backend.stream, frameIndex);
66178     } else {
66179         return ma_resource_manager_data_buffer_seek_to_pcm_frame(&pDataSource->backend.buffer, frameIndex);
66180     }
66181 }
66182
66183 MA_API ma_result ma_resource_manager_data_source_map(ma_resource_manager_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount)
66184 {
66185     if (pDataSource == NULL) {
66186         return MA_INVALID_ARGS;
66187     }
66188
66189     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66190         return ma_resource_manager_data_stream_map(&pDataSource->backend.stream, ppFramesOut, pFrameCount);
66191     } else {
66192         return MA_NOT_IMPLEMENTED;  /* Mapping not supported with data buffers. */
66193     }
66194 }
66195
66196 MA_API ma_result ma_resource_manager_data_source_unmap(ma_resource_manager_data_source* pDataSource, ma_uint64 frameCount)
66197 {
66198     if (pDataSource == NULL) {
66199         return MA_INVALID_ARGS;
66200     }
66201
66202     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66203         return ma_resource_manager_data_stream_unmap(&pDataSource->backend.stream, frameCount);
66204     } else {
66205         return MA_NOT_IMPLEMENTED;  /* Mapping not supported with data buffers. */
66206     }
66207 }
66208
66209 MA_API ma_result ma_resource_manager_data_source_get_data_format(ma_resource_manager_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
66210 {
66211     if (pDataSource == NULL) {
66212         return MA_INVALID_ARGS;
66213     }
66214
66215     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66216         return ma_resource_manager_data_stream_get_data_format(&pDataSource->backend.stream, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
66217     } else {
66218         return ma_resource_manager_data_buffer_get_data_format(&pDataSource->backend.buffer, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
66219     }
66220 }
66221
66222 MA_API ma_result ma_resource_manager_data_source_get_cursor_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pCursor)
66223 {
66224     if (pDataSource == NULL) {
66225         return MA_INVALID_ARGS;
66226     }
66227
66228     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66229         return ma_resource_manager_data_stream_get_cursor_in_pcm_frames(&pDataSource->backend.stream, pCursor);
66230     } else {
66231         return ma_resource_manager_data_buffer_get_cursor_in_pcm_frames(&pDataSource->backend.buffer, pCursor);
66232     }
66233 }
66234
66235 MA_API ma_result ma_resource_manager_data_source_get_length_in_pcm_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pLength)
66236 {
66237     if (pDataSource == NULL) {
66238         return MA_INVALID_ARGS;
66239     }
66240
66241     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66242         return ma_resource_manager_data_stream_get_length_in_pcm_frames(&pDataSource->backend.stream, pLength);
66243     } else {
66244         return ma_resource_manager_data_buffer_get_length_in_pcm_frames(&pDataSource->backend.buffer, pLength);
66245     }
66246 }
66247
66248 MA_API ma_result ma_resource_manager_data_source_result(const ma_resource_manager_data_source* pDataSource)
66249 {
66250     if (pDataSource == NULL) {
66251         return MA_INVALID_ARGS;
66252     }
66253
66254     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66255         return ma_resource_manager_data_stream_result(&pDataSource->backend.stream);
66256     } else {
66257         return ma_resource_manager_data_buffer_result(&pDataSource->backend.buffer);
66258     }
66259 }
66260
66261 MA_API ma_result ma_resource_manager_data_source_set_looping(ma_resource_manager_data_source* pDataSource, ma_bool32 isLooping)
66262 {
66263     if (pDataSource == NULL) {
66264         return MA_INVALID_ARGS;
66265     }
66266
66267     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66268         return ma_resource_manager_data_stream_set_looping(&pDataSource->backend.stream, isLooping);
66269     } else {
66270         return ma_resource_manager_data_buffer_set_looping(&pDataSource->backend.buffer, isLooping);
66271     }
66272 }
66273
66274 MA_API ma_bool32 ma_resource_manager_data_source_is_looping(const ma_resource_manager_data_source* pDataSource)
66275 {
66276     if (pDataSource == NULL) {
66277         return MA_FALSE;
66278     }
66279
66280     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66281         return ma_resource_manager_data_stream_is_looping(&pDataSource->backend.stream);
66282     } else {
66283         return ma_resource_manager_data_buffer_is_looping(&pDataSource->backend.buffer);
66284     }
66285 }
66286
66287 MA_API ma_result ma_resource_manager_data_source_get_available_frames(ma_resource_manager_data_source* pDataSource, ma_uint64* pAvailableFrames)
66288 {
66289     if (pAvailableFrames == NULL) {
66290         return MA_INVALID_ARGS;
66291     }
66292
66293     *pAvailableFrames = 0;
66294
66295     if (pDataSource == NULL) {
66296         return MA_INVALID_ARGS;
66297     }
66298
66299     if ((pDataSource->flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM) != 0) {
66300         return ma_resource_manager_data_stream_get_available_frames(&pDataSource->backend.stream, pAvailableFrames);
66301     } else {
66302         return ma_resource_manager_data_buffer_get_available_frames(&pDataSource->backend.buffer, pAvailableFrames);
66303     }
66304 }
66305
66306
66307 MA_API ma_result ma_resource_manager_post_job(ma_resource_manager* pResourceManager, const ma_resource_manager_job* pJob)
66308 {
66309     if (pResourceManager == NULL) {
66310         return MA_INVALID_ARGS;
66311     }
66312
66313     return ma_resource_manager_job_queue_post(&pResourceManager->jobQueue, pJob);
66314 }
66315
66316 MA_API ma_result ma_resource_manager_post_job_quit(ma_resource_manager* pResourceManager)
66317 {
66318     ma_resource_manager_job job = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_QUIT);
66319     return ma_resource_manager_post_job(pResourceManager, &job);
66320 }
66321
66322 MA_API ma_result ma_resource_manager_next_job(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob)
66323 {
66324     if (pResourceManager == NULL) {
66325         return MA_INVALID_ARGS;
66326     }
66327
66328     return ma_resource_manager_job_queue_next(&pResourceManager->jobQueue, pJob);
66329 }
66330
66331
66332 static ma_result ma_resource_manager_process_job__load_data_buffer_node(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob)
66333 {
66334     ma_result result = MA_SUCCESS;
66335     ma_resource_manager_data_buffer_node* pDataBufferNode;
66336
66337     MA_ASSERT(pResourceManager != NULL);
66338     MA_ASSERT(pJob != NULL);
66339
66340     pDataBufferNode = pJob->data.loadDataBufferNode.pDataBufferNode;
66341
66342     MA_ASSERT(pDataBufferNode != NULL);
66343     MA_ASSERT(pDataBufferNode->isDataOwnedByResourceManager == MA_TRUE);  /* The data should always be owned by the resource manager. */
66344
66345     /* The data buffer is not getting deleted, but we may be getting executed out of order. If so, we need to push the job back onto the queue and return. */
66346     if (pJob->order != c89atomic_load_32(&pDataBufferNode->executionPointer)) {
66347         return ma_resource_manager_post_job(pResourceManager, pJob);    /* Attempting to execute out of order. Probably interleaved with a MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER job. */
66348     }
66349
66350     /* First thing we need to do is check whether or not the data buffer is getting deleted. If so we just abort. */
66351     if (ma_resource_manager_data_buffer_node_result(pDataBufferNode) != MA_BUSY) {
66352         result = ma_resource_manager_data_buffer_node_result(pDataBufferNode);    /* The data buffer may be getting deleted before it's even been loaded. */
66353         goto done;
66354     }
66355
66356     /*
66357     We're ready to start loading. Essentially what we're doing here is initializing the data supply
66358     of the node. Once this is complete, data buffers can have their connectors initialized which
66359     will allow then to have audio data read from them.
66360
66361     Note that when the data supply type has been moved away from "unknown", that is when other threads
66362     will determine that the node is available for data delivery and the data buffer connectors can be
66363     initialized. Therefore, it's important that it is set after the data supply has been initialized.
66364     */
66365     if (pJob->data.loadDataBufferNode.decode) {
66366         /*
66367         Decoding. This is the complex case because we're not going to be doing the entire decoding
66368         process here. Instead it's going to be split of multiple jobs and loaded in pages. The
66369         reason for this is to evenly distribute decoding time across multiple sounds, rather than
66370         having one huge sound hog all the available processing resources.
66371
66372         The first thing we do is initialize a decoder. This is allocated on the heap and is passed
66373         around to the paging jobs. When the last paging job has completed it's processing, it'll
66374         free the decoder for us.
66375
66376         This job does not do any actual decoding. It instead just posts a PAGE_DATA_BUFFER_NODE job
66377         which is where the actual decoding work will be done. However, once this job is complete,
66378         the node will be in a state where data buffer connectors can be initialized.
66379         */
66380         ma_decoder* pDecoder;   /* <-- Free'd on the last page decode. */
66381         ma_resource_manager_job pageDataBufferNodeJob;
66382
66383         /* Allocate the decoder by initializing a decoded data supply. */
66384         result = ma_resource_manager_data_buffer_node_init_supply_decoded(pResourceManager, pDataBufferNode, pJob->data.loadDataBufferNode.pFilePath, pJob->data.loadDataBufferNode.pFilePathW, &pDecoder);
66385
66386         /*
66387         Don't ever propagate an MA_BUSY result code or else the resource manager will think the
66388         node is just busy decoding rather than in an error state. This should never happen, but
66389         including this logic for safety just in case.
66390         */
66391         if (result == MA_BUSY) {
66392             result  = MA_ERROR;
66393         }
66394
66395         if (result != MA_SUCCESS) {
66396             if (pJob->data.loadDataBufferNode.pFilePath != NULL) {
66397                 ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to initialize data supply for \"%s\". %s.\n", pJob->data.loadDataBufferNode.pFilePath, ma_result_description(result));
66398             } else {
66399                 #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER)
66400                     ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_WARNING, "Failed to initialize data supply for \"%ls\", %s.\n", pJob->data.loadDataBufferNode.pFilePathW, ma_result_description(result));
66401                 #endif
66402             }
66403
66404             goto done;
66405         }
66406
66407         /*
66408         At this point the node's data supply is initialized and other threads can start initializing
66409         their data buffer connectors. However, no data will actually be available until we start to
66410         actually decode it. To do this, we need to post a paging job which is where the decoding
66411         work is done.
66412
66413         Note that if an error occurred at an earlier point, this section will have been skipped.
66414         */
66415         pageDataBufferNodeJob = ma_resource_manager_job_init(MA_RESOURCE_MANAGER_JOB_PAGE_DATA_BUFFER_NODE);
66416         pageDataBufferNodeJob.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode);
66417         pageDataBufferNodeJob.data.pageDataBufferNode.pDataBufferNode   = pDataBufferNode;
66418         pageDataBufferNodeJob.data.pageDataBufferNode.pDecoder          = pDecoder;
66419         pageDataBufferNodeJob.data.pageDataBufferNode.pDoneNotification = pJob->data.loadDataBufferNode.pDoneNotification;
66420         pageDataBufferNodeJob.data.pageDataBufferNode.pDoneFence        = pJob->data.loadDataBufferNode.pDoneFence;
66421
66422         /* The job has been set up so it can now be posted. */
66423         result = ma_resource_manager_post_job(pResourceManager, &pageDataBufferNodeJob);
66424
66425         /*
66426         When we get here, we want to make sure the result code is set to MA_BUSY. The reason for
66427         this is that the result will be copied over to the node's internal result variable. In
66428         this case, since the decoding is still in-progress, we need to make sure the result code
66429         is set to MA_BUSY.
66430         */
66431         if (result != MA_SUCCESS) {
66432             ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to post MA_RESOURCE_MANAGER_JOB_PAGE_DATA_BUFFER_NODE job. %s\n", ma_result_description(result));
66433             ma_decoder_uninit(pDecoder);
66434             ma_free(pDecoder, &pResourceManager->config.allocationCallbacks);
66435         } else {
66436             result = MA_BUSY;
66437         }
66438     } else {
66439         /* No decoding. This is the simple case. We need only read the file content into memory and we're done. */
66440         result = ma_resource_manager_data_buffer_node_init_supply_encoded(pResourceManager, pDataBufferNode, pJob->data.loadDataBufferNode.pFilePath, pJob->data.loadDataBufferNode.pFilePathW);
66441     }
66442
66443
66444 done:
66445     /* File paths are no longer needed. */
66446     ma_free(pJob->data.loadDataBufferNode.pFilePath,  &pResourceManager->config.allocationCallbacks);
66447     ma_free(pJob->data.loadDataBufferNode.pFilePathW, &pResourceManager->config.allocationCallbacks);
66448
66449     /*
66450     We need to set the result to at the very end to ensure no other threads try reading the data before we've fully initialized the object. Other threads
66451     are going to be inspecting this variable to determine whether or not they're ready to read data. We can only change the result if it's set to MA_BUSY
66452     because otherwise we may be changing away from an error code which would be bad. An example is if the application creates a data buffer, but then
66453     immediately deletes it before we've got to this point. In this case, pDataBuffer->result will be MA_UNAVAILABLE, and setting it to MA_SUCCESS or any
66454     other error code would cause the buffer to look like it's in a state that it's not.
66455     */
66456     c89atomic_compare_and_swap_i32(&pDataBufferNode->result, MA_BUSY, result);
66457
66458     /* At this point initialization is complete and we can signal the notification if any. */
66459     if (pJob->data.loadDataBufferNode.pInitNotification != NULL) {
66460         ma_async_notification_signal(pJob->data.loadDataBufferNode.pInitNotification);
66461     }
66462     if (pJob->data.loadDataBufferNode.pInitFence != NULL) {
66463         ma_fence_release(pJob->data.loadDataBufferNode.pInitFence);
66464     }
66465
66466     /* If we have a success result it means we've fully loaded the buffer. This will happen in the non-decoding case. */
66467     if (result != MA_BUSY) {
66468         if (pJob->data.loadDataBufferNode.pDoneNotification != NULL) {
66469             ma_async_notification_signal(pJob->data.loadDataBufferNode.pDoneNotification);
66470         }
66471         if (pJob->data.loadDataBufferNode.pDoneFence != NULL) {
66472             ma_fence_release(pJob->data.loadDataBufferNode.pDoneFence);
66473         }
66474     }
66475
66476     /* Increment the node's execution pointer so that the next jobs can be processed. This is how we keep decoding of pages in-order. */
66477     c89atomic_fetch_add_32(&pDataBufferNode->executionPointer, 1);
66478     return result;
66479 }
66480
66481 static ma_result ma_resource_manager_process_job__free_data_buffer_node(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob)
66482 {
66483     ma_resource_manager_data_buffer_node* pDataBufferNode;
66484
66485     MA_ASSERT(pResourceManager != NULL);
66486     MA_ASSERT(pJob             != NULL);
66487
66488     pDataBufferNode = pJob->data.freeDataBufferNode.pDataBufferNode;
66489
66490     MA_ASSERT(pDataBufferNode != NULL);
66491
66492     if (pJob->order != c89atomic_load_32(&pDataBufferNode->executionPointer)) {
66493         return ma_resource_manager_post_job(pResourceManager, pJob);    /* Out of order. */
66494     }
66495
66496     ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode);
66497
66498     /* The event needs to be signalled last. */
66499     if (pJob->data.freeDataBufferNode.pDoneNotification != NULL) {
66500         ma_async_notification_signal(pJob->data.freeDataBufferNode.pDoneNotification);
66501     }
66502
66503     if (pJob->data.freeDataBufferNode.pDoneFence != NULL) {
66504         ma_fence_release(pJob->data.freeDataBufferNode.pDoneFence);
66505     }
66506
66507     c89atomic_fetch_add_32(&pDataBufferNode->executionPointer, 1);
66508     return MA_SUCCESS;
66509 }
66510
66511 static ma_result ma_resource_manager_process_job__page_data_buffer_node(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob)
66512 {
66513     ma_result result = MA_SUCCESS;
66514     ma_resource_manager_data_buffer_node* pDataBufferNode;
66515
66516     MA_ASSERT(pResourceManager != NULL);
66517     MA_ASSERT(pJob             != NULL);
66518
66519     pDataBufferNode = pJob->data.pageDataBufferNode.pDataBufferNode;
66520     MA_ASSERT(pDataBufferNode != NULL);
66521
66522     if (pJob->order != c89atomic_load_32(&pDataBufferNode->executionPointer)) {
66523         return ma_resource_manager_post_job(pResourceManager, pJob);    /* Out of order. */
66524     }
66525
66526     /* Don't do any more decoding if the data buffer has started the uninitialization process. */
66527     result = ma_resource_manager_data_buffer_node_result(pDataBufferNode);
66528     if (result != MA_BUSY) {
66529         goto done;
66530     }
66531
66532     /* We're ready to decode the next page. */
66533     result = ma_resource_manager_data_buffer_node_decode_next_page(pResourceManager, pDataBufferNode, pJob->data.pageDataBufferNode.pDecoder);
66534
66535     /*
66536     If we have a success code by this point, we want to post another job. We're going to set the
66537     result back to MA_BUSY to make it clear that there's still more to load.
66538     */
66539     if (result == MA_SUCCESS) {
66540         ma_resource_manager_job newJob;
66541         newJob = *pJob; /* Everything is the same as the input job, except the execution order. */
66542         newJob.order = ma_resource_manager_data_buffer_node_next_execution_order(pDataBufferNode);   /* We need a fresh execution order. */
66543
66544         result = ma_resource_manager_post_job(pResourceManager, &newJob);
66545
66546         /* Since the sound isn't yet fully decoded we want the status to be set to busy. */
66547         if (result == MA_SUCCESS) {
66548             result  = MA_BUSY;
66549         }
66550     }
66551
66552 done:
66553     /* If there's still more to decode the result will be set to MA_BUSY. Otherwise we can free the decoder. */
66554     if (result != MA_BUSY) {
66555         ma_decoder_uninit(pJob->data.pageDataBufferNode.pDecoder);
66556         ma_free(pJob->data.pageDataBufferNode.pDecoder, &pResourceManager->config.allocationCallbacks);
66557     }
66558
66559     /* If we reached the end we need to treat it as successful. */
66560     if (result == MA_AT_END) {
66561         result  = MA_SUCCESS;
66562     }
66563
66564     /* Make sure we set the result of node in case some error occurred. */
66565     c89atomic_compare_and_swap_i32(&pDataBufferNode->result, MA_BUSY, result);
66566
66567     /* Signal the notification after setting the result in case the notification callback wants to inspect the result code. */
66568     if (result != MA_BUSY) {
66569         if (pJob->data.pageDataBufferNode.pDoneNotification != NULL) {
66570             ma_async_notification_signal(pJob->data.pageDataBufferNode.pDoneNotification);
66571         }
66572
66573         if (pJob->data.pageDataBufferNode.pDoneFence != NULL) {
66574             ma_fence_release(pJob->data.pageDataBufferNode.pDoneFence);
66575         }
66576     }
66577
66578     c89atomic_fetch_add_32(&pDataBufferNode->executionPointer, 1);
66579     return result;
66580 }
66581
66582
66583 static ma_result ma_resource_manager_process_job__load_data_buffer(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob)
66584 {
66585     ma_result result = MA_SUCCESS;
66586     ma_resource_manager_data_buffer* pDataBuffer;
66587     ma_resource_manager_data_supply_type dataSupplyType = ma_resource_manager_data_supply_type_unknown;
66588     ma_bool32 isConnectorInitialized = MA_FALSE;
66589
66590     /*
66591     All we're doing here is checking if the node has finished loading. If not, we just re-post the job
66592     and keep waiting. Otherwise we increment the execution counter and set the buffer's result code.
66593     */
66594     MA_ASSERT(pResourceManager != NULL);
66595     MA_ASSERT(pJob             != NULL);
66596
66597     pDataBuffer = pJob->data.loadDataBuffer.pDataBuffer;
66598     MA_ASSERT(pDataBuffer != NULL);
66599
66600     if (pJob->order != c89atomic_load_32(&pDataBuffer->executionPointer)) {
66601         return ma_resource_manager_post_job(pResourceManager, pJob);    /* Attempting to execute out of order. Probably interleaved with a MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER job. */
66602     }
66603
66604     /*
66605     First thing we need to do is check whether or not the data buffer is getting deleted. If so we
66606     just abort, but making sure we increment the execution pointer.
66607     */
66608     result = ma_resource_manager_data_buffer_result(pDataBuffer);
66609     if (result != MA_BUSY) {
66610         goto done;  /* <-- This will ensure the exucution pointer is incremented. */
66611     } else {
66612         result = MA_SUCCESS;    /* <-- Make sure this is reset. */
66613     }
66614
66615     /* Try initializing the connector if we haven't already. */
66616     isConnectorInitialized = pDataBuffer->isConnectorInitialized;
66617     if (isConnectorInitialized == MA_FALSE) {
66618         dataSupplyType = ma_resource_manager_data_buffer_node_get_data_supply_type(pDataBuffer->pNode);
66619
66620         if (dataSupplyType != ma_resource_manager_data_supply_type_unknown) {
66621             /* We can now initialize the connector. If this fails, we need to abort. It's very rare for this to fail. */
66622             result = ma_resource_manager_data_buffer_init_connector(pDataBuffer, pJob->data.loadDataBuffer.pInitNotification, pJob->data.loadDataBuffer.pInitFence);
66623             if (result != MA_SUCCESS) {
66624                 ma_log_postf(ma_resource_manager_get_log(pResourceManager), MA_LOG_LEVEL_ERROR, "Failed to initialize connector for data buffer. %s.\n", ma_result_description(result));
66625                 goto done;
66626             }
66627         } else {
66628             /* Don't have a known data supply type. Most likely the data buffer node is still loading, but it could be that an error occurred. */
66629         }
66630     } else {
66631         /* The connector is already initialized. Nothing to do here. */
66632     }
66633
66634     /*
66635     If the data node is still loading, we need to repost the job and *not* increment the execution
66636     pointer (i.e. we need to not fall through to the "done" label).
66637
66638     There is a hole between here and the where the data connector is initialized where the data
66639     buffer node may have finished initializing. We need to check for this by checking the result of
66640     the data buffer node and whether or not we had an unknown data supply type at the time of
66641     trying to initialize the data connector. 
66642     */
66643     result = ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode);
66644     if (result == MA_BUSY || (result == MA_SUCCESS && isConnectorInitialized == MA_FALSE && dataSupplyType == ma_resource_manager_data_supply_type_unknown)) {
66645         return ma_resource_manager_post_job(pResourceManager, pJob);
66646     }
66647
66648 done:
66649     /* Only move away from a busy code so that we don't trash any existing error codes. */
66650     c89atomic_compare_and_swap_i32(&pJob->data.loadDataBuffer.pDataBuffer->result, MA_BUSY, result);
66651
66652     /* Only signal the other threads after the result has been set just for cleanliness sake. */
66653     if (pJob->data.loadDataBuffer.pDoneNotification != NULL) {
66654         ma_async_notification_signal(pJob->data.loadDataBuffer.pDoneNotification);
66655     }
66656     if (pJob->data.loadDataBuffer.pDoneFence != NULL) {
66657         ma_fence_release(pJob->data.loadDataBuffer.pDoneFence);
66658     }
66659
66660     /*
66661     If at this point the data buffer has not had it's connector initialized, it means the
66662     notification event was never signalled which means we need to signal it here.
66663     */
66664     if (pDataBuffer->isConnectorInitialized == MA_FALSE && result != MA_SUCCESS) {
66665         if (pJob->data.loadDataBuffer.pInitNotification != NULL) {
66666             ma_async_notification_signal(pJob->data.loadDataBuffer.pInitNotification);
66667         }
66668         if (pJob->data.loadDataBuffer.pInitFence != NULL) {
66669             ma_fence_release(pJob->data.loadDataBuffer.pInitFence);
66670         }
66671     }
66672
66673     c89atomic_fetch_add_32(&pDataBuffer->executionPointer, 1);
66674     return result;
66675 }
66676
66677 static ma_result ma_resource_manager_process_job__free_data_buffer(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob)
66678 {
66679     ma_resource_manager_data_buffer* pDataBuffer;
66680
66681     MA_ASSERT(pResourceManager != NULL);
66682     MA_ASSERT(pJob             != NULL);
66683
66684     pDataBuffer = pJob->data.freeDataBuffer.pDataBuffer;
66685     MA_ASSERT(pDataBuffer != NULL);
66686
66687     if (pJob->order != c89atomic_load_32(&pDataBuffer->executionPointer)) {
66688         return ma_resource_manager_post_job(pResourceManager, pJob);    /* Out of order. */
66689     }
66690
66691     ma_resource_manager_data_buffer_uninit_internal(pDataBuffer);
66692
66693     /* The event needs to be signalled last. */
66694     if (pJob->data.freeDataBuffer.pDoneNotification != NULL) {
66695         ma_async_notification_signal(pJob->data.freeDataBuffer.pDoneNotification);
66696     }
66697
66698     if (pJob->data.freeDataBuffer.pDoneFence != NULL) {
66699         ma_fence_release(pJob->data.freeDataBuffer.pDoneFence);
66700     }
66701
66702     c89atomic_fetch_add_32(&pDataBuffer->executionPointer, 1);
66703     return MA_SUCCESS;
66704 }
66705
66706 static ma_result ma_resource_manager_process_job__load_data_stream(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob)
66707 {
66708     ma_result result = MA_SUCCESS;
66709     ma_decoder_config decoderConfig;
66710     ma_uint32 pageBufferSizeInBytes;
66711     ma_resource_manager_data_stream* pDataStream;
66712
66713     MA_ASSERT(pResourceManager != NULL);
66714     MA_ASSERT(pJob             != NULL);
66715
66716     pDataStream = pJob->data.loadDataStream.pDataStream;
66717     MA_ASSERT(pDataStream != NULL);
66718
66719     if (pJob->order != c89atomic_load_32(&pDataStream->executionPointer)) {
66720         return ma_resource_manager_post_job(pResourceManager, pJob);    /* Out of order. */
66721     }
66722
66723     if (ma_resource_manager_data_stream_result(pDataStream) != MA_BUSY) {
66724         result = MA_INVALID_OPERATION;  /* Most likely the data stream is being uninitialized. */
66725         goto done;
66726     }
66727
66728     /* We need to initialize the decoder first so we can determine the size of the pages. */
66729     decoderConfig = ma_resource_manager__init_decoder_config(pResourceManager);
66730
66731     if (pJob->data.loadDataStream.pFilePath != NULL) {
66732         result = ma_decoder_init_vfs(pResourceManager->config.pVFS, pJob->data.loadDataStream.pFilePath, &decoderConfig, &pDataStream->decoder);
66733     } else {
66734         result = ma_decoder_init_vfs_w(pResourceManager->config.pVFS, pJob->data.loadDataStream.pFilePathW, &decoderConfig, &pDataStream->decoder);
66735     }
66736     if (result != MA_SUCCESS) {
66737         goto done;
66738     }
66739
66740     /* Retrieve the total length of the file before marking the decoder are loaded. */
66741     result = ma_decoder_get_length_in_pcm_frames(&pDataStream->decoder, &pDataStream->totalLengthInPCMFrames);
66742     if (result != MA_SUCCESS) {
66743         goto done;  /* Failed to retrieve the length. */
66744     }
66745
66746     /*
66747     Only mark the decoder as initialized when the length of the decoder has been retrieved because that can possibly require a scan over the whole file
66748     and we don't want to have another thread trying to access the decoder while it's scanning.
66749     */
66750     pDataStream->isDecoderInitialized = MA_TRUE;
66751
66752     /* We have the decoder so we can now initialize our page buffer. */
66753     pageBufferSizeInBytes = ma_resource_manager_data_stream_get_page_size_in_frames(pDataStream) * 2 * ma_get_bytes_per_frame(pDataStream->decoder.outputFormat, pDataStream->decoder.outputChannels);
66754
66755     pDataStream->pPageData = ma_malloc(pageBufferSizeInBytes, &pResourceManager->config.allocationCallbacks);
66756     if (pDataStream->pPageData == NULL) {
66757         ma_decoder_uninit(&pDataStream->decoder);
66758         result = MA_OUT_OF_MEMORY;
66759         goto done;
66760     }
66761
66762     /* Seek to our initial seek point before filling the initial pages. */
66763     ma_decoder_seek_to_pcm_frame(&pDataStream->decoder, pJob->data.loadDataStream.initialSeekPoint);
66764
66765     /* We have our decoder and our page buffer, so now we need to fill our pages. */
66766     ma_resource_manager_data_stream_fill_pages(pDataStream);
66767
66768     /* And now we're done. We want to make sure the result is MA_SUCCESS. */
66769     result = MA_SUCCESS;
66770
66771 done:
66772     ma_free(pJob->data.loadDataStream.pFilePath,  &pResourceManager->config.allocationCallbacks);
66773     ma_free(pJob->data.loadDataStream.pFilePathW, &pResourceManager->config.allocationCallbacks);
66774
66775     /* We can only change the status away from MA_BUSY. If it's set to anything else it means an error has occurred somewhere or the uninitialization process has started (most likely). */
66776     c89atomic_compare_and_swap_i32(&pDataStream->result, MA_BUSY, result);
66777
66778     /* Only signal the other threads after the result has been set just for cleanliness sake. */
66779     if (pJob->data.loadDataStream.pInitNotification != NULL) {
66780         ma_async_notification_signal(pJob->data.loadDataStream.pInitNotification);
66781     }
66782     if (pJob->data.loadDataStream.pInitFence != NULL) {
66783         ma_fence_release(pJob->data.loadDataStream.pInitFence);
66784     }
66785
66786     c89atomic_fetch_add_32(&pDataStream->executionPointer, 1);
66787     return result;
66788 }
66789
66790 static ma_result ma_resource_manager_process_job__free_data_stream(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob)
66791 {
66792     ma_resource_manager_data_stream* pDataStream;
66793
66794     MA_ASSERT(pResourceManager != NULL);
66795     MA_ASSERT(pJob             != NULL);
66796
66797     pDataStream = pJob->data.freeDataStream.pDataStream;
66798     MA_ASSERT(pDataStream != NULL);
66799
66800     if (pJob->order != c89atomic_load_32(&pDataStream->executionPointer)) {
66801         return ma_resource_manager_post_job(pResourceManager, pJob);    /* Out of order. */
66802     }
66803
66804     /* If our status is not MA_UNAVAILABLE we have a bug somewhere. */
66805     MA_ASSERT(ma_resource_manager_data_stream_result(pDataStream) == MA_UNAVAILABLE);
66806
66807     if (pDataStream->isDecoderInitialized) {
66808         ma_decoder_uninit(&pDataStream->decoder);
66809     }
66810
66811     if (pDataStream->pPageData != NULL) {
66812         ma_free(pDataStream->pPageData, &pResourceManager->config.allocationCallbacks);
66813         pDataStream->pPageData = NULL;  /* Just in case... */
66814     }
66815
66816     ma_data_source_uninit(&pDataStream->ds);
66817
66818     /* The event needs to be signalled last. */
66819     if (pJob->data.freeDataStream.pDoneNotification != NULL) {
66820         ma_async_notification_signal(pJob->data.freeDataStream.pDoneNotification);
66821     }
66822     if (pJob->data.freeDataStream.pDoneFence != NULL) {
66823         ma_fence_release(pJob->data.freeDataStream.pDoneFence);
66824     }
66825
66826     /*c89atomic_fetch_add_32(&pDataStream->executionPointer, 1);*/
66827     return MA_SUCCESS;
66828 }
66829
66830 static ma_result ma_resource_manager_process_job__page_data_stream(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob)
66831 {
66832     ma_result result = MA_SUCCESS;
66833     ma_resource_manager_data_stream* pDataStream;
66834
66835     MA_ASSERT(pResourceManager != NULL);
66836     MA_ASSERT(pJob             != NULL);
66837
66838     pDataStream = pJob->data.pageDataStream.pDataStream;
66839     MA_ASSERT(pDataStream != NULL);
66840
66841     if (pJob->order != c89atomic_load_32(&pDataStream->executionPointer)) {
66842         return ma_resource_manager_post_job(pResourceManager, pJob);    /* Out of order. */
66843     }
66844
66845     /* For streams, the status should be MA_SUCCESS. */
66846     if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS) {
66847         result = MA_INVALID_OPERATION;
66848         goto done;
66849     }
66850
66851     ma_resource_manager_data_stream_fill_page(pDataStream, pJob->data.pageDataStream.pageIndex);
66852
66853 done:
66854     c89atomic_fetch_add_32(&pDataStream->executionPointer, 1);
66855     return result;
66856 }
66857
66858 static ma_result ma_resource_manager_process_job__seek_data_stream(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob)
66859 {
66860     ma_result result = MA_SUCCESS;
66861     ma_resource_manager_data_stream* pDataStream;
66862
66863     MA_ASSERT(pResourceManager != NULL);
66864     MA_ASSERT(pJob             != NULL);
66865
66866     pDataStream = pJob->data.seekDataStream.pDataStream;
66867     MA_ASSERT(pDataStream != NULL);
66868
66869     if (pJob->order != c89atomic_load_32(&pDataStream->executionPointer)) {
66870         return ma_resource_manager_post_job(pResourceManager, pJob);    /* Out of order. */
66871     }
66872
66873     /* For streams the status should be MA_SUCCESS for this to do anything. */
66874     if (ma_resource_manager_data_stream_result(pDataStream) != MA_SUCCESS || pDataStream->isDecoderInitialized == MA_FALSE) {
66875         result = MA_INVALID_OPERATION;
66876         goto done;
66877     }
66878
66879     /*
66880     With seeking we just assume both pages are invalid and the relative frame cursor at position 0. This is basically exactly the same as loading, except
66881     instead of initializing the decoder, we seek to a frame.
66882     */
66883     ma_decoder_seek_to_pcm_frame(&pDataStream->decoder, pJob->data.seekDataStream.frameIndex);
66884
66885     /* After seeking we'll need to reload the pages. */
66886     ma_resource_manager_data_stream_fill_pages(pDataStream);
66887
66888     /* We need to let the public API know that we're done seeking. */
66889     c89atomic_fetch_sub_32(&pDataStream->seekCounter, 1);
66890
66891 done:
66892     c89atomic_fetch_add_32(&pDataStream->executionPointer, 1);
66893     return result;
66894 }
66895
66896 MA_API ma_result ma_resource_manager_process_job(ma_resource_manager* pResourceManager, ma_resource_manager_job* pJob)
66897 {
66898     if (pResourceManager == NULL || pJob == NULL) {
66899         return MA_INVALID_ARGS;
66900     }
66901
66902     switch (pJob->toc.breakup.code)
66903     {
66904         /* Data Buffer Node */
66905         case MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER_NODE: return ma_resource_manager_process_job__load_data_buffer_node(pResourceManager, pJob);
66906         case MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER_NODE: return ma_resource_manager_process_job__free_data_buffer_node(pResourceManager, pJob);
66907         case MA_RESOURCE_MANAGER_JOB_PAGE_DATA_BUFFER_NODE: return ma_resource_manager_process_job__page_data_buffer_node(pResourceManager, pJob);
66908
66909         /* Data Buffer */
66910         case MA_RESOURCE_MANAGER_JOB_LOAD_DATA_BUFFER: return ma_resource_manager_process_job__load_data_buffer(pResourceManager, pJob);
66911         case MA_RESOURCE_MANAGER_JOB_FREE_DATA_BUFFER: return ma_resource_manager_process_job__free_data_buffer(pResourceManager, pJob);
66912
66913         /* Data Stream */
66914         case MA_RESOURCE_MANAGER_JOB_LOAD_DATA_STREAM: return ma_resource_manager_process_job__load_data_stream(pResourceManager, pJob);
66915         case MA_RESOURCE_MANAGER_JOB_FREE_DATA_STREAM: return ma_resource_manager_process_job__free_data_stream(pResourceManager, pJob);
66916         case MA_RESOURCE_MANAGER_JOB_PAGE_DATA_STREAM: return ma_resource_manager_process_job__page_data_stream(pResourceManager, pJob);
66917         case MA_RESOURCE_MANAGER_JOB_SEEK_DATA_STREAM: return ma_resource_manager_process_job__seek_data_stream(pResourceManager, pJob);
66918
66919         default: break;
66920     }
66921
66922     /* Getting here means we don't know what the job code is and cannot do anything with it. */
66923     return MA_INVALID_OPERATION;
66924 }
66925
66926 MA_API ma_result ma_resource_manager_process_next_job(ma_resource_manager* pResourceManager)
66927 {
66928     ma_result result;
66929     ma_resource_manager_job job;
66930
66931     if (pResourceManager == NULL) {
66932         return MA_INVALID_ARGS;
66933     }
66934
66935     /* This will return MA_CANCELLED if the next job is a quit job. */
66936     result = ma_resource_manager_next_job(pResourceManager, &job);
66937     if (result != MA_SUCCESS) {
66938         return result;
66939     }
66940
66941     return ma_resource_manager_process_job(pResourceManager, &job);
66942 }
66943 #endif  /* MA_NO_RESOURCE_MANAGER */
66944
66945
66946 #ifndef MA_NO_NODE_GRAPH
66947 /* 10ms @ 48K = 480. Must never exceed 65535. */
66948 #ifndef MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS
66949 #define MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS 480
66950 #endif
66951
66952
66953 static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusIndex, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime);
66954
66955 MA_API void ma_debug_fill_pcm_frames_with_sine_wave(float* pFramesOut, ma_uint32 frameCount, ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
66956 {
66957     #ifndef MA_NO_GENERATION
66958     {
66959         ma_waveform_config waveformConfig;
66960         ma_waveform waveform;
66961
66962         waveformConfig = ma_waveform_config_init(format, channels, sampleRate, ma_waveform_type_sine, 1.0, 400);
66963         ma_waveform_init(&waveformConfig, &waveform);
66964         ma_waveform_read_pcm_frames(&waveform, pFramesOut, frameCount, NULL);
66965     }
66966     #else
66967     {
66968         (void)pFramesOut;
66969         (void)frameCount;
66970         (void)format;
66971         (void)channels;
66972         (void)sampleRate;
66973         #if defined(MA_DEBUG_OUTPUT)
66974         {
66975             #if _MSC_VER
66976                 #pragma message ("ma_debug_fill_pcm_frames_with_sine_wave() will do nothing because MA_NO_GENERATION is enabled.")
66977             #endif
66978         }
66979         #endif
66980     }
66981     #endif
66982 }
66983
66984
66985
66986 static ma_result ma_mix_pcm_frames_f32(float* pDst, const float* pSrc, ma_uint64 frameCount, ma_uint32 channels, float volume)
66987 {
66988     ma_uint64 iSample;
66989     ma_uint64 sampleCount;
66990
66991     if (pDst == NULL || pSrc == NULL || channels == 0) {
66992         return MA_INVALID_ARGS;
66993     }
66994
66995     if (volume == 0) {
66996         return MA_SUCCESS;  /* No changes if the volume is 0. */
66997     }
66998
66999     sampleCount = frameCount * channels;
67000
67001     if (volume == 1) {
67002         for (iSample = 0; iSample < sampleCount; iSample += 1) {
67003             pDst[iSample] += pSrc[iSample];
67004         }
67005     } else {
67006         for (iSample = 0; iSample < sampleCount; iSample += 1) {
67007             pDst[iSample] += ma_apply_volume_unclipped_f32(pSrc[iSample], volume);
67008         }
67009     }
67010
67011     return MA_SUCCESS;
67012 }
67013
67014
67015 MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels)
67016 {
67017     ma_node_graph_config config;
67018
67019     MA_ZERO_OBJECT(&config);
67020     config.channels = channels;
67021
67022     return config;
67023 }
67024
67025
67026 static void ma_node_graph_set_is_reading(ma_node_graph* pNodeGraph, ma_bool32 isReading)
67027 {
67028     MA_ASSERT(pNodeGraph != NULL);
67029     c89atomic_exchange_32(&pNodeGraph->isReading, isReading);
67030 }
67031
67032 #if 0
67033 static ma_bool32 ma_node_graph_is_reading(ma_node_graph* pNodeGraph)
67034 {
67035     MA_ASSERT(pNodeGraph != NULL);
67036     return c89atomic_load_32(&pNodeGraph->isReading);
67037 }
67038 #endif
67039
67040
67041 static void ma_node_graph_endpoint_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
67042 {
67043     MA_ASSERT(pNode != NULL);
67044     MA_ASSERT(ma_node_get_input_bus_count(pNode)  == 1);
67045     MA_ASSERT(ma_node_get_output_bus_count(pNode) == 1);
67046
67047     /* Input channel count needs to be the same as the output channel count. */
67048     MA_ASSERT(ma_node_get_input_channels(pNode, 0) == ma_node_get_output_channels(pNode, 0));
67049
67050     /* We don't need to do anything here because it's a passthrough. */
67051     (void)pNode;
67052     (void)ppFramesIn;
67053     (void)pFrameCountIn;
67054     (void)ppFramesOut;
67055     (void)pFrameCountOut;
67056
67057 #if 0
67058     /* The data has already been mixed. We just need to move it to the output buffer. */
67059     if (ppFramesIn != NULL) {
67060         ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, ma_node_get_output_channels(pNode, 0));
67061     }
67062 #endif
67063 }
67064
67065 static ma_node_vtable g_node_graph_endpoint_vtable =
67066 {
67067     ma_node_graph_endpoint_process_pcm_frames,
67068     NULL,   /* onGetRequiredInputFrameCount */
67069     1,      /* 1 input bus. */
67070     1,      /* 1 output bus. */
67071     MA_NODE_FLAG_PASSTHROUGH    /* Flags. The endpoint is a passthrough. */
67072 };
67073
67074 MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph)
67075 {
67076     ma_result result;
67077     ma_node_config endpointConfig;
67078
67079     if (pNodeGraph == NULL) {
67080         return MA_INVALID_ARGS;
67081     }
67082
67083     MA_ZERO_OBJECT(pNodeGraph);
67084
67085     endpointConfig = ma_node_config_init();
67086     endpointConfig.vtable          = &g_node_graph_endpoint_vtable;
67087     endpointConfig.pInputChannels  = &pConfig->channels;
67088     endpointConfig.pOutputChannels = &pConfig->channels;
67089
67090     result = ma_node_init(pNodeGraph, &endpointConfig, pAllocationCallbacks, &pNodeGraph->endpoint);
67091     if (result != MA_SUCCESS) {
67092         return result;
67093     }
67094
67095     return MA_SUCCESS;
67096 }
67097
67098 MA_API void ma_node_graph_uninit(ma_node_graph* pNodeGraph, const ma_allocation_callbacks* pAllocationCallbacks)
67099 {
67100     if (pNodeGraph == NULL) {
67101         return;
67102     }
67103
67104     ma_node_uninit(&pNodeGraph->endpoint, pAllocationCallbacks);
67105 }
67106
67107 MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph)
67108 {
67109     if (pNodeGraph == NULL) {
67110         return NULL;
67111     }
67112
67113     return &pNodeGraph->endpoint;
67114 }
67115
67116 MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
67117 {
67118     ma_result result = MA_SUCCESS;
67119     ma_uint64 totalFramesRead;
67120     ma_uint32 channels;
67121
67122     if (pFramesRead != NULL) {
67123         *pFramesRead = 0;   /* Safety. */
67124     }
67125
67126     if (pNodeGraph == NULL) {
67127         return MA_INVALID_ARGS;
67128     }
67129
67130     channels = ma_node_get_output_channels(&pNodeGraph->endpoint, 0);
67131
67132
67133     /* We'll be nice and try to do a full read of all frameCount frames. */
67134     totalFramesRead = 0;
67135     while (totalFramesRead < frameCount) {
67136         ma_uint32 framesJustRead;
67137         ma_uint64 framesToRead = frameCount - totalFramesRead;
67138
67139         if (framesToRead > 0xFFFFFFFF) {
67140             framesToRead = 0xFFFFFFFF;
67141         }
67142
67143         ma_node_graph_set_is_reading(pNodeGraph, MA_TRUE);
67144         {
67145             result = ma_node_read_pcm_frames(&pNodeGraph->endpoint, 0, (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), (ma_uint32)framesToRead, &framesJustRead, ma_node_get_time(&pNodeGraph->endpoint));
67146         }
67147         ma_node_graph_set_is_reading(pNodeGraph, MA_FALSE);
67148
67149         totalFramesRead += framesJustRead;
67150
67151         if (result != MA_SUCCESS) {
67152             break;
67153         }
67154
67155         /* Abort if we weren't able to read any frames or else we risk getting stuck in a loop. */
67156         if (framesJustRead == 0) {
67157             break;
67158         }
67159     }
67160
67161     /* Let's go ahead and silence any leftover frames just for some added safety to ensure the caller doesn't try emitting garbage out of the speakers. */
67162     if (totalFramesRead < frameCount) {
67163         ma_silence_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), (frameCount - totalFramesRead), ma_format_f32, channels);
67164     }
67165
67166     if (pFramesRead != NULL) {
67167         *pFramesRead = totalFramesRead;
67168     }
67169
67170     return result;
67171 }
67172
67173 MA_API ma_uint32 ma_node_graph_get_channels(const ma_node_graph* pNodeGraph)
67174 {
67175     if (pNodeGraph == NULL) {
67176         return 0;
67177     }
67178
67179     return ma_node_get_output_channels(&pNodeGraph->endpoint, 0);
67180 }
67181
67182 MA_API ma_uint64 ma_node_graph_get_time(const ma_node_graph* pNodeGraph)
67183 {
67184     if (pNodeGraph == NULL) {
67185         return 0;
67186     }
67187
67188     return ma_node_get_time(&pNodeGraph->endpoint); /* Global time is just the local time of the endpoint. */
67189 }
67190
67191 MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 globalTime)
67192 {
67193     if (pNodeGraph == NULL) {
67194         return MA_INVALID_ARGS;
67195     }
67196
67197     return ma_node_set_time(&pNodeGraph->endpoint, globalTime); /* Global time is just the local time of the endpoint. */
67198 }
67199
67200
67201 #define MA_NODE_OUTPUT_BUS_FLAG_HAS_READ    0x01    /* Whether or not this bus ready to read more data. Only used on nodes with multiple output buses. */
67202
67203 static ma_result ma_node_output_bus_init(ma_node* pNode, ma_uint32 outputBusIndex, ma_uint32 channels, ma_node_output_bus* pOutputBus)
67204 {
67205     MA_ASSERT(pOutputBus != NULL);
67206     MA_ASSERT(outputBusIndex < MA_MAX_NODE_BUS_COUNT);
67207     MA_ASSERT(outputBusIndex < ma_node_get_output_bus_count(pNode));
67208     MA_ASSERT(channels < 256);
67209
67210     MA_ZERO_OBJECT(pOutputBus);
67211
67212     if (channels == 0) {
67213         return MA_INVALID_ARGS;
67214     }
67215
67216     pOutputBus->pNode          = pNode;
67217     pOutputBus->outputBusIndex = (ma_uint8)outputBusIndex;
67218     pOutputBus->channels       = (ma_uint8)channels;
67219     pOutputBus->flags          = MA_NODE_OUTPUT_BUS_FLAG_HAS_READ; /* <-- Important that this flag is set by default. */
67220     pOutputBus->volume         = 1;
67221
67222     return MA_SUCCESS;
67223 }
67224
67225 static void ma_node_output_bus_lock(ma_node_output_bus* pOutputBus)
67226 {
67227     ma_spinlock_lock(&pOutputBus->lock);
67228 }
67229
67230 static void ma_node_output_bus_unlock(ma_node_output_bus* pOutputBus)
67231 {
67232     ma_spinlock_unlock(&pOutputBus->lock);
67233 }
67234
67235
67236 static ma_uint32 ma_node_output_bus_get_channels(const ma_node_output_bus* pOutputBus)
67237 {
67238     return pOutputBus->channels;
67239 }
67240
67241
67242 static void ma_node_output_bus_set_has_read(ma_node_output_bus* pOutputBus, ma_bool32 hasRead)
67243 {
67244     if (hasRead) {
67245         c89atomic_fetch_or_32(&pOutputBus->flags, MA_NODE_OUTPUT_BUS_FLAG_HAS_READ);
67246     } else {
67247         c89atomic_fetch_and_32(&pOutputBus->flags, (ma_uint32)~MA_NODE_OUTPUT_BUS_FLAG_HAS_READ);
67248     }
67249 }
67250
67251 static ma_bool32 ma_node_output_bus_has_read(ma_node_output_bus* pOutputBus)
67252 {
67253     return (c89atomic_load_32(&pOutputBus->flags) & MA_NODE_OUTPUT_BUS_FLAG_HAS_READ) != 0;
67254 }
67255
67256
67257 static void ma_node_output_bus_set_is_attached(ma_node_output_bus* pOutputBus, ma_bool32 isAttached)
67258 {
67259     c89atomic_exchange_32(&pOutputBus->isAttached, isAttached);
67260 }
67261
67262 static ma_bool32 ma_node_output_bus_is_attached(ma_node_output_bus* pOutputBus)
67263 {
67264     return c89atomic_load_32(&pOutputBus->isAttached);
67265 }
67266
67267
67268 static ma_result ma_node_output_bus_set_volume(ma_node_output_bus* pOutputBus, float volume)
67269 {
67270     MA_ASSERT(pOutputBus != NULL);
67271
67272     if (volume < 0.0f) {
67273         volume = 0.0f;
67274     }
67275
67276     c89atomic_exchange_f32(&pOutputBus->volume, volume);
67277
67278     return MA_SUCCESS;
67279 }
67280
67281 static float ma_node_output_bus_get_volume(const ma_node_output_bus* pOutputBus)
67282 {
67283     return c89atomic_load_f32((float*)&pOutputBus->volume);
67284 }
67285
67286
67287 static ma_result ma_node_input_bus_init(ma_uint32 channels, ma_node_input_bus* pInputBus)
67288 {
67289     MA_ASSERT(pInputBus != NULL);
67290     MA_ASSERT(channels < 256);
67291
67292     MA_ZERO_OBJECT(pInputBus);
67293
67294     if (channels == 0) {
67295         return MA_INVALID_ARGS;
67296     }
67297
67298     pInputBus->channels = (ma_uint8)channels;
67299
67300     return MA_SUCCESS;
67301 }
67302
67303 static void ma_node_input_bus_lock(ma_node_input_bus* pInputBus)
67304 {
67305     ma_spinlock_lock(&pInputBus->lock);
67306 }
67307
67308 static void ma_node_input_bus_unlock(ma_node_input_bus* pInputBus)
67309 {
67310     ma_spinlock_unlock(&pInputBus->lock);
67311 }
67312
67313
67314 static void ma_node_input_bus_next_begin(ma_node_input_bus* pInputBus)
67315 {
67316     c89atomic_fetch_add_32(&pInputBus->nextCounter, 1);
67317 }
67318
67319 static void ma_node_input_bus_next_end(ma_node_input_bus* pInputBus)
67320 {
67321     c89atomic_fetch_sub_32(&pInputBus->nextCounter, 1);
67322 }
67323
67324 static ma_uint32 ma_node_input_bus_get_next_counter(ma_node_input_bus* pInputBus)
67325 {
67326     return c89atomic_load_32(&pInputBus->nextCounter);
67327 }
67328
67329
67330 static ma_uint32 ma_node_input_bus_get_channels(const ma_node_input_bus* pInputBus)
67331 {
67332     return pInputBus->channels;
67333 }
67334
67335
67336 static void ma_node_input_bus_detach__no_output_bus_lock(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus)
67337 {
67338     MA_ASSERT(pInputBus  != NULL);
67339     MA_ASSERT(pOutputBus != NULL);
67340
67341     /*
67342     Mark the output bus as detached first. This will prevent future iterations on the audio thread
67343     from iterating this output bus.
67344     */
67345     ma_node_output_bus_set_is_attached(pOutputBus, MA_FALSE);
67346
67347     /*
67348     We cannot use the output bus lock here since it'll be getting used at a higher level, but we do
67349     still need to use the input bus lock since we'll be updating pointers on two different output
67350     buses. The same rules apply here as the attaching case. Although we're using a lock here, we're
67351     *not* using a lock when iterating over the list in the audio thread. We therefore need to craft
67352     this in a way such that the iteration on the audio thread doesn't break.
67353
67354     The the first thing to do is swap out the "next" pointer of the previous output bus with the
67355     new "next" output bus. This is the operation that matters for iteration on the audio thread.
67356     After that, the previous pointer on the new "next" pointer needs to be updated, after which
67357     point the linked list will be in a good state.
67358     */
67359     ma_node_input_bus_lock(pInputBus);
67360     {
67361         ma_node_output_bus* pOldPrev = (ma_node_output_bus*)c89atomic_load_ptr(&pOutputBus->pPrev);
67362         ma_node_output_bus* pOldNext = (ma_node_output_bus*)c89atomic_load_ptr(&pOutputBus->pNext);
67363
67364         if (pOldPrev != NULL) {
67365             c89atomic_exchange_ptr(&pOldPrev->pNext, pOldNext); /* <-- This is where the output bus is detached from the list. */
67366         }
67367         if (pOldNext != NULL) {
67368             c89atomic_exchange_ptr(&pOldNext->pPrev, pOldPrev); /* <-- This is required for detachment. */
67369         }
67370     }
67371     ma_node_input_bus_unlock(pInputBus);
67372
67373     /* At this point the output bus is detached and the linked list is completely unaware of it. Reset some data for safety. */
67374     c89atomic_exchange_ptr(&pOutputBus->pNext, NULL);   /* Using atomic exchanges here, mainly for the benefit of analysis tools which don't always recognize spinlocks. */
67375     c89atomic_exchange_ptr(&pOutputBus->pPrev, NULL);   /* As above. */
67376     pOutputBus->pInputNode             = NULL;
67377     pOutputBus->inputNodeInputBusIndex = 0;
67378
67379
67380     /*
67381     For thread-safety reasons, we don't want to be returning from this straight away. We need to
67382     wait for the audio thread to finish with the output bus. There's two things we need to wait
67383     for. The first is the part that selects the next output bus in the list, and the other is the
67384     part that reads from the output bus. Basically all we're doing is waiting for the input bus
67385     to stop referencing the output bus.
67386
67387     We're doing this part last because we want the section above to run while the audio thread
67388     is finishing up with the output bus, just for efficiency reasons. We marked the output bus as
67389     detached right at the top of this function which is going to prevent the audio thread from
67390     iterating the output bus again.
67391     */
67392
67393     /* Part 1: Wait for the current iteration to complete. */
67394     while (ma_node_input_bus_get_next_counter(pInputBus) > 0) {
67395         ma_yield();
67396     }
67397
67398     /* Part 2: Wait for any reads to complete. */
67399     while (c89atomic_load_32(&pOutputBus->refCount) > 0) {
67400         ma_yield();
67401     }
67402
67403     /*
67404     At this point we're done detaching and we can be guaranteed that the audio thread is not going
67405     to attempt to reference this output bus again (until attached again).
67406     */
67407 }
67408
67409 #if 0   /* Not used at the moment, but leaving here in case I need it later. */
67410 static void ma_node_input_bus_detach(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus)
67411 {
67412     MA_ASSERT(pInputBus  != NULL);
67413     MA_ASSERT(pOutputBus != NULL);
67414
67415     ma_node_output_bus_lock(pOutputBus);
67416     {
67417         ma_node_input_bus_detach__no_output_bus_lock(pInputBus, pOutputBus);
67418     }
67419     ma_node_output_bus_unlock(pOutputBus);
67420 }
67421 #endif
67422
67423 static void ma_node_input_bus_attach(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus, ma_node* pNewInputNode, ma_uint32 inputNodeInputBusIndex)
67424 {
67425     MA_ASSERT(pInputBus  != NULL);
67426     MA_ASSERT(pOutputBus != NULL);
67427
67428     ma_node_output_bus_lock(pOutputBus);
67429     {
67430         ma_node_output_bus* pOldInputNode = (ma_node_output_bus*)c89atomic_load_ptr(&pOutputBus->pInputNode);
67431
67432         /* Detach from any existing attachment first if necessary. */
67433         if (pOldInputNode != NULL) {
67434             ma_node_input_bus_detach__no_output_bus_lock(pInputBus, pOutputBus);
67435         }
67436
67437         /*
67438         At this point we can be sure the output bus is not attached to anything. The linked list in the
67439         old input bus has been updated so that pOutputBus will not get iterated again.
67440         */
67441         pOutputBus->pInputNode             = pNewInputNode;                     /* No need for an atomic assignment here because modification of this variable always happens within a lock. */
67442         pOutputBus->inputNodeInputBusIndex = (ma_uint8)inputNodeInputBusIndex;  /* As above. */
67443
67444         /*
67445         Now we need to attach the output bus to the linked list. This involves updating two pointers on
67446         two different output buses so I'm going to go ahead and keep this simple and just use a lock.
67447         There are ways to do this without a lock, but it's just too hard to maintain for it's value.
67448
67449         Although we're locking here, it's important to remember that we're *not* locking when iterating
67450         and reading audio data since that'll be running on the audio thread. As a result we need to be
67451         careful how we craft this so that we don't break iteration. What we're going to do is always
67452         attach the new item so that it becomes the first item in the list. That way, as we're iterating
67453         we won't break any links in the list and iteration will continue safely. The detaching case will
67454         also be crafted in a way as to not break list iteration. It's important to remember to use
67455         atomic exchanges here since no locking is happening on the audio thread during iteration.
67456         */
67457         ma_node_input_bus_lock(pInputBus);
67458         {
67459             ma_node_output_bus* pNewPrev = &pInputBus->head;
67460             ma_node_output_bus* pNewNext = (ma_node_output_bus*)c89atomic_load_ptr(&pInputBus->head.pNext);
67461
67462             /* Update the local output bus. */
67463             c89atomic_exchange_ptr(&pOutputBus->pPrev, pNewPrev);
67464             c89atomic_exchange_ptr(&pOutputBus->pNext, pNewNext);
67465
67466             /* Update the other output buses to point back to the local output bus. */
67467             c89atomic_exchange_ptr(&pInputBus->head.pNext, pOutputBus); /* <-- This is where the output bus is actually attached to the input bus. */
67468
67469             /* Do the previous pointer last. This is only used for detachment. */
67470             if (pNewNext != NULL) {
67471                 c89atomic_exchange_ptr(&pNewNext->pPrev,  pOutputBus);
67472             }
67473         }
67474         ma_node_input_bus_unlock(pInputBus);
67475
67476         /*
67477         Mark the node as attached last. This is used to controlling whether or the output bus will be
67478         iterated on the audio thread. Mainly required for detachment purposes.
67479         */
67480         ma_node_output_bus_set_is_attached(pOutputBus, MA_TRUE);
67481     }
67482     ma_node_output_bus_unlock(pOutputBus);
67483 }
67484
67485 static ma_node_output_bus* ma_node_input_bus_next(ma_node_input_bus* pInputBus, ma_node_output_bus* pOutputBus)
67486 {
67487     ma_node_output_bus* pNext;
67488
67489     MA_ASSERT(pInputBus != NULL);
67490
67491     if (pOutputBus == NULL) {
67492         return NULL;
67493     }
67494
67495     ma_node_input_bus_next_begin(pInputBus);
67496     {
67497         pNext = pOutputBus;
67498         for (;;) {
67499             pNext = (ma_node_output_bus*)c89atomic_load_ptr(&pNext->pNext);
67500             if (pNext == NULL) {
67501                 break;      /* Reached the end. */
67502             }
67503
67504             if (ma_node_output_bus_is_attached(pNext) == MA_FALSE) {
67505                 continue;   /* The node is not attached. Keep checking. */
67506             }
67507
67508             /* The next node has been selected. */
67509             break;
67510         }
67511
67512         /* We need to increment the reference count of the selected node. */
67513         if (pNext != NULL) {
67514             c89atomic_fetch_add_32(&pNext->refCount, 1);
67515         }
67516
67517         /* The previous node is no longer being referenced. */
67518         c89atomic_fetch_sub_32(&pOutputBus->refCount, 1);
67519     }
67520     ma_node_input_bus_next_end(pInputBus);
67521
67522     return pNext;
67523 }
67524
67525 static ma_node_output_bus* ma_node_input_bus_first(ma_node_input_bus* pInputBus)
67526 {
67527     return ma_node_input_bus_next(pInputBus, &pInputBus->head);
67528 }
67529
67530
67531
67532 static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_input_bus* pInputBus, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime)
67533 {
67534     ma_result result = MA_SUCCESS;
67535     ma_node_output_bus* pOutputBus;
67536     ma_node_output_bus* pFirst;
67537     ma_uint32 inputChannels;
67538
67539     /*
67540     This will be called from the audio thread which means we can't be doing any locking. Basically,
67541     this function will not perfom any locking, whereas attaching and detaching will, but crafted in
67542     such a way that we don't need to perform any locking here. The important thing to remember is
67543     to always iterate in a forward direction.
67544
67545     In order to process any data we need to first read from all input buses. That's where this
67546     function comes in. This iterates over each of the attachments and accumulates/mixes them. We
67547     also convert the channels to the nodes output channel count before mixing. We want to do this
67548     channel conversion so that the caller of this function can invoke the processing callback
67549     without having to do it themselves.
67550
67551     When we iterate over each of the attachments on the input bus, we need to read as much data as
67552     we can from each of them so that we don't end up with holes between each of the attachments. To
67553     do this, we need to read from each attachment in a loop and read as many frames as we can, up
67554     to `frameCount`.
67555     */
67556     MA_ASSERT(pInputNode  != NULL);
67557     MA_ASSERT(pFramesRead != NULL); /* pFramesRead is critical and must always be specified. On input it's undefined and on output it'll be set to the number of frames actually read. */
67558
67559     *pFramesRead = 0;   /* Safety. */
67560
67561     inputChannels = ma_node_input_bus_get_channels(pInputBus);
67562
67563     /*
67564     We need to be careful with how we call ma_node_input_bus_first() and ma_node_input_bus_next(). They
67565     are both critical to our lock-free thread-safety system. We can only call ma_node_input_bus_first()
67566     once per iteration, however we have an optimization to checks whether or not it's the first item in
67567     the list. We therefore need to store a pointer to the first item rather than repeatedly calling
67568     ma_node_input_bus_first(). It's safe to keep hold of this pointer, so long as we don't dereference it
67569     after calling ma_node_input_bus_next(), which we won't be.
67570     */
67571     pFirst = ma_node_input_bus_first(pInputBus);
67572     if (pFirst == NULL) {
67573         return MA_SUCCESS;  /* No attachments. Read nothing. */
67574     }
67575
67576     for (pOutputBus = pFirst; pOutputBus != NULL; pOutputBus = ma_node_input_bus_next(pInputBus, pOutputBus)) {
67577         ma_uint32 framesProcessed = 0;
67578
67579         MA_ASSERT(pOutputBus->pNode != NULL);
67580
67581         if (pFramesOut != NULL) {
67582             /* Read. */
67583             float temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE / sizeof(float)];
67584             ma_uint32 tempCapInFrames = ma_countof(temp) / inputChannels;
67585
67586             while (framesProcessed < frameCount) {
67587                 float* pRunningFramesOut;
67588                 ma_uint32 framesToRead;
67589                 ma_uint32 framesJustRead;
67590
67591                 framesToRead = frameCount - framesProcessed;
67592                 if (framesToRead > tempCapInFrames) {
67593                     framesToRead = tempCapInFrames;
67594                 }
67595
67596                 pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(pFramesOut, framesProcessed, inputChannels);
67597
67598                 if (pOutputBus == pFirst) {
67599                     /* Fast path. First attachment. We just read straight into the output buffer (no mixing required). */
67600                     result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, pRunningFramesOut, framesToRead, &framesJustRead, globalTime + framesProcessed);
67601                 } else {
67602                     /* Slow path. Not the first attachment. Mixing required. */
67603                     result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, temp, framesToRead, &framesJustRead, globalTime + framesProcessed);
67604                     if (result == MA_SUCCESS || result == MA_AT_END) {
67605                         ma_mix_pcm_frames_f32(pRunningFramesOut, temp, framesJustRead, inputChannels, /*volume*/1);
67606                     }
67607                 }
67608
67609                 framesProcessed += framesJustRead;
67610
67611                 /* If we reached the end or otherwise failed to read any data we need to finish up with this output node. */
67612                 if (result != MA_SUCCESS) {
67613                     break;
67614                 }
67615
67616                 /* If we didn't read anything, abort so we don't get stuck in a loop. */
67617                 if (framesJustRead == 0) {
67618                     break;
67619                 }
67620             }
67621
67622             /* If it's the first attachment we didn't do any mixing. Any leftover samples need to be silenced. */
67623             if (pOutputBus == pFirst && framesProcessed < frameCount) {
67624                 ma_silence_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, framesProcessed, ma_format_f32, inputChannels), (frameCount - framesProcessed), ma_format_f32, inputChannels);
67625             }
67626         } else {
67627             /* Seek. */
67628             ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, NULL, frameCount, &framesProcessed, globalTime);
67629         }
67630     }
67631
67632     /* In this path we always "process" the entire amount. */
67633     *pFramesRead = frameCount;
67634
67635     return result;
67636 }
67637
67638
67639 MA_API ma_node_config ma_node_config_init(void)
67640 {
67641     ma_node_config config;
67642
67643     MA_ZERO_OBJECT(&config);
67644     config.initialState   = ma_node_state_started;    /* Nodes are started by default. */
67645     config.inputBusCount  = MA_NODE_BUS_COUNT_UNKNOWN;
67646     config.outputBusCount = MA_NODE_BUS_COUNT_UNKNOWN;
67647
67648     return config;
67649 }
67650
67651
67652
67653 static ma_result ma_node_detach_full(ma_node* pNode);
67654
67655 static float* ma_node_get_cached_input_ptr(ma_node* pNode, ma_uint32 inputBusIndex)
67656 {
67657     ma_node_base* pNodeBase = (ma_node_base*)pNode;
67658     ma_uint32 iInputBus;
67659     float* pBasePtr;
67660
67661     MA_ASSERT(pNodeBase != NULL);
67662
67663     /* Input data is stored at the front of the buffer. */
67664     pBasePtr = pNodeBase->pCachedData;
67665     for (iInputBus = 0; iInputBus < inputBusIndex; iInputBus += 1) {
67666         pBasePtr += pNodeBase->cachedDataCapInFramesPerBus * ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iInputBus]);
67667     }
67668
67669     return pBasePtr;
67670 }
67671
67672 static float* ma_node_get_cached_output_ptr(ma_node* pNode, ma_uint32 outputBusIndex)
67673 {
67674     ma_node_base* pNodeBase = (ma_node_base*)pNode;
67675     ma_uint32 iInputBus;
67676     ma_uint32 iOutputBus;
67677     float* pBasePtr;
67678
67679     MA_ASSERT(pNodeBase != NULL);
67680
67681     /* Cached output data starts after the input data. */
67682     pBasePtr = pNodeBase->pCachedData;
67683     for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNodeBase); iInputBus += 1) {
67684         pBasePtr += pNodeBase->cachedDataCapInFramesPerBus * ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iInputBus]);
67685     }
67686
67687     for (iOutputBus = 0; iOutputBus < outputBusIndex; iOutputBus += 1) {
67688         pBasePtr += pNodeBase->cachedDataCapInFramesPerBus * ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[iOutputBus]);
67689     }
67690
67691     return pBasePtr;
67692 }
67693
67694
67695 typedef struct
67696 {
67697     size_t sizeInBytes;
67698     size_t inputBusOffset;
67699     size_t outputBusOffset;
67700     size_t cachedDataOffset;
67701     ma_uint32 inputBusCount;    /* So it doesn't have to be calculated twice. */
67702     ma_uint32 outputBusCount;   /* So it doesn't have to be calculated twice. */
67703 } ma_node_heap_layout;
67704
67705 static ma_result ma_node_translate_bus_counts(const ma_node_config* pConfig, ma_uint32* pInputBusCount, ma_uint32* pOutputBusCount)
67706 {
67707     ma_uint32 inputBusCount;
67708     ma_uint32 outputBusCount;
67709
67710     MA_ASSERT(pConfig != NULL);
67711     MA_ASSERT(pInputBusCount  != NULL);
67712     MA_ASSERT(pOutputBusCount != NULL);
67713
67714     /* Bus counts are determined by the vtable, unless they're set to `MA_NODE_BUS_COUNT_UNKNWON`, in which case they're taken from the config. */
67715     if (pConfig->vtable->inputBusCount == MA_NODE_BUS_COUNT_UNKNOWN) {
67716         inputBusCount = pConfig->inputBusCount;
67717     } else {
67718         inputBusCount = pConfig->vtable->inputBusCount;
67719
67720         if (pConfig->inputBusCount != MA_NODE_BUS_COUNT_UNKNOWN && pConfig->inputBusCount != pConfig->vtable->inputBusCount) {
67721             return MA_INVALID_ARGS; /* Invalid configuration. You must not specify a conflicting bus count between the node's config and the vtable. */
67722         }
67723     }
67724
67725     if (pConfig->vtable->outputBusCount == MA_NODE_BUS_COUNT_UNKNOWN) {
67726         outputBusCount = pConfig->outputBusCount;
67727     } else {
67728         outputBusCount = pConfig->vtable->outputBusCount;
67729
67730         if (pConfig->outputBusCount != MA_NODE_BUS_COUNT_UNKNOWN && pConfig->outputBusCount != pConfig->vtable->outputBusCount) {
67731             return MA_INVALID_ARGS; /* Invalid configuration. You must not specify a conflicting bus count between the node's config and the vtable. */
67732         }
67733     }
67734
67735     /* Bus counts must be within limits. */
67736     if (inputBusCount > MA_MAX_NODE_BUS_COUNT || outputBusCount > MA_MAX_NODE_BUS_COUNT) {
67737         return MA_INVALID_ARGS;
67738     }
67739
67740
67741     /* We must have channel counts for each bus. */
67742     if ((inputBusCount > 0 && pConfig->pInputChannels == NULL) || (outputBusCount > 0 && pConfig->pOutputChannels == NULL)) {
67743         return MA_INVALID_ARGS; /* You must specify channel counts for each input and output bus. */
67744     }
67745
67746
67747     /* Some special rules for passthrough nodes. */
67748     if ((pConfig->vtable->flags & MA_NODE_FLAG_PASSTHROUGH) != 0) {
67749         if (pConfig->vtable->inputBusCount != 1 || pConfig->vtable->outputBusCount != 1) {
67750             return MA_INVALID_ARGS; /* Passthrough nodes must have exactly 1 input bus and 1 output bus. */
67751         }
67752
67753         if (pConfig->pInputChannels[0] != pConfig->pOutputChannels[0]) {
67754             return MA_INVALID_ARGS; /* Passthrough nodes must have the same number of channels between input and output nodes. */
67755         }
67756     }
67757
67758
67759     *pInputBusCount  = inputBusCount;
67760     *pOutputBusCount = outputBusCount;
67761
67762     return MA_SUCCESS;
67763 }
67764
67765 static ma_result ma_node_get_heap_layout(const ma_node_config* pConfig, ma_node_heap_layout* pHeapLayout)
67766 {
67767     ma_result result;
67768     ma_uint32 inputBusCount;
67769     ma_uint32 outputBusCount;
67770
67771     MA_ASSERT(pHeapLayout != NULL);
67772
67773     MA_ZERO_OBJECT(pHeapLayout);
67774
67775     if (pConfig == NULL || pConfig->vtable == NULL || pConfig->vtable->onProcess == NULL) {
67776         return MA_INVALID_ARGS;
67777     }
67778
67779     result = ma_node_translate_bus_counts(pConfig, &inputBusCount, &outputBusCount);
67780     if (result != MA_SUCCESS) {
67781         return result;
67782     }
67783
67784     pHeapLayout->sizeInBytes = 0;
67785
67786     /* Input buses. */
67787     if (inputBusCount > MA_MAX_NODE_LOCAL_BUS_COUNT) {
67788         pHeapLayout->inputBusOffset = pHeapLayout->sizeInBytes;
67789         pHeapLayout->sizeInBytes += ma_align_64(sizeof(ma_node_input_bus) * inputBusCount);
67790     } else {
67791         pHeapLayout->inputBusOffset = MA_SIZE_MAX;  /* MA_SIZE_MAX indicates that no heap allocation is required for the input bus. */
67792     }
67793
67794     /* Output buses. */
67795     if (outputBusCount > MA_MAX_NODE_LOCAL_BUS_COUNT) {
67796         pHeapLayout->outputBusOffset = pHeapLayout->sizeInBytes;
67797         pHeapLayout->sizeInBytes += ma_align_64(sizeof(ma_node_output_bus) * outputBusCount);
67798     } else {
67799         pHeapLayout->outputBusOffset = MA_SIZE_MAX;
67800     }
67801
67802     /*
67803     Cached audio data.
67804
67805     We need to allocate memory for a caching both input and output data. We have an optimization
67806     where no caching is necessary for specific conditions:
67807
67808         - The node has 0 inputs and 1 output.
67809
67810     When a node meets the above conditions, no cache is allocated.
67811
67812     The size choice for this buffer is a little bit finicky. We don't want to be too wasteful by
67813     allocating too much, but at the same time we want it be large enough so that enough frames can
67814     be processed for each call to ma_node_read_pcm_frames() so that it keeps things efficient. For
67815     now I'm going with 10ms @ 48K which is 480 frames per bus. This is configurable at compile
67816     time. It might also be worth investigating whether or not this can be configured at run time.
67817     */
67818     if (inputBusCount == 0 && outputBusCount == 1) {
67819         /* Fast path. No cache needed. */
67820         pHeapLayout->cachedDataOffset = MA_SIZE_MAX;
67821     } else {
67822         /* Slow path. Cache needed. */
67823         size_t cachedDataSizeInBytes = 0;
67824         ma_uint32 iBus;
67825
67826         MA_ASSERT(MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS <= 0xFFFF);    /* Clamped to 16 bits. */
67827
67828         for (iBus = 0; iBus < inputBusCount; iBus += 1) {
67829             cachedDataSizeInBytes += MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS * ma_get_bytes_per_frame(ma_format_f32, pConfig->pInputChannels[iBus]);
67830         }
67831
67832         for (iBus = 0; iBus < outputBusCount; iBus += 1) {
67833             cachedDataSizeInBytes += MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS * ma_get_bytes_per_frame(ma_format_f32, pConfig->pOutputChannels[iBus]);
67834         }
67835
67836         pHeapLayout->cachedDataOffset = pHeapLayout->sizeInBytes;
67837         pHeapLayout->sizeInBytes += ma_align_64(cachedDataSizeInBytes);
67838     }
67839
67840
67841     /*
67842     Not technically part of the heap, but we can output the input and output bus counts so we can
67843     avoid a redundant call to ma_node_translate_bus_counts().
67844     */
67845     pHeapLayout->inputBusCount  = inputBusCount;
67846     pHeapLayout->outputBusCount = outputBusCount;
67847
67848     /* Make sure allocation size is aligned. */
67849     pHeapLayout->sizeInBytes = ma_align_64(pHeapLayout->sizeInBytes);
67850
67851     return MA_SUCCESS;
67852 }
67853
67854 MA_API ma_result ma_node_get_heap_size(const ma_node_config* pConfig, size_t* pHeapSizeInBytes)
67855 {
67856     ma_result result;
67857     ma_node_heap_layout heapLayout;
67858
67859     if (pHeapSizeInBytes == NULL) {
67860         return MA_INVALID_ARGS;
67861     }
67862
67863     *pHeapSizeInBytes = 0;
67864
67865     result = ma_node_get_heap_layout(pConfig, &heapLayout);
67866     if (result != MA_SUCCESS) {
67867         return result;
67868     }
67869
67870     *pHeapSizeInBytes = heapLayout.sizeInBytes;
67871
67872     return MA_SUCCESS;
67873 }
67874
67875 MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, void* pHeap, ma_node* pNode)
67876 {
67877     ma_node_base* pNodeBase = (ma_node_base*)pNode;
67878     ma_result result;
67879     ma_node_heap_layout heapLayout;
67880     ma_uint32 iInputBus;
67881     ma_uint32 iOutputBus;
67882
67883     if (pNodeBase == NULL) {
67884         return MA_INVALID_ARGS;
67885     }
67886
67887     MA_ZERO_OBJECT(pNodeBase);
67888
67889     result = ma_node_get_heap_layout(pConfig, &heapLayout);
67890     if (result != MA_SUCCESS) {
67891         return result;
67892     }
67893
67894     pNodeBase->_pHeap = pHeap;
67895     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
67896
67897     pNodeBase->pNodeGraph     = pNodeGraph;
67898     pNodeBase->vtable         = pConfig->vtable;
67899     pNodeBase->state          = pConfig->initialState;
67900     pNodeBase->stateTimes[ma_node_state_started] = 0;
67901     pNodeBase->stateTimes[ma_node_state_stopped] = (ma_uint64)(ma_int64)-1; /* Weird casting for VC6 compatibility. */
67902     pNodeBase->inputBusCount  = heapLayout.inputBusCount;
67903     pNodeBase->outputBusCount = heapLayout.outputBusCount;
67904
67905     if (heapLayout.inputBusOffset != MA_SIZE_MAX) {
67906         pNodeBase->pInputBuses = (ma_node_input_bus*)ma_offset_ptr(pHeap, heapLayout.inputBusOffset);
67907     } else {
67908         pNodeBase->pInputBuses = pNodeBase->_inputBuses;
67909     }
67910
67911     if (heapLayout.outputBusOffset != MA_SIZE_MAX) {
67912         pNodeBase->pOutputBuses = (ma_node_output_bus*)ma_offset_ptr(pHeap, heapLayout.inputBusOffset);
67913     } else {
67914         pNodeBase->pOutputBuses = pNodeBase->_outputBuses;
67915     }
67916
67917     if (heapLayout.cachedDataOffset != MA_SIZE_MAX) {
67918         pNodeBase->pCachedData = (float*)ma_offset_ptr(pHeap, heapLayout.cachedDataOffset);
67919         pNodeBase->cachedDataCapInFramesPerBus = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS;
67920     } else {
67921         pNodeBase->pCachedData = NULL;
67922     }
67923
67924
67925
67926     /* We need to run an initialization step for each input and output bus. */
67927     for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNodeBase); iInputBus += 1) {
67928         result = ma_node_input_bus_init(pConfig->pInputChannels[iInputBus], &pNodeBase->pInputBuses[iInputBus]);
67929         if (result != MA_SUCCESS) {
67930             return result;
67931         }
67932     }
67933
67934     for (iOutputBus = 0; iOutputBus < ma_node_get_output_bus_count(pNodeBase); iOutputBus += 1) {
67935         result = ma_node_output_bus_init(pNodeBase, iOutputBus, pConfig->pOutputChannels[iOutputBus], &pNodeBase->pOutputBuses[iOutputBus]);
67936         if (result != MA_SUCCESS) {
67937             return result;
67938         }
67939     }
67940
67941
67942     /* The cached data needs to be initialized to silence (or a sine wave tone if we're debugging). */
67943     if (pNodeBase->pCachedData != NULL) {
67944         ma_uint32 iBus;
67945
67946     #if 1   /* Toggle this between 0 and 1 to turn debugging on or off. 1 = fill with a sine wave for debugging; 0 = fill with silence. */
67947         /* For safety we'll go ahead and default the buffer to silence. */
67948         for (iBus = 0; iBus < ma_node_get_input_bus_count(pNodeBase); iBus += 1) {
67949             ma_silence_pcm_frames(ma_node_get_cached_input_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iBus]));
67950         }
67951         for (iBus = 0; iBus < ma_node_get_output_bus_count(pNodeBase); iBus += 1) {
67952             ma_silence_pcm_frames(ma_node_get_cached_output_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[iBus]));
67953         }
67954     #else
67955         /* For debugging. Default to a sine wave. */
67956         for (iBus = 0; iBus < ma_node_get_input_bus_count(pNodeBase); iBus += 1) {
67957             ma_debug_fill_pcm_frames_with_sine_wave(ma_node_get_cached_input_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[iBus]), 48000);
67958         }
67959         for (iBus = 0; iBus < ma_node_get_output_bus_count(pNodeBase); iBus += 1) {
67960             ma_debug_fill_pcm_frames_with_sine_wave(ma_node_get_cached_output_ptr(pNode, iBus), pNodeBase->cachedDataCapInFramesPerBus, ma_format_f32, ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[iBus]), 48000);
67961         }
67962     #endif
67963     }
67964
67965     return MA_SUCCESS;
67966 }
67967
67968 MA_API ma_result ma_node_init(ma_node_graph* pNodeGraph, const ma_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node* pNode)
67969 {
67970     ma_result result;
67971     size_t heapSizeInBytes;
67972     void* pHeap;
67973
67974     result = ma_node_get_heap_size(pConfig, &heapSizeInBytes);
67975     if (result != MA_SUCCESS) {
67976         return result;
67977     }
67978
67979     if (heapSizeInBytes > 0) {
67980         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
67981         if (pHeap == NULL) {
67982             return MA_OUT_OF_MEMORY;
67983         }
67984     } else {
67985         pHeap = NULL;
67986     }
67987
67988     result = ma_node_init_preallocated(pNodeGraph, pConfig, pHeap, pNode);
67989     if (result != MA_SUCCESS) {
67990         ma_free(pHeap, pAllocationCallbacks);
67991         return result;
67992     }
67993
67994     ((ma_node_base*)pNode)->_ownsHeap = MA_TRUE;
67995     return MA_SUCCESS;
67996 }
67997
67998 MA_API void ma_node_uninit(ma_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks)
67999 {
68000     ma_node_base* pNodeBase = (ma_node_base*)pNode;
68001
68002     if (pNodeBase == NULL) {
68003         return;
68004     }
68005
68006     /*
68007     The first thing we need to do is fully detach the node. This will detach all inputs and
68008     outputs. We need to do this first because it will sever the connection with the node graph and
68009     allow us to complete uninitialization without needing to worry about thread-safety with the
68010     audio thread. The detachment process will wait for any local processing of the node to finish.
68011     */
68012     ma_node_detach_full(pNode);
68013
68014     /*
68015     At this point the node should be completely unreferenced by the node graph and we can finish up
68016     the uninitialization process without needing to worry about thread-safety.
68017     */
68018     if (pNodeBase->_ownsHeap) {
68019         ma_free(pNodeBase->_pHeap, pAllocationCallbacks);
68020     }
68021 }
68022
68023 MA_API ma_node_graph* ma_node_get_node_graph(const ma_node* pNode)
68024 {
68025     if (pNode == NULL) {
68026         return NULL;
68027     }
68028
68029     return ((const ma_node_base*)pNode)->pNodeGraph;
68030 }
68031
68032 MA_API ma_uint32 ma_node_get_input_bus_count(const ma_node* pNode)
68033 {
68034     if (pNode == NULL) {
68035         return 0;
68036     }
68037
68038     return ((ma_node_base*)pNode)->inputBusCount;
68039 }
68040
68041 MA_API ma_uint32 ma_node_get_output_bus_count(const ma_node* pNode)
68042 {
68043     if (pNode == NULL) {
68044         return 0;
68045     }
68046
68047     return ((ma_node_base*)pNode)->outputBusCount;
68048 }
68049
68050
68051 MA_API ma_uint32 ma_node_get_input_channels(const ma_node* pNode, ma_uint32 inputBusIndex)
68052 {
68053     const ma_node_base* pNodeBase = (const ma_node_base*)pNode;
68054
68055     if (pNode == NULL) {
68056         return 0;
68057     }
68058
68059     if (inputBusIndex >= ma_node_get_input_bus_count(pNode)) {
68060         return 0;   /* Invalid bus index. */
68061     }
68062
68063     return ma_node_input_bus_get_channels(&pNodeBase->pInputBuses[inputBusIndex]);
68064 }
68065
68066 MA_API ma_uint32 ma_node_get_output_channels(const ma_node* pNode, ma_uint32 outputBusIndex)
68067 {
68068     const ma_node_base* pNodeBase = (const ma_node_base*)pNode;
68069
68070     if (pNode == NULL) {
68071         return 0;
68072     }
68073
68074     if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) {
68075         return 0;   /* Invalid bus index. */
68076     }
68077
68078     return ma_node_output_bus_get_channels(&pNodeBase->pOutputBuses[outputBusIndex]);
68079 }
68080
68081
68082 static ma_result ma_node_detach_full(ma_node* pNode)
68083 {
68084     ma_node_base* pNodeBase = (ma_node_base*)pNode;
68085     ma_uint32 iInputBus;
68086
68087     if (pNodeBase == NULL) {
68088         return MA_INVALID_ARGS;
68089     }
68090
68091     /*
68092     Make sure the node is completely detached first. This will not return until the output bus is
68093     guaranteed to no longer be referenced by the audio thread.
68094     */
68095     ma_node_detach_all_output_buses(pNode);
68096
68097     /*
68098     At this point all output buses will have been detached from the graph and we can be guaranteed
68099     that none of it's input nodes will be getting processed by the graph. We can detach these
68100     without needing to worry about the audio thread touching them.
68101     */
68102     for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNode); iInputBus += 1) {
68103         ma_node_input_bus* pInputBus;
68104         ma_node_output_bus* pOutputBus;
68105
68106         pInputBus = &pNodeBase->pInputBuses[iInputBus];
68107
68108         /*
68109         This is important. We cannot be using ma_node_input_bus_first() or ma_node_input_bus_next(). Those
68110         functions are specifically for the audio thread. We'll instead just manually iterate using standard
68111         linked list logic. We don't need to worry about the audio thread referencing these because the step
68112         above severed the connection to the graph.
68113         */
68114         for (pOutputBus = (ma_node_output_bus*)c89atomic_load_ptr(&pInputBus->head.pNext); pOutputBus != NULL; pOutputBus = (ma_node_output_bus*)c89atomic_load_ptr(&pOutputBus->pNext)) {
68115             ma_node_detach_output_bus(pOutputBus->pNode, pOutputBus->outputBusIndex);   /* This won't do any waiting in practice and should be efficient. */
68116         }
68117     }
68118
68119     return MA_SUCCESS;
68120 }
68121
68122 MA_API ma_result ma_node_detach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex)
68123 {
68124     ma_result result = MA_SUCCESS;
68125     ma_node_base* pNodeBase = (ma_node_base*)pNode;
68126     ma_node_base* pInputNodeBase;
68127
68128     if (pNode == NULL) {
68129         return MA_INVALID_ARGS;
68130     }
68131
68132     if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) {
68133         return MA_INVALID_ARGS; /* Invalid output bus index. */
68134     }
68135
68136     /* We need to lock the output bus because we need to inspect the input node and grab it's input bus. */
68137     ma_node_output_bus_lock(&pNodeBase->pOutputBuses[outputBusIndex]);
68138     {
68139         pInputNodeBase = (ma_node_base*)pNodeBase->pOutputBuses[outputBusIndex].pInputNode;
68140         if (pInputNodeBase != NULL) {
68141             ma_node_input_bus_detach__no_output_bus_lock(&pInputNodeBase->pInputBuses[pNodeBase->pOutputBuses[outputBusIndex].inputNodeInputBusIndex], &pNodeBase->pOutputBuses[outputBusIndex]);
68142         }
68143     }
68144     ma_node_output_bus_unlock(&pNodeBase->pOutputBuses[outputBusIndex]);
68145
68146     return result;
68147 }
68148
68149 MA_API ma_result ma_node_detach_all_output_buses(ma_node* pNode)
68150 {
68151     ma_uint32 iOutputBus;
68152
68153     if (pNode == NULL) {
68154         return MA_INVALID_ARGS;
68155     }
68156
68157     for (iOutputBus = 0; iOutputBus < ma_node_get_output_bus_count(pNode); iOutputBus += 1) {
68158         ma_node_detach_output_bus(pNode, iOutputBus);
68159     }
68160
68161     return MA_SUCCESS;
68162 }
68163
68164 MA_API ma_result ma_node_attach_output_bus(ma_node* pNode, ma_uint32 outputBusIndex, ma_node* pOtherNode, ma_uint32 otherNodeInputBusIndex)
68165 {
68166     ma_node_base* pNodeBase  = (ma_node_base*)pNode;
68167     ma_node_base* pOtherNodeBase = (ma_node_base*)pOtherNode;
68168
68169     if (pNodeBase == NULL || pOtherNodeBase == NULL) {
68170         return MA_INVALID_ARGS;
68171     }
68172
68173     if (pNodeBase == pOtherNodeBase) {
68174         return MA_INVALID_OPERATION;    /* Cannot attach a node to itself. */
68175     }
68176
68177     if (outputBusIndex >= ma_node_get_output_bus_count(pNode) || otherNodeInputBusIndex >= ma_node_get_input_bus_count(pOtherNode)) {
68178         return MA_INVALID_OPERATION;    /* Invalid bus index. */
68179     }
68180
68181     /* The output channel count of the output node must be the same as the input channel count of the input node. */
68182     if (ma_node_get_output_channels(pNode, outputBusIndex) != ma_node_get_input_channels(pOtherNode, otherNodeInputBusIndex)) {
68183         return MA_INVALID_OPERATION;    /* Channel count is incompatible. */
68184     }
68185
68186     /* This will deal with detaching if the output bus is already attached to something. */
68187     ma_node_input_bus_attach(&pOtherNodeBase->pInputBuses[otherNodeInputBusIndex], &pNodeBase->pOutputBuses[outputBusIndex], pOtherNode, otherNodeInputBusIndex);
68188
68189     return MA_SUCCESS;
68190 }
68191
68192 MA_API ma_result ma_node_set_output_bus_volume(ma_node* pNode, ma_uint32 outputBusIndex, float volume)
68193 {
68194     ma_node_base* pNodeBase = (ma_node_base*)pNode;
68195
68196     if (pNodeBase == NULL) {
68197         return MA_INVALID_ARGS;
68198     }
68199
68200     if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) {
68201         return MA_INVALID_ARGS; /* Invalid bus index. */
68202     }
68203
68204     return ma_node_output_bus_set_volume(&pNodeBase->pOutputBuses[outputBusIndex], volume);
68205 }
68206
68207 MA_API float ma_node_get_output_bus_volume(const ma_node* pNode, ma_uint32 outputBusIndex)
68208 {
68209     const ma_node_base* pNodeBase = (const ma_node_base*)pNode;
68210
68211     if (pNodeBase == NULL) {
68212         return 0;
68213     }
68214
68215     if (outputBusIndex >= ma_node_get_output_bus_count(pNode)) {
68216         return 0;   /* Invalid bus index. */
68217     }
68218
68219     return ma_node_output_bus_get_volume(&pNodeBase->pOutputBuses[outputBusIndex]);
68220 }
68221
68222 MA_API ma_result ma_node_set_state(ma_node* pNode, ma_node_state state)
68223 {
68224     ma_node_base* pNodeBase = (ma_node_base*)pNode;
68225
68226     if (pNodeBase == NULL) {
68227         return MA_INVALID_ARGS;
68228     }
68229
68230     c89atomic_exchange_i32(&pNodeBase->state, state);
68231
68232     return MA_SUCCESS;
68233 }
68234
68235 MA_API ma_node_state ma_node_get_state(const ma_node* pNode)
68236 {
68237     const ma_node_base* pNodeBase = (const ma_node_base*)pNode;
68238
68239     if (pNodeBase == NULL) {
68240         return ma_node_state_stopped;
68241     }
68242
68243     return (ma_node_state)c89atomic_load_i32(&pNodeBase->state);
68244 }
68245
68246 MA_API ma_result ma_node_set_state_time(ma_node* pNode, ma_node_state state, ma_uint64 globalTime)
68247 {
68248     if (pNode == NULL) {
68249         return MA_INVALID_ARGS;
68250     }
68251
68252     /* Validation check for safety since we'll be using this as an index into stateTimes[]. */
68253     if (state != ma_node_state_started && state != ma_node_state_stopped) {
68254         return MA_INVALID_ARGS;
68255     }
68256
68257     c89atomic_exchange_64(&((ma_node_base*)pNode)->stateTimes[state], globalTime);
68258
68259     return MA_SUCCESS;
68260 }
68261
68262 MA_API ma_uint64 ma_node_get_state_time(const ma_node* pNode, ma_node_state state)
68263 {
68264     if (pNode == NULL) {
68265         return 0;
68266     }
68267
68268     /* Validation check for safety since we'll be using this as an index into stateTimes[]. */
68269     if (state != ma_node_state_started && state != ma_node_state_stopped) {
68270         return 0;
68271     }
68272
68273     return c89atomic_load_64(&((ma_node_base*)pNode)->stateTimes[state]);
68274 }
68275
68276 MA_API ma_node_state ma_node_get_state_by_time(const ma_node* pNode, ma_uint64 globalTime)
68277 {
68278     if (pNode == NULL) {
68279         return ma_node_state_stopped;
68280     }
68281
68282     return ma_node_get_state_by_time_range(pNode, globalTime, globalTime);
68283 }
68284
68285 MA_API ma_node_state ma_node_get_state_by_time_range(const ma_node* pNode, ma_uint64 globalTimeBeg, ma_uint64 globalTimeEnd)
68286 {
68287     ma_node_state state;
68288
68289     if (pNode == NULL) {
68290         return ma_node_state_stopped;
68291     }
68292
68293     state = ma_node_get_state(pNode);
68294
68295     /* An explicitly stopped node is always stopped. */
68296     if (state == ma_node_state_stopped) {
68297         return ma_node_state_stopped;
68298     }
68299
68300     /*
68301     Getting here means the node is marked as started, but it may still not be truly started due to
68302     it's start time not having been reached yet. Also, the stop time may have also been reached in
68303     which case it'll be considered stopped.
68304     */
68305     if (ma_node_get_state_time(pNode, ma_node_state_started) > globalTimeBeg) {
68306         return ma_node_state_stopped;   /* Start time has not yet been reached. */
68307     }
68308
68309     if (ma_node_get_state_time(pNode, ma_node_state_stopped) <= globalTimeEnd) {
68310         return ma_node_state_stopped;   /* Stop time has been reached. */
68311     }
68312
68313     /* Getting here means the node is marked as started and is within it's start/stop times. */
68314     return ma_node_state_started;
68315 }
68316
68317 MA_API ma_uint64 ma_node_get_time(const ma_node* pNode)
68318 {
68319     if (pNode == NULL) {
68320         return 0;
68321     }
68322
68323     return c89atomic_load_64(&((ma_node_base*)pNode)->localTime);
68324 }
68325
68326 MA_API ma_result ma_node_set_time(ma_node* pNode, ma_uint64 localTime)
68327 {
68328     if (pNode == NULL) {
68329         return MA_INVALID_ARGS;
68330     }
68331
68332     c89atomic_exchange_64(&((ma_node_base*)pNode)->localTime, localTime);
68333
68334     return MA_SUCCESS;
68335 }
68336
68337
68338
68339 static void ma_node_process_pcm_frames_internal(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
68340 {
68341     ma_node_base* pNodeBase = (ma_node_base*)pNode;
68342
68343     MA_ASSERT(pNode != NULL);
68344
68345     if (pNodeBase->vtable->onProcess) {
68346         pNodeBase->vtable->onProcess(pNode, ppFramesIn, pFrameCountIn, ppFramesOut, pFrameCountOut);
68347     }
68348 }
68349
68350 static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusIndex, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime)
68351 {
68352     ma_node_base* pNodeBase = (ma_node_base*)pNode;
68353     ma_result result = MA_SUCCESS;
68354     ma_uint32 iInputBus;
68355     ma_uint32 iOutputBus;
68356     ma_uint32 inputBusCount;
68357     ma_uint32 outputBusCount;
68358     ma_uint32 totalFramesRead = 0;
68359     float* ppFramesIn[MA_MAX_NODE_BUS_COUNT];
68360     float* ppFramesOut[MA_MAX_NODE_BUS_COUNT];
68361     ma_uint64 globalTimeBeg;
68362     ma_uint64 globalTimeEnd;
68363     ma_uint64 startTime;
68364     ma_uint64 stopTime;
68365     ma_uint32 timeOffsetBeg;
68366     ma_uint32 timeOffsetEnd;
68367     ma_uint32 frameCountIn;
68368     ma_uint32 frameCountOut;
68369
68370     /*
68371     pFramesRead is mandatory. It must be used to determine how many frames were read. It's normal and
68372     expected that the number of frames read may be different to that requested. Therefore, the caller
68373     must look at this value to correctly determine how many frames were read.
68374     */
68375     MA_ASSERT(pFramesRead != NULL); /* <-- If you've triggered this assert, you're using this function wrong. You *must* use this variable and inspect it after the call returns. */
68376     if (pFramesRead == NULL) {
68377         return MA_INVALID_ARGS;
68378     }
68379
68380     *pFramesRead = 0;   /* Safety. */
68381
68382     if (pNodeBase == NULL) {
68383         return MA_INVALID_ARGS;
68384     }
68385
68386     if (outputBusIndex >= ma_node_get_output_bus_count(pNodeBase)) {
68387         return MA_INVALID_ARGS; /* Invalid output bus index. */
68388     }
68389
68390     /* Don't do anything if we're in a stopped state. */
68391     if (ma_node_get_state_by_time_range(pNode, globalTime, globalTime + frameCount) != ma_node_state_started) {
68392         return MA_SUCCESS;  /* We're in a stopped state. This is not an error - we just need to not read anything. */
68393     }
68394
68395
68396     globalTimeBeg = globalTime;
68397     globalTimeEnd = globalTime + frameCount;
68398     startTime = ma_node_get_state_time(pNode, ma_node_state_started);
68399     stopTime  = ma_node_get_state_time(pNode, ma_node_state_stopped);
68400
68401     /*
68402     At this point we know that we are inside our start/stop times. However, we may need to adjust
68403     our frame count and output pointer to accomodate since we could be straddling the time period
68404     that this function is getting called for.
68405
68406     It's possible (and likely) that the start time does not line up with the output buffer. We
68407     therefore need to offset it by a number of frames to accomodate. The same thing applies for
68408     the stop time.
68409     */
68410     timeOffsetBeg = (globalTimeBeg < startTime) ? (ma_uint32)(globalTimeEnd - startTime) : 0;
68411     timeOffsetEnd = (globalTimeEnd > stopTime)  ? (ma_uint32)(globalTimeEnd - stopTime)  : 0;
68412
68413     /* Trim based on the start offset. We need to silence the start of the buffer. */
68414     if (timeOffsetBeg > 0) {
68415         ma_silence_pcm_frames(pFramesOut, timeOffsetBeg, ma_format_f32, ma_node_get_output_channels(pNode, outputBusIndex));
68416         pFramesOut += timeOffsetBeg * ma_node_get_output_channels(pNode, outputBusIndex);
68417         frameCount -= timeOffsetBeg;
68418     }
68419
68420     /* Trim based on the end offset. We don't need to silence the tail section because we'll just have a reduced value written to pFramesRead. */
68421     if (timeOffsetEnd > 0) {
68422         frameCount -= timeOffsetEnd;
68423     }
68424
68425
68426     /* We run on different paths depending on the bus counts. */
68427     inputBusCount  = ma_node_get_input_bus_count(pNode);
68428     outputBusCount = ma_node_get_output_bus_count(pNode);
68429
68430     /*
68431     Run a simplified path when there are no inputs and one output. In this case there's nothing to
68432     actually read and we can go straight to output. This is a very common scenario because the vast
68433     majority of data source nodes will use this setup so this optimization I think is worthwhile.
68434     */
68435     if (inputBusCount == 0 && outputBusCount == 1) {
68436         /* Fast path. No need to read from input and no need for any caching. */
68437         frameCountIn  = 0;
68438         frameCountOut = frameCount;    /* Just read as much as we can. The callback will return what was actually read. */
68439
68440         ppFramesOut[0] = pFramesOut;
68441         ma_node_process_pcm_frames_internal(pNode, NULL, &frameCountIn, ppFramesOut, &frameCountOut);
68442         totalFramesRead = frameCountOut;
68443     } else {
68444         /* Slow path. Need to read input data. */
68445         if ((pNodeBase->vtable->flags & MA_NODE_FLAG_PASSTHROUGH) != 0) {
68446             /*
68447             Fast path. We're running a passthrough. We need to read directly into the output buffer, but
68448             still fire the callback so that event handling and trigger nodes can do their thing. Since
68449             it's a passthrough there's no need for any kind of caching logic.
68450             */
68451             MA_ASSERT(outputBusCount == inputBusCount);
68452             MA_ASSERT(outputBusCount == 1);
68453             MA_ASSERT(outputBusIndex == 0);
68454
68455             /* We just read directly from input bus to output buffer, and then afterwards fire the callback. */
68456             ppFramesOut[0] = pFramesOut;
68457             ppFramesIn[0] = ppFramesOut[0];
68458
68459             result = ma_node_input_bus_read_pcm_frames(pNodeBase, &pNodeBase->pInputBuses[0], ppFramesIn[0], frameCount, &totalFramesRead, globalTime);
68460             if (result == MA_SUCCESS) {
68461                 /* Even though it's a passthrough, we still need to fire the callback. */
68462                 frameCountIn  = totalFramesRead;
68463                 frameCountOut = totalFramesRead;
68464
68465                 if (totalFramesRead > 0) {
68466                     ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut);  /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */
68467                 }
68468
68469                 /*
68470                 A passthrough should never have modified the input and output frame counts. If you're
68471                 triggering these assers you need to fix your processing callback.
68472                 */
68473                 MA_ASSERT(frameCountIn  == totalFramesRead);
68474                 MA_ASSERT(frameCountOut == totalFramesRead);
68475             }
68476         } else {
68477             /* Slow path. Need to do caching. */
68478             ma_uint32 framesToProcessIn;
68479             ma_uint32 framesToProcessOut;
68480             ma_bool32 consumeNullInput = MA_FALSE;
68481
68482             /*
68483             We use frameCount as a basis for the number of frames to read since that's what's being
68484             requested, however we still need to clamp it to whatever can fit in the cache.
68485
68486             This will also be used as the basis for determining how many input frames to read. This is
68487             not ideal because it can result in too many input frames being read which introduces latency.
68488             To solve this, nodes can implement an optional callback called onGetRequiredInputFrameCount
68489             which is used as hint to miniaudio as to how many input frames it needs to read at a time. This
68490             callback is completely optional, and if it's not set, miniaudio will assume `frameCount`.
68491
68492             This function will be called multiple times for each period of time, once for each output node.
68493             We cannot read from each input node each time this function is called. Instead we need to check
68494             whether or not this is first output bus to be read from for this time period, and if so, read
68495             from our input data.
68496
68497             To determine whether or not we're ready to read data, we check a flag. There will be one flag
68498             for each output. When the flag is set, it means data has been read previously and that we're
68499             ready to advance time forward for our input nodes by reading fresh data.
68500             */
68501             framesToProcessOut = frameCount;
68502             if (framesToProcessOut > pNodeBase->cachedDataCapInFramesPerBus) {
68503                 framesToProcessOut = pNodeBase->cachedDataCapInFramesPerBus;
68504             }
68505
68506             framesToProcessIn  = frameCount;
68507             if (pNodeBase->vtable->onGetRequiredInputFrameCount) {
68508                 pNodeBase->vtable->onGetRequiredInputFrameCount(pNode, framesToProcessOut, &framesToProcessIn); /* <-- It does not matter if this fails. */
68509             }
68510             if (framesToProcessIn > pNodeBase->cachedDataCapInFramesPerBus) {
68511                 framesToProcessIn = pNodeBase->cachedDataCapInFramesPerBus;
68512             }
68513
68514
68515             MA_ASSERT(framesToProcessIn  <= 0xFFFF);
68516             MA_ASSERT(framesToProcessOut <= 0xFFFF);
68517
68518             if (ma_node_output_bus_has_read(&pNodeBase->pOutputBuses[outputBusIndex])) {
68519                 /* Getting here means we need to do another round of processing. */
68520                 pNodeBase->cachedFrameCountOut = 0;
68521
68522                 for (;;) {
68523                     frameCountOut = 0;
68524
68525                     /*
68526                     We need to prepare our output frame pointers for processing. In the same iteration we need
68527                     to mark every output bus as unread so that future calls to this function for different buses
68528                     for the current time period don't pull in data when they should instead be reading from cache.
68529                     */
68530                     for (iOutputBus = 0; iOutputBus < outputBusCount; iOutputBus += 1) {
68531                         ma_node_output_bus_set_has_read(&pNodeBase->pOutputBuses[iOutputBus], MA_FALSE); /* <-- This is what tells the next calls to this function for other output buses for this time period to read from cache instead of pulling in more data. */
68532                         ppFramesOut[iOutputBus] = ma_node_get_cached_output_ptr(pNode, iOutputBus);
68533                     }
68534
68535                     /* We only need to read from input buses if there isn't already some data in the cache. */
68536                     if (pNodeBase->cachedFrameCountIn == 0) {
68537                         ma_uint32 maxFramesReadIn = 0;
68538
68539                         /* Here is where we pull in data from the input buses. This is what will trigger an advance in time. */
68540                         for (iInputBus = 0; iInputBus < inputBusCount; iInputBus += 1) {
68541                             ma_uint32 framesRead;
68542
68543                             /* The first thing to do is get the offset within our bulk allocation to store this input data. */
68544                             ppFramesIn[iInputBus] = ma_node_get_cached_input_ptr(pNode, iInputBus);
68545
68546                             /* Once we've determined our destination pointer we can read. Note that we must inspect the number of frames read and fill any leftovers with silence for safety. */
68547                             result = ma_node_input_bus_read_pcm_frames(pNodeBase, &pNodeBase->pInputBuses[iInputBus], ppFramesIn[iInputBus], framesToProcessIn, &framesRead, globalTime);
68548                             if (result != MA_SUCCESS) {
68549                                 /* It doesn't really matter if we fail because we'll just fill with silence. */
68550                                 framesRead = 0; /* Just for safety, but I don't think it's really needed. */
68551                             }
68552
68553                             /* TODO: Minor optimization opportunity here. If no frames were read and the buffer is already filled with silence, no need to re-silence it. */
68554                             /* Any leftover frames need to silenced for safety. */
68555                             if (framesRead < framesToProcessIn) {
68556                                 ma_silence_pcm_frames(ppFramesIn[iInputBus] + (framesRead * ma_node_get_input_channels(pNodeBase, iInputBus)), (framesToProcessIn - framesRead), ma_format_f32, ma_node_get_input_channels(pNodeBase, iInputBus));
68557                             }
68558
68559                             maxFramesReadIn = ma_max(maxFramesReadIn, framesRead);
68560                         }
68561
68562                         /* This was a fresh load of input data so reset our consumption counter. */
68563                         pNodeBase->consumedFrameCountIn = 0;
68564
68565                         /*
68566                         We don't want to keep processing if there's nothing to process, so set the number of cached
68567                         input frames to the maximum number we read from each attachment (the lesser will be padded
68568                         with silence). If we didn't read anything, this will be set to 0 and the entire buffer will
68569                         have been assigned to silence. This being equal to 0 is an important property for us because
68570                         it allows us to detect when NULL can be passed into the processing callback for the input
68571                         buffer for the purpose of continuous processing.
68572                         */
68573                         pNodeBase->cachedFrameCountIn = (ma_uint16)maxFramesReadIn;
68574                     } else {
68575                         /* We don't need to read anything, but we do need to prepare our input frame pointers. */
68576                         for (iInputBus = 0; iInputBus < inputBusCount; iInputBus += 1) {
68577                             ppFramesIn[iInputBus] = ma_node_get_cached_input_ptr(pNode, iInputBus) + (pNodeBase->consumedFrameCountIn * ma_node_get_input_channels(pNodeBase, iInputBus));
68578                         }
68579                     }
68580
68581                     /*
68582                     At this point we have our input data so now we need to do some processing. Sneaky little
68583                     optimization here - we can set the pointer to the output buffer for this output bus so
68584                     that the final copy into the output buffer is done directly by onProcess().
68585                     */
68586                     if (pFramesOut != NULL) {
68587                         ppFramesOut[outputBusIndex] = ma_offset_pcm_frames_ptr_f32(pFramesOut, pNodeBase->cachedFrameCountOut, ma_node_get_output_channels(pNode, outputBusIndex));
68588                     }
68589
68590
68591                     /* Give the processing function the entire capacity of the output buffer. */
68592                     frameCountOut = (framesToProcessOut - pNodeBase->cachedFrameCountOut);
68593
68594                     /*
68595                     We need to treat nodes with continuous processing a little differently. For these ones,
68596                     we always want to fire the callback with the requested number of frames, regardless of
68597                     pNodeBase->cachedFrameCountIn, which could be 0. Also, we want to check if we can pass
68598                     in NULL for the input buffer to the callback.
68599                     */
68600                     if ((pNodeBase->vtable->flags & MA_NODE_FLAG_CONTINUOUS_PROCESSING) != 0) {
68601                         /* We're using continuous processing. Make sure we specify the whole frame count at all times. */
68602                         frameCountIn = framesToProcessIn;    /* Give the processing function as much input data as we've got in the buffer, including any silenced padding from short reads. */
68603
68604                         if ((pNodeBase->vtable->flags & MA_NODE_FLAG_ALLOW_NULL_INPUT) != 0 && pNodeBase->consumedFrameCountIn == 0 && pNodeBase->cachedFrameCountIn == 0) {
68605                             consumeNullInput = MA_TRUE;
68606                         } else {
68607                             consumeNullInput = MA_FALSE;
68608                         }
68609
68610                         /*
68611                         Since we're using continuous processing we're always passing in a full frame count
68612                         regardless of how much input data was read. If this is greater than what we read as
68613                         input, we'll end up with an underflow. We instead need to make sure our cached frame
68614                         count is set to the number of frames we'll be passing to the data callback. Not
68615                         doing this will result in an underflow when we "consume" the cached data later on.
68616
68617                         Note that this check needs to be done after the "consumeNullInput" check above because
68618                         we use the property of cachedFrameCountIn being 0 to determine whether or not we
68619                         should be passing in a null pointer to the processing callback for when the node is
68620                         configured with MA_NODE_FLAG_ALLOW_NULL_INPUT.
68621                         */
68622                         if (pNodeBase->cachedFrameCountIn < (ma_uint16)frameCountIn) {
68623                             pNodeBase->cachedFrameCountIn = (ma_uint16)frameCountIn;
68624                         }
68625                     } else {
68626                         frameCountIn = pNodeBase->cachedFrameCountIn;  /* Give the processing function as much valid input data as we've got. */
68627                         consumeNullInput = MA_FALSE;
68628                     }
68629
68630                     /*
68631                     Process data slightly differently depending on whether or not we're consuming NULL
68632                     input (checked just above).
68633                     */
68634                     if (consumeNullInput) {
68635                         ma_node_process_pcm_frames_internal(pNode, NULL, &frameCountIn, ppFramesOut, &frameCountOut);
68636                     } else {
68637                         /*
68638                         We want to skip processing if there's no input data, but we can only do that safely if
68639                         we know that there is no chance of any output frames being produced. If continuous
68640                         processing is being used, this won't be a problem because the input frame count will
68641                         always be non-0. However, if continuous processing is *not* enabled and input and output
68642                         data is processed at different rates, we still need to process that last input frame
68643                         because there could be a few excess output frames needing to be produced from cached
68644                         data. The `MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES` flag is used as the indicator for
68645                         determining whether or not we need to process the node even when there are no input
68646                         frames available right now.
68647                         */
68648                         if (frameCountIn > 0 || (pNodeBase->vtable->flags & MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES) != 0) {
68649                             ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut);    /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */
68650                         } else {
68651                             frameCountOut = 0;  /* No data was processed. */
68652                         }
68653                     }
68654
68655                     /*
68656                     Thanks to our sneaky optimization above we don't need to do any data copying directly into
68657                     the output buffer - the onProcess() callback just did that for us. We do, however, need to
68658                     apply the number of input and output frames that were processed. Note that due to continuous
68659                     processing above, we need to do explicit checks here. If we just consumed a NULL input
68660                     buffer it means that no actual input data was processed from the internal buffers and we
68661                     don't want to be modifying any counters.
68662                     */
68663                     if (consumeNullInput == MA_FALSE) {
68664                         pNodeBase->consumedFrameCountIn += (ma_uint16)frameCountIn;
68665                         pNodeBase->cachedFrameCountIn   -= (ma_uint16)frameCountIn;
68666                     }
68667
68668                     /* The cached output frame count is always equal to what we just read. */
68669                     pNodeBase->cachedFrameCountOut += (ma_uint16)frameCountOut;
68670
68671                     /* If we couldn't process any data, we're done. The loop needs to be terminated here or else we'll get stuck in a loop. */
68672                     if (pNodeBase->cachedFrameCountOut == framesToProcessOut || (frameCountOut == 0 && frameCountIn == 0)) {
68673                         break;
68674                     }
68675                 }
68676             } else {
68677                 /*
68678                 We're not needing to read anything from the input buffer so just read directly from our
68679                 already-processed data.
68680                 */
68681                 if (pFramesOut != NULL) {
68682                     ma_copy_pcm_frames(pFramesOut, ma_node_get_cached_output_ptr(pNodeBase, outputBusIndex), pNodeBase->cachedFrameCountOut, ma_format_f32, ma_node_get_output_channels(pNodeBase, outputBusIndex));
68683                 }
68684             }
68685
68686             /* The number of frames read is always equal to the number of cached output frames. */
68687             totalFramesRead = pNodeBase->cachedFrameCountOut;
68688
68689             /* Now that we've read the data, make sure our read flag is set. */
68690             ma_node_output_bus_set_has_read(&pNodeBase->pOutputBuses[outputBusIndex], MA_TRUE);
68691         }
68692     }
68693     
68694     /* Apply volume, if necessary. */
68695     ma_apply_volume_factor_f32(pFramesOut, totalFramesRead * ma_node_get_output_channels(pNodeBase, outputBusIndex), ma_node_output_bus_get_volume(&pNodeBase->pOutputBuses[outputBusIndex]));
68696
68697     /* Advance our local time forward. */
68698     c89atomic_fetch_add_64(&pNodeBase->localTime, (ma_uint64)totalFramesRead);
68699
68700     *pFramesRead = totalFramesRead + timeOffsetBeg; /* Must include the silenced section at the start of the buffer. */
68701     return result;
68702 }
68703
68704
68705
68706
68707 /* Data source node. */
68708 MA_API ma_data_source_node_config ma_data_source_node_config_init(ma_data_source* pDataSource)
68709 {
68710     ma_data_source_node_config config;
68711
68712     MA_ZERO_OBJECT(&config);
68713     config.nodeConfig  = ma_node_config_init();
68714     config.pDataSource = pDataSource;
68715
68716     return config;
68717 }
68718
68719
68720 static void ma_data_source_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
68721 {
68722     ma_data_source_node* pDataSourceNode = (ma_data_source_node*)pNode;
68723     ma_format format;
68724     ma_uint32 channels;
68725     ma_uint32 frameCount;
68726     ma_uint64 framesRead = 0;
68727
68728     MA_ASSERT(pDataSourceNode != NULL);
68729     MA_ASSERT(pDataSourceNode->pDataSource != NULL);
68730     MA_ASSERT(ma_node_get_input_bus_count(pDataSourceNode)  == 0);
68731     MA_ASSERT(ma_node_get_output_bus_count(pDataSourceNode) == 1);
68732
68733     /* We don't want to read from ppFramesIn at all. Instead we read from the data source. */
68734     (void)ppFramesIn;
68735     (void)pFrameCountIn;
68736
68737     frameCount = *pFrameCountOut;
68738
68739     /* miniaudio should never be calling this with a frame count of zero. */
68740     MA_ASSERT(frameCount > 0);
68741
68742     if (ma_data_source_get_data_format(pDataSourceNode->pDataSource, &format, &channels, NULL, NULL, 0) == MA_SUCCESS) { /* <-- Don't care about sample rate here. */
68743         /* The node graph system requires samples be in floating point format. This is checked in ma_data_source_node_init(). */
68744         MA_ASSERT(format == ma_format_f32);
68745         (void)format;   /* Just to silence some static analysis tools. */
68746
68747         ma_data_source_read_pcm_frames(pDataSourceNode->pDataSource, ppFramesOut[0], frameCount, &framesRead);
68748     }
68749
68750     *pFrameCountOut = (ma_uint32)framesRead;
68751 }
68752
68753 static ma_node_vtable g_ma_data_source_node_vtable =
68754 {
68755     ma_data_source_node_process_pcm_frames,
68756     NULL,   /* onGetRequiredInputFrameCount */
68757     0,      /* 0 input buses. */
68758     1,      /* 1 output bus. */
68759     0
68760 };
68761
68762 MA_API ma_result ma_data_source_node_init(ma_node_graph* pNodeGraph, const ma_data_source_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source_node* pDataSourceNode)
68763 {
68764     ma_result result;
68765     ma_format format;   /* For validating the format, which must be ma_format_f32. */
68766     ma_uint32 channels; /* For specifying the channel count of the output bus. */
68767     ma_node_config baseConfig;
68768
68769     if (pDataSourceNode == NULL) {
68770         return MA_INVALID_ARGS;
68771     }
68772
68773     MA_ZERO_OBJECT(pDataSourceNode);
68774
68775     if (pConfig == NULL) {
68776         return MA_INVALID_ARGS;
68777     }
68778
68779     result = ma_data_source_get_data_format(pConfig->pDataSource, &format, &channels, NULL, NULL, 0);    /* Don't care about sample rate. This will check pDataSource for NULL. */
68780     if (result != MA_SUCCESS) {
68781         return result;
68782     }
68783
68784     MA_ASSERT(format == ma_format_f32); /* <-- If you've triggered this it means your data source is not outputting floating-point samples. You must configure your data source to use ma_format_f32. */
68785     if (format != ma_format_f32) {
68786         return MA_INVALID_ARGS; /* Invalid format. */
68787     }
68788
68789     /* The channel count is defined by the data source. If the caller has manually changed the channels we just ignore it. */
68790     baseConfig = pConfig->nodeConfig;
68791     baseConfig.vtable = &g_ma_data_source_node_vtable;  /* Explicitly set the vtable here to prevent callers from setting it incorrectly. */
68792
68793     /*
68794     The channel count is defined by the data source. It is invalid for the caller to manually set
68795     the channel counts in the config. `ma_data_source_node_config_init()` will have defaulted the
68796     channel count pointer to NULL which is how it must remain. If you trigger any of these asserts
68797     it means you're explicitly setting the channel count. Instead, configure the output channel
68798     count of your data source to be the necessary channel count.
68799     */
68800     if (baseConfig.pOutputChannels != NULL) {
68801         return MA_INVALID_ARGS;
68802     }
68803
68804     baseConfig.pOutputChannels = &channels;
68805
68806     result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pDataSourceNode->base);
68807     if (result != MA_SUCCESS) {
68808         return result;
68809     }
68810
68811     pDataSourceNode->pDataSource = pConfig->pDataSource;
68812
68813     return MA_SUCCESS;
68814 }
68815
68816 MA_API void ma_data_source_node_uninit(ma_data_source_node* pDataSourceNode, const ma_allocation_callbacks* pAllocationCallbacks)
68817 {
68818     ma_node_uninit(&pDataSourceNode->base, pAllocationCallbacks);
68819 }
68820
68821 MA_API ma_result ma_data_source_node_set_looping(ma_data_source_node* pDataSourceNode, ma_bool32 isLooping)
68822 {
68823     if (pDataSourceNode == NULL) {
68824         return MA_INVALID_ARGS;
68825     }
68826
68827     return ma_data_source_set_looping(pDataSourceNode->pDataSource, isLooping);
68828 }
68829
68830 MA_API ma_bool32 ma_data_source_node_is_looping(ma_data_source_node* pDataSourceNode)
68831 {
68832     if (pDataSourceNode == NULL) {
68833         return MA_FALSE;
68834     }
68835
68836     return ma_data_source_is_looping(pDataSourceNode->pDataSource);
68837 }
68838
68839
68840
68841 /* Splitter Node. */
68842 MA_API ma_splitter_node_config ma_splitter_node_config_init(ma_uint32 channels)
68843 {
68844     ma_splitter_node_config config;
68845
68846     MA_ZERO_OBJECT(&config);
68847     config.nodeConfig = ma_node_config_init();
68848     config.channels   = channels;
68849
68850     return config;
68851 }
68852
68853
68854 static void ma_splitter_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
68855 {
68856     ma_node_base* pNodeBase = (ma_node_base*)pNode;
68857     ma_uint32 iOutputBus;
68858     ma_uint32 channels;
68859
68860     MA_ASSERT(pNodeBase != NULL);
68861     MA_ASSERT(ma_node_get_input_bus_count(pNodeBase)  == 1);
68862     MA_ASSERT(ma_node_get_output_bus_count(pNodeBase) >= 2);
68863
68864     /* We don't need to consider the input frame count - it'll be the same as the output frame count and we process everything. */
68865     (void)pFrameCountIn;
68866
68867     /* NOTE: This assumes the same number of channels for all inputs and outputs. This was checked in ma_splitter_node_init(). */
68868     channels = ma_node_get_input_channels(pNodeBase, 0);
68869
68870     /* Splitting is just copying the first input bus and copying it over to each output bus. */
68871     for (iOutputBus = 0; iOutputBus < ma_node_get_output_bus_count(pNodeBase); iOutputBus += 1) {
68872         ma_copy_pcm_frames(ppFramesOut[iOutputBus], ppFramesIn[0], *pFrameCountOut, ma_format_f32, channels);
68873     }
68874 }
68875
68876 static ma_node_vtable g_ma_splitter_node_vtable =
68877 {
68878     ma_splitter_node_process_pcm_frames,
68879     NULL,   /* onGetRequiredInputFrameCount */
68880     1,      /* 1 input bus. */
68881     2,      /* 2 output buses. */
68882     0
68883 };
68884
68885 MA_API ma_result ma_splitter_node_init(ma_node_graph* pNodeGraph, const ma_splitter_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_splitter_node* pSplitterNode)
68886 {
68887     ma_result result;
68888     ma_node_config baseConfig;
68889     ma_uint32 pInputChannels[1];
68890     ma_uint32 pOutputChannels[2];
68891
68892     if (pSplitterNode == NULL) {
68893         return MA_INVALID_ARGS;
68894     }
68895
68896     MA_ZERO_OBJECT(pSplitterNode);
68897
68898     if (pConfig == NULL) {
68899         return MA_INVALID_ARGS;
68900     }
68901
68902     /* Splitters require the same number of channels between inputs and outputs. */
68903     pInputChannels[0]  = pConfig->channels;
68904     pOutputChannels[0] = pConfig->channels;
68905     pOutputChannels[1] = pConfig->channels;
68906
68907     baseConfig = pConfig->nodeConfig;
68908     baseConfig.vtable = &g_ma_splitter_node_vtable;
68909     baseConfig.pInputChannels  = pInputChannels;
68910     baseConfig.pOutputChannels = pOutputChannels;
68911
68912     result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pSplitterNode->base);
68913     if (result != MA_SUCCESS) {
68914         return result;  /* Failed to initialize the base node. */
68915     }
68916
68917     return MA_SUCCESS;
68918 }
68919
68920 MA_API void ma_splitter_node_uninit(ma_splitter_node* pSplitterNode, const ma_allocation_callbacks* pAllocationCallbacks)
68921 {
68922     ma_node_uninit(pSplitterNode, pAllocationCallbacks);
68923 }
68924
68925
68926 /*
68927 Biquad Node
68928 */
68929 MA_API ma_biquad_node_config ma_biquad_node_config_init(ma_uint32 channels, float b0, float b1, float b2, float a0, float a1, float a2)
68930 {
68931     ma_biquad_node_config config;
68932
68933     config.nodeConfig = ma_node_config_init();
68934     config.biquad = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2);
68935
68936     return config;
68937 }
68938
68939 static void ma_biquad_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
68940 {
68941     ma_biquad_node* pLPFNode = (ma_biquad_node*)pNode;
68942
68943     MA_ASSERT(pNode != NULL);
68944     (void)pFrameCountIn;
68945
68946     ma_biquad_process_pcm_frames(&pLPFNode->biquad, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut);
68947 }
68948
68949 static ma_node_vtable g_ma_biquad_node_vtable =
68950 {
68951     ma_biquad_node_process_pcm_frames,
68952     NULL,   /* onGetRequiredInputFrameCount */
68953     1,      /* One input. */
68954     1,      /* One output. */
68955     0       /* Default flags. */
68956 };
68957
68958 MA_API ma_result ma_biquad_node_init(ma_node_graph* pNodeGraph, const ma_biquad_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad_node* pNode)
68959 {
68960     ma_result result;
68961     ma_node_config baseNodeConfig;
68962
68963     if (pNode == NULL) {
68964         return MA_INVALID_ARGS;
68965     }
68966
68967     MA_ZERO_OBJECT(pNode);
68968
68969     if (pConfig == NULL) {
68970         return MA_INVALID_ARGS;
68971     }
68972
68973     if (pConfig->biquad.format != ma_format_f32) {
68974         return MA_INVALID_ARGS; /* The format must be f32. */
68975     }
68976
68977     result = ma_biquad_init(&pConfig->biquad, pAllocationCallbacks, &pNode->biquad);
68978     if (result != MA_SUCCESS) {
68979         return result;
68980     }
68981
68982     baseNodeConfig = ma_node_config_init();
68983     baseNodeConfig.vtable          = &g_ma_biquad_node_vtable;
68984     baseNodeConfig.pInputChannels  = &pConfig->biquad.channels;
68985     baseNodeConfig.pOutputChannels = &pConfig->biquad.channels;
68986
68987     result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode);
68988     if (result != MA_SUCCESS) {
68989         return result;
68990     }
68991
68992     return result;
68993 }
68994
68995 MA_API ma_result ma_biquad_node_reinit(const ma_biquad_config* pConfig, ma_biquad_node* pNode)
68996 {
68997     ma_biquad_node* pLPFNode = (ma_biquad_node*)pNode;
68998
68999     MA_ASSERT(pNode != NULL);
69000
69001     return ma_biquad_reinit(pConfig, &pLPFNode->biquad);
69002 }
69003
69004 MA_API void ma_biquad_node_uninit(ma_biquad_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks)
69005 {
69006     ma_biquad_node* pLPFNode = (ma_biquad_node*)pNode;
69007
69008     if (pNode == NULL) {
69009         return;
69010     }
69011
69012     ma_node_uninit(pNode, pAllocationCallbacks);
69013     ma_biquad_uninit(&pLPFNode->biquad, pAllocationCallbacks);
69014 }
69015
69016
69017
69018 /*
69019 Low Pass Filter Node
69020 */
69021 MA_API ma_lpf_node_config ma_lpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
69022 {
69023     ma_lpf_node_config config;
69024
69025     config.nodeConfig = ma_node_config_init();
69026     config.lpf = ma_lpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order);
69027
69028     return config;
69029 }
69030
69031 static void ma_lpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
69032 {
69033     ma_lpf_node* pLPFNode = (ma_lpf_node*)pNode;
69034
69035     MA_ASSERT(pNode != NULL);
69036     (void)pFrameCountIn;
69037
69038     ma_lpf_process_pcm_frames(&pLPFNode->lpf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut);
69039 }
69040
69041 static ma_node_vtable g_ma_lpf_node_vtable =
69042 {
69043     ma_lpf_node_process_pcm_frames,
69044     NULL,   /* onGetRequiredInputFrameCount */
69045     1,      /* One input. */
69046     1,      /* One output. */
69047     0       /* Default flags. */
69048 };
69049
69050 MA_API ma_result ma_lpf_node_init(ma_node_graph* pNodeGraph, const ma_lpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf_node* pNode)
69051 {
69052     ma_result result;
69053     ma_node_config baseNodeConfig;
69054
69055     if (pNode == NULL) {
69056         return MA_INVALID_ARGS;
69057     }
69058
69059     MA_ZERO_OBJECT(pNode);
69060
69061     if (pConfig == NULL) {
69062         return MA_INVALID_ARGS;
69063     }
69064
69065     if (pConfig->lpf.format != ma_format_f32) {
69066         return MA_INVALID_ARGS; /* The format must be f32. */
69067     }
69068
69069     result = ma_lpf_init(&pConfig->lpf, pAllocationCallbacks, &pNode->lpf);
69070     if (result != MA_SUCCESS) {
69071         return result;
69072     }
69073
69074     baseNodeConfig = ma_node_config_init();
69075     baseNodeConfig.vtable          = &g_ma_lpf_node_vtable;
69076     baseNodeConfig.pInputChannels  = &pConfig->lpf.channels;
69077     baseNodeConfig.pOutputChannels = &pConfig->lpf.channels;
69078
69079     result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode);
69080     if (result != MA_SUCCESS) {
69081         return result;
69082     }
69083
69084     return result;
69085 }
69086
69087 MA_API ma_result ma_lpf_node_reinit(const ma_lpf_config* pConfig, ma_lpf_node* pNode)
69088 {
69089     ma_lpf_node* pLPFNode = (ma_lpf_node*)pNode;
69090
69091     if (pNode == NULL) {
69092         return MA_INVALID_ARGS;
69093     }
69094
69095     return ma_lpf_reinit(pConfig, &pLPFNode->lpf);
69096 }
69097
69098 MA_API void ma_lpf_node_uninit(ma_lpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks)
69099 {
69100     ma_lpf_node* pLPFNode = (ma_lpf_node*)pNode;
69101
69102     if (pNode == NULL) {
69103         return;
69104     }
69105
69106     ma_node_uninit(pNode, pAllocationCallbacks);
69107     ma_lpf_uninit(&pLPFNode->lpf, pAllocationCallbacks);
69108 }
69109
69110
69111
69112 /*
69113 High Pass Filter Node
69114 */
69115 MA_API ma_hpf_node_config ma_hpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
69116 {
69117     ma_hpf_node_config config;
69118
69119     config.nodeConfig = ma_node_config_init();
69120     config.hpf = ma_hpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order);
69121
69122     return config;
69123 }
69124
69125 static void ma_hpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
69126 {
69127     ma_hpf_node* pHPFNode = (ma_hpf_node*)pNode;
69128
69129     MA_ASSERT(pNode != NULL);
69130     (void)pFrameCountIn;
69131
69132     ma_hpf_process_pcm_frames(&pHPFNode->hpf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut);
69133 }
69134
69135 static ma_node_vtable g_ma_hpf_node_vtable =
69136 {
69137     ma_hpf_node_process_pcm_frames,
69138     NULL,   /* onGetRequiredInputFrameCount */
69139     1,      /* One input. */
69140     1,      /* One output. */
69141     0       /* Default flags. */
69142 };
69143
69144 MA_API ma_result ma_hpf_node_init(ma_node_graph* pNodeGraph, const ma_hpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf_node* pNode)
69145 {
69146     ma_result result;
69147     ma_node_config baseNodeConfig;
69148
69149     if (pNode == NULL) {
69150         return MA_INVALID_ARGS;
69151     }
69152
69153     MA_ZERO_OBJECT(pNode);
69154
69155     if (pConfig == NULL) {
69156         return MA_INVALID_ARGS;
69157     }
69158
69159     if (pConfig->hpf.format != ma_format_f32) {
69160         return MA_INVALID_ARGS; /* The format must be f32. */
69161     }
69162
69163     result = ma_hpf_init(&pConfig->hpf, pAllocationCallbacks, &pNode->hpf);
69164     if (result != MA_SUCCESS) {
69165         return result;
69166     }
69167
69168     baseNodeConfig = ma_node_config_init();
69169     baseNodeConfig.vtable          = &g_ma_hpf_node_vtable;
69170     baseNodeConfig.pInputChannels  = &pConfig->hpf.channels;
69171     baseNodeConfig.pOutputChannels = &pConfig->hpf.channels;
69172
69173     result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode);
69174     if (result != MA_SUCCESS) {
69175         return result;
69176     }
69177
69178     return result;
69179 }
69180
69181 MA_API ma_result ma_hpf_node_reinit(const ma_hpf_config* pConfig, ma_hpf_node* pNode)
69182 {
69183     ma_hpf_node* pHPFNode = (ma_hpf_node*)pNode;
69184
69185     if (pNode == NULL) {
69186         return MA_INVALID_ARGS;
69187     }
69188
69189     return ma_hpf_reinit(pConfig, &pHPFNode->hpf);
69190 }
69191
69192 MA_API void ma_hpf_node_uninit(ma_hpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks)
69193 {
69194     ma_hpf_node* pHPFNode = (ma_hpf_node*)pNode;
69195
69196     if (pNode == NULL) {
69197         return;
69198     }
69199
69200     ma_node_uninit(pNode, pAllocationCallbacks);
69201     ma_hpf_uninit(&pHPFNode->hpf, pAllocationCallbacks);
69202 }
69203
69204
69205
69206
69207 /*
69208 Band Pass Filter Node
69209 */
69210 MA_API ma_bpf_node_config ma_bpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
69211 {
69212     ma_bpf_node_config config;
69213
69214     config.nodeConfig = ma_node_config_init();
69215     config.bpf = ma_bpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order);
69216
69217     return config;
69218 }
69219
69220 static void ma_bpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
69221 {
69222     ma_bpf_node* pBPFNode = (ma_bpf_node*)pNode;
69223
69224     MA_ASSERT(pNode != NULL);
69225     (void)pFrameCountIn;
69226
69227     ma_bpf_process_pcm_frames(&pBPFNode->bpf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut);
69228 }
69229
69230 static ma_node_vtable g_ma_bpf_node_vtable =
69231 {
69232     ma_bpf_node_process_pcm_frames,
69233     NULL,   /* onGetRequiredInputFrameCount */
69234     1,      /* One input. */
69235     1,      /* One output. */
69236     0       /* Default flags. */
69237 };
69238
69239 MA_API ma_result ma_bpf_node_init(ma_node_graph* pNodeGraph, const ma_bpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf_node* pNode)
69240 {
69241     ma_result result;
69242     ma_node_config baseNodeConfig;
69243
69244     if (pNode == NULL) {
69245         return MA_INVALID_ARGS;
69246     }
69247
69248     MA_ZERO_OBJECT(pNode);
69249
69250     if (pConfig == NULL) {
69251         return MA_INVALID_ARGS;
69252     }
69253
69254     if (pConfig->bpf.format != ma_format_f32) {
69255         return MA_INVALID_ARGS; /* The format must be f32. */
69256     }
69257
69258     result = ma_bpf_init(&pConfig->bpf, pAllocationCallbacks, &pNode->bpf);
69259     if (result != MA_SUCCESS) {
69260         return result;
69261     }
69262
69263     baseNodeConfig = ma_node_config_init();
69264     baseNodeConfig.vtable          = &g_ma_bpf_node_vtable;
69265     baseNodeConfig.pInputChannels  = &pConfig->bpf.channels;
69266     baseNodeConfig.pOutputChannels = &pConfig->bpf.channels;
69267
69268     result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode);
69269     if (result != MA_SUCCESS) {
69270         return result;
69271     }
69272
69273     return result;
69274 }
69275
69276 MA_API ma_result ma_bpf_node_reinit(const ma_bpf_config* pConfig, ma_bpf_node* pNode)
69277 {
69278     ma_bpf_node* pBPFNode = (ma_bpf_node*)pNode;
69279
69280     if (pNode == NULL) {
69281         return MA_INVALID_ARGS;
69282     }
69283
69284     return ma_bpf_reinit(pConfig, &pBPFNode->bpf);
69285 }
69286
69287 MA_API void ma_bpf_node_uninit(ma_bpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks)
69288 {
69289     ma_bpf_node* pBPFNode = (ma_bpf_node*)pNode;
69290
69291     if (pNode == NULL) {
69292         return;
69293     }
69294
69295     ma_node_uninit(pNode, pAllocationCallbacks);
69296     ma_bpf_uninit(&pBPFNode->bpf, pAllocationCallbacks);
69297 }
69298
69299
69300
69301 /*
69302 Notching Filter Node
69303 */
69304 MA_API ma_notch_node_config ma_notch_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency)
69305 {
69306     ma_notch_node_config config;
69307
69308     config.nodeConfig = ma_node_config_init();
69309     config.notch = ma_notch2_config_init(ma_format_f32, channels, sampleRate, q, frequency);
69310
69311     return config;
69312 }
69313
69314 static void ma_notch_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
69315 {
69316     ma_notch_node* pBPFNode = (ma_notch_node*)pNode;
69317
69318     MA_ASSERT(pNode != NULL);
69319     (void)pFrameCountIn;
69320
69321     ma_notch2_process_pcm_frames(&pBPFNode->notch, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut);
69322 }
69323
69324 static ma_node_vtable g_ma_notch_node_vtable =
69325 {
69326     ma_notch_node_process_pcm_frames,
69327     NULL,   /* onGetRequiredInputFrameCount */
69328     1,      /* One input. */
69329     1,      /* One output. */
69330     0       /* Default flags. */
69331 };
69332
69333 MA_API ma_result ma_notch_node_init(ma_node_graph* pNodeGraph, const ma_notch_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch_node* pNode)
69334 {
69335     ma_result result;
69336     ma_node_config baseNodeConfig;
69337
69338     if (pNode == NULL) {
69339         return MA_INVALID_ARGS;
69340     }
69341
69342     MA_ZERO_OBJECT(pNode);
69343
69344     if (pConfig == NULL) {
69345         return MA_INVALID_ARGS;
69346     }
69347
69348     if (pConfig->notch.format != ma_format_f32) {
69349         return MA_INVALID_ARGS; /* The format must be f32. */
69350     }
69351
69352     result = ma_notch2_init(&pConfig->notch, pAllocationCallbacks, &pNode->notch);
69353     if (result != MA_SUCCESS) {
69354         return result;
69355     }
69356
69357     baseNodeConfig = ma_node_config_init();
69358     baseNodeConfig.vtable          = &g_ma_notch_node_vtable;
69359     baseNodeConfig.pInputChannels  = &pConfig->notch.channels;
69360     baseNodeConfig.pOutputChannels = &pConfig->notch.channels;
69361
69362     result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode);
69363     if (result != MA_SUCCESS) {
69364         return result;
69365     }
69366
69367     return result;
69368 }
69369
69370 MA_API ma_result ma_notch_node_reinit(const ma_notch_config* pConfig, ma_notch_node* pNode)
69371 {
69372     ma_notch_node* pNotchNode = (ma_notch_node*)pNode;
69373
69374     if (pNode == NULL) {
69375         return MA_INVALID_ARGS;
69376     }
69377
69378     return ma_notch2_reinit(pConfig, &pNotchNode->notch);
69379 }
69380
69381 MA_API void ma_notch_node_uninit(ma_notch_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks)
69382 {
69383     ma_notch_node* pNotchNode = (ma_notch_node*)pNode;
69384
69385     if (pNode == NULL) {
69386         return;
69387     }
69388
69389     ma_node_uninit(pNode, pAllocationCallbacks);
69390     ma_notch2_uninit(&pNotchNode->notch, pAllocationCallbacks);
69391 }
69392
69393
69394
69395 /*
69396 Peaking Filter Node
69397 */
69398 MA_API ma_peak_node_config ma_peak_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency)
69399 {
69400     ma_peak_node_config config;
69401
69402     config.nodeConfig = ma_node_config_init();
69403     config.peak = ma_peak2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency);
69404
69405     return config;
69406 }
69407
69408 static void ma_peak_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
69409 {
69410     ma_peak_node* pBPFNode = (ma_peak_node*)pNode;
69411
69412     MA_ASSERT(pNode != NULL);
69413     (void)pFrameCountIn;
69414
69415     ma_peak2_process_pcm_frames(&pBPFNode->peak, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut);
69416 }
69417
69418 static ma_node_vtable g_ma_peak_node_vtable =
69419 {
69420     ma_peak_node_process_pcm_frames,
69421     NULL,   /* onGetRequiredInputFrameCount */
69422     1,      /* One input. */
69423     1,      /* One output. */
69424     0       /* Default flags. */
69425 };
69426
69427 MA_API ma_result ma_peak_node_init(ma_node_graph* pNodeGraph, const ma_peak_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak_node* pNode)
69428 {
69429     ma_result result;
69430     ma_node_config baseNodeConfig;
69431
69432     if (pNode == NULL) {
69433         return MA_INVALID_ARGS;
69434     }
69435
69436     MA_ZERO_OBJECT(pNode);
69437
69438     if (pConfig == NULL) {
69439         return MA_INVALID_ARGS;
69440     }
69441
69442     if (pConfig->peak.format != ma_format_f32) {
69443         return MA_INVALID_ARGS; /* The format must be f32. */
69444     }
69445
69446     result = ma_peak2_init(&pConfig->peak, pAllocationCallbacks, &pNode->peak);
69447     if (result != MA_SUCCESS) {
69448         ma_node_uninit(pNode, pAllocationCallbacks);
69449         return result;
69450     }
69451
69452     baseNodeConfig = ma_node_config_init();
69453     baseNodeConfig.vtable          = &g_ma_peak_node_vtable;
69454     baseNodeConfig.pInputChannels  = &pConfig->peak.channels;
69455     baseNodeConfig.pOutputChannels = &pConfig->peak.channels;
69456
69457     result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode);
69458     if (result != MA_SUCCESS) {
69459         return result;
69460     }
69461
69462     return result;
69463 }
69464
69465 MA_API ma_result ma_peak_node_reinit(const ma_peak_config* pConfig, ma_peak_node* pNode)
69466 {
69467     ma_peak_node* pPeakNode = (ma_peak_node*)pNode;
69468
69469     if (pNode == NULL) {
69470         return MA_INVALID_ARGS;
69471     }
69472
69473     return ma_peak2_reinit(pConfig, &pPeakNode->peak);
69474 }
69475
69476 MA_API void ma_peak_node_uninit(ma_peak_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks)
69477 {
69478     ma_peak_node* pPeakNode = (ma_peak_node*)pNode;
69479
69480     if (pNode == NULL) {
69481         return;
69482     }
69483
69484     ma_node_uninit(pNode, pAllocationCallbacks);
69485     ma_peak2_uninit(&pPeakNode->peak, pAllocationCallbacks);
69486 }
69487
69488
69489
69490 /*
69491 Low Shelf Filter Node
69492 */
69493 MA_API ma_loshelf_node_config ma_loshelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency)
69494 {
69495     ma_loshelf_node_config config;
69496
69497     config.nodeConfig = ma_node_config_init();
69498     config.loshelf = ma_loshelf2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency);
69499
69500     return config;
69501 }
69502
69503 static void ma_loshelf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
69504 {
69505     ma_loshelf_node* pBPFNode = (ma_loshelf_node*)pNode;
69506
69507     MA_ASSERT(pNode != NULL);
69508     (void)pFrameCountIn;
69509
69510     ma_loshelf2_process_pcm_frames(&pBPFNode->loshelf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut);
69511 }
69512
69513 static ma_node_vtable g_ma_loshelf_node_vtable =
69514 {
69515     ma_loshelf_node_process_pcm_frames,
69516     NULL,   /* onGetRequiredInputFrameCount */
69517     1,      /* One input. */
69518     1,      /* One output. */
69519     0       /* Default flags. */
69520 };
69521
69522 MA_API ma_result ma_loshelf_node_init(ma_node_graph* pNodeGraph, const ma_loshelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf_node* pNode)
69523 {
69524     ma_result result;
69525     ma_node_config baseNodeConfig;
69526
69527     if (pNode == NULL) {
69528         return MA_INVALID_ARGS;
69529     }
69530
69531     MA_ZERO_OBJECT(pNode);
69532
69533     if (pConfig == NULL) {
69534         return MA_INVALID_ARGS;
69535     }
69536
69537     if (pConfig->loshelf.format != ma_format_f32) {
69538         return MA_INVALID_ARGS; /* The format must be f32. */
69539     }
69540
69541     result = ma_loshelf2_init(&pConfig->loshelf, pAllocationCallbacks, &pNode->loshelf);
69542     if (result != MA_SUCCESS) {
69543         return result;
69544     }
69545
69546     baseNodeConfig = ma_node_config_init();
69547     baseNodeConfig.vtable          = &g_ma_loshelf_node_vtable;
69548     baseNodeConfig.pInputChannels  = &pConfig->loshelf.channels;
69549     baseNodeConfig.pOutputChannels = &pConfig->loshelf.channels;
69550
69551     result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode);
69552     if (result != MA_SUCCESS) {
69553         return result;
69554     }
69555
69556     return result;
69557 }
69558
69559 MA_API ma_result ma_loshelf_node_reinit(const ma_loshelf_config* pConfig, ma_loshelf_node* pNode)
69560 {
69561     ma_loshelf_node* pLoshelfNode = (ma_loshelf_node*)pNode;
69562
69563     if (pNode == NULL) {
69564         return MA_INVALID_ARGS;
69565     }
69566
69567     return ma_loshelf2_reinit(pConfig, &pLoshelfNode->loshelf);
69568 }
69569
69570 MA_API void ma_loshelf_node_uninit(ma_loshelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks)
69571 {
69572     ma_loshelf_node* pLoshelfNode = (ma_loshelf_node*)pNode;
69573
69574     if (pNode == NULL) {
69575         return;
69576     }
69577
69578     ma_node_uninit(pNode, pAllocationCallbacks);
69579     ma_loshelf2_uninit(&pLoshelfNode->loshelf, pAllocationCallbacks);
69580 }
69581
69582
69583
69584 /*
69585 High Shelf Filter Node
69586 */
69587 MA_API ma_hishelf_node_config ma_hishelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency)
69588 {
69589     ma_hishelf_node_config config;
69590
69591     config.nodeConfig = ma_node_config_init();
69592     config.hishelf = ma_hishelf2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency);
69593
69594     return config;
69595 }
69596
69597 static void ma_hishelf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
69598 {
69599     ma_hishelf_node* pBPFNode = (ma_hishelf_node*)pNode;
69600
69601     MA_ASSERT(pNode != NULL);
69602     (void)pFrameCountIn;
69603
69604     ma_hishelf2_process_pcm_frames(&pBPFNode->hishelf, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut);
69605 }
69606
69607 static ma_node_vtable g_ma_hishelf_node_vtable =
69608 {
69609     ma_hishelf_node_process_pcm_frames,
69610     NULL,   /* onGetRequiredInputFrameCount */
69611     1,      /* One input. */
69612     1,      /* One output. */
69613     0       /* Default flags. */
69614 };
69615
69616 MA_API ma_result ma_hishelf_node_init(ma_node_graph* pNodeGraph, const ma_hishelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf_node* pNode)
69617 {
69618     ma_result result;
69619     ma_node_config baseNodeConfig;
69620
69621     if (pNode == NULL) {
69622         return MA_INVALID_ARGS;
69623     }
69624
69625     MA_ZERO_OBJECT(pNode);
69626
69627     if (pConfig == NULL) {
69628         return MA_INVALID_ARGS;
69629     }
69630
69631     if (pConfig->hishelf.format != ma_format_f32) {
69632         return MA_INVALID_ARGS; /* The format must be f32. */
69633     }
69634
69635     result = ma_hishelf2_init(&pConfig->hishelf, pAllocationCallbacks, &pNode->hishelf);
69636     if (result != MA_SUCCESS) {
69637         return result;
69638     }
69639
69640     baseNodeConfig = ma_node_config_init();
69641     baseNodeConfig.vtable          = &g_ma_hishelf_node_vtable;
69642     baseNodeConfig.pInputChannels  = &pConfig->hishelf.channels;
69643     baseNodeConfig.pOutputChannels = &pConfig->hishelf.channels;
69644
69645     result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode);
69646     if (result != MA_SUCCESS) {
69647         return result;
69648     }
69649
69650     return result;
69651 }
69652
69653 MA_API ma_result ma_hishelf_node_reinit(const ma_hishelf_config* pConfig, ma_hishelf_node* pNode)
69654 {
69655     ma_hishelf_node* pHishelfNode = (ma_hishelf_node*)pNode;
69656
69657     if (pNode == NULL) {
69658         return MA_INVALID_ARGS;
69659     }
69660
69661     return ma_hishelf2_reinit(pConfig, &pHishelfNode->hishelf);
69662 }
69663
69664 MA_API void ma_hishelf_node_uninit(ma_hishelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks)
69665 {
69666     ma_hishelf_node* pHishelfNode = (ma_hishelf_node*)pNode;
69667
69668     if (pNode == NULL) {
69669         return;
69670     }
69671
69672     ma_node_uninit(pNode, pAllocationCallbacks);
69673     ma_hishelf2_uninit(&pHishelfNode->hishelf, pAllocationCallbacks);
69674 }
69675
69676
69677
69678
69679 MA_API ma_delay_node_config ma_delay_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay)
69680 {
69681     ma_delay_node_config config;
69682
69683     config.nodeConfig = ma_node_config_init();
69684     config.delay = ma_delay_config_init(channels, sampleRate, delayInFrames, decay);
69685
69686     return config;
69687 }
69688
69689
69690 static void ma_delay_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
69691 {
69692     ma_delay_node* pDelayNode = (ma_delay_node*)pNode;
69693
69694     (void)pFrameCountIn;
69695
69696     ma_delay_process_pcm_frames(&pDelayNode->delay, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut);
69697 }
69698
69699 static ma_node_vtable g_ma_delay_node_vtable =
69700 {
69701     ma_delay_node_process_pcm_frames,
69702     NULL,
69703     1,  /* 1 input channels. */
69704     1,  /* 1 output channel. */
69705     MA_NODE_FLAG_CONTINUOUS_PROCESSING  /* Delay requires continuous processing to ensure the tail get's processed. */
69706 };
69707
69708 MA_API ma_result ma_delay_node_init(ma_node_graph* pNodeGraph, const ma_delay_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay_node* pDelayNode)
69709 {
69710     ma_result result;
69711     ma_node_config baseConfig;
69712
69713     if (pDelayNode == NULL) {
69714         return MA_INVALID_ARGS;
69715     }
69716
69717     MA_ZERO_OBJECT(pDelayNode);
69718
69719     result = ma_delay_init(&pConfig->delay, pAllocationCallbacks, &pDelayNode->delay);
69720     if (result != MA_SUCCESS) {
69721         return result;
69722     }
69723
69724     baseConfig = pConfig->nodeConfig;
69725     baseConfig.vtable          = &g_ma_delay_node_vtable;
69726     baseConfig.pInputChannels  = &pConfig->delay.channels;
69727     baseConfig.pOutputChannels = &pConfig->delay.channels;
69728
69729     result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pDelayNode->baseNode);
69730     if (result != MA_SUCCESS) {
69731         ma_delay_uninit(&pDelayNode->delay, pAllocationCallbacks);
69732         return result;
69733     }
69734
69735     return result;
69736 }
69737
69738 MA_API void ma_delay_node_uninit(ma_delay_node* pDelayNode, const ma_allocation_callbacks* pAllocationCallbacks)
69739 {
69740     if (pDelayNode == NULL) {
69741         return;
69742     }
69743
69744     /* The base node is always uninitialized first. */
69745     ma_node_uninit(pDelayNode, pAllocationCallbacks);
69746     ma_delay_uninit(&pDelayNode->delay, pAllocationCallbacks);
69747 }
69748
69749 MA_API void ma_delay_node_set_wet(ma_delay_node* pDelayNode, float value)
69750 {
69751     if (pDelayNode == NULL) {
69752         return;
69753     }
69754
69755     ma_delay_set_wet(&pDelayNode->delay, value);
69756 }
69757
69758 MA_API float ma_delay_node_get_wet(const ma_delay_node* pDelayNode)
69759 {
69760     if (pDelayNode == NULL) {
69761         return 0;
69762     }
69763
69764     return ma_delay_get_wet(&pDelayNode->delay);
69765 }
69766
69767 MA_API void ma_delay_node_set_dry(ma_delay_node* pDelayNode, float value)
69768 {
69769     if (pDelayNode == NULL) {
69770         return;
69771     }
69772
69773     ma_delay_set_dry(&pDelayNode->delay, value);
69774 }
69775
69776 MA_API float ma_delay_node_get_dry(const ma_delay_node* pDelayNode)
69777 {
69778     if (pDelayNode == NULL) {
69779         return 0;
69780     }
69781
69782     return ma_delay_get_dry(&pDelayNode->delay);
69783 }
69784
69785 MA_API void ma_delay_node_set_decay(ma_delay_node* pDelayNode, float value)
69786 {
69787     if (pDelayNode == NULL) {
69788         return;
69789     }
69790
69791     ma_delay_set_decay(&pDelayNode->delay, value);
69792 }
69793
69794 MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode)
69795 {
69796     if (pDelayNode == NULL) {
69797         return 0;
69798     }
69799
69800     return ma_delay_get_decay(&pDelayNode->delay);
69801 }
69802 #endif  /* MA_NO_NODE_GRAPH */
69803
69804
69805 #if !defined(MA_NO_ENGINE) && !defined(MA_NO_NODE_GRAPH)
69806 /**************************************************************************************************************************************************************
69807
69808 Engine
69809
69810 **************************************************************************************************************************************************************/
69811 #define MA_SEEK_TARGET_NONE         (~(ma_uint64)0)
69812
69813 MA_API ma_engine_node_config ma_engine_node_config_init(ma_engine* pEngine, ma_engine_node_type type, ma_uint32 flags)
69814 {
69815     ma_engine_node_config config;
69816
69817     MA_ZERO_OBJECT(&config);
69818     config.pEngine                  = pEngine;
69819     config.type                     = type;
69820     config.isPitchDisabled          = (flags & MA_SOUND_FLAG_NO_PITCH) != 0;
69821     config.isSpatializationDisabled = (flags & MA_SOUND_FLAG_NO_SPATIALIZATION) != 0;
69822
69823     return config;
69824 }
69825
69826
69827 static void ma_engine_node_update_pitch_if_required(ma_engine_node* pEngineNode)
69828 {
69829     ma_bool32 isUpdateRequired = MA_FALSE;
69830     float newPitch;
69831
69832     MA_ASSERT(pEngineNode != NULL);
69833
69834     newPitch = c89atomic_load_explicit_f32(&pEngineNode->pitch, c89atomic_memory_order_acquire);
69835
69836     if (pEngineNode->oldPitch != newPitch) {
69837         pEngineNode->oldPitch  = newPitch;
69838         isUpdateRequired = MA_TRUE;
69839     }
69840
69841     if (pEngineNode->oldDopplerPitch != pEngineNode->spatializer.dopplerPitch) {
69842         pEngineNode->oldDopplerPitch  = pEngineNode->spatializer.dopplerPitch;
69843         isUpdateRequired = MA_TRUE;
69844     }
69845
69846     if (isUpdateRequired) {
69847         float basePitch = (float)pEngineNode->sampleRate / ma_engine_get_sample_rate(pEngineNode->pEngine);
69848         ma_linear_resampler_set_rate_ratio(&pEngineNode->resampler, basePitch * pEngineNode->oldPitch * pEngineNode->oldDopplerPitch);
69849     }
69850 }
69851
69852 static ma_bool32 ma_engine_node_is_pitching_enabled(const ma_engine_node* pEngineNode)
69853 {
69854     MA_ASSERT(pEngineNode != NULL);
69855
69856     /* Don't try to be clever by skiping resampling in the pitch=1 case or else you'll glitch when moving away from 1. */
69857     return !c89atomic_load_explicit_32(&pEngineNode->isPitchDisabled, c89atomic_memory_order_acquire);
69858 }
69859
69860 static ma_bool32 ma_engine_node_is_spatialization_enabled(const ma_engine_node* pEngineNode)
69861 {
69862     MA_ASSERT(pEngineNode != NULL);
69863
69864     return !c89atomic_load_explicit_32(&pEngineNode->isSpatializationDisabled, c89atomic_memory_order_acquire);
69865 }
69866
69867 static ma_uint64 ma_engine_node_get_required_input_frame_count(const ma_engine_node* pEngineNode, ma_uint64 outputFrameCount)
69868 {
69869     ma_uint64 inputFrameCount = 0;
69870
69871     if (ma_engine_node_is_pitching_enabled(pEngineNode)) {
69872         ma_result result = ma_linear_resampler_get_required_input_frame_count(&pEngineNode->resampler, outputFrameCount, &inputFrameCount);
69873         if (result != MA_SUCCESS) {
69874             inputFrameCount = 0;
69875         }
69876     } else {
69877         inputFrameCount = outputFrameCount;    /* No resampling, so 1:1. */
69878     }
69879
69880     return inputFrameCount;
69881 }
69882
69883 static void ma_engine_node_process_pcm_frames__general(ma_engine_node* pEngineNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
69884 {
69885     ma_uint32 frameCountIn;
69886     ma_uint32 frameCountOut;
69887     ma_uint32 totalFramesProcessedIn;
69888     ma_uint32 totalFramesProcessedOut;
69889     ma_uint32 channelsIn;
69890     ma_uint32 channelsOut;
69891     ma_bool32 isPitchingEnabled;
69892     ma_bool32 isFadingEnabled;
69893     ma_bool32 isSpatializationEnabled;
69894     ma_bool32 isPanningEnabled;
69895
69896     frameCountIn  = *pFrameCountIn;
69897     frameCountOut = *pFrameCountOut;
69898
69899     channelsIn  = ma_spatializer_get_input_channels(&pEngineNode->spatializer);
69900     channelsOut = ma_spatializer_get_output_channels(&pEngineNode->spatializer);
69901
69902     totalFramesProcessedIn  = 0;
69903     totalFramesProcessedOut = 0;
69904
69905     isPitchingEnabled       = ma_engine_node_is_pitching_enabled(pEngineNode);
69906     isFadingEnabled         = pEngineNode->fader.volumeBeg != 1 || pEngineNode->fader.volumeEnd != 1;
69907     isSpatializationEnabled = ma_engine_node_is_spatialization_enabled(pEngineNode);
69908     isPanningEnabled        = pEngineNode->panner.pan != 0 && channelsOut != 1;
69909
69910     /* Keep going while we've still got data available for processing. */
69911     while (totalFramesProcessedOut < frameCountOut) {
69912         /*
69913         We need to process in a specific order. We always do resampling first because it's likely
69914         we're going to be increasing the channel count after spatialization. Also, I want to do
69915         fading based on the output sample rate.
69916
69917         We'll first read into a buffer from the resampler. Then we'll do all processing that
69918         operates on the on the input channel count. We'll then get the spatializer to output to
69919         the output buffer and then do all effects from that point directly in the output buffer
69920         in-place.
69921
69922         Note that we're always running the resampler. If we try to be clever and skip resampling
69923         when the pitch is 1, we'll get a glitch when we move away from 1, back to 1, and then
69924         away from 1 again. We'll want to implement any pitch=1 optimizations in the resampler
69925         itself.
69926
69927         There's a small optimization here that we'll utilize since it might be a fairly common
69928         case. When the input and output channel counts are the same, we'll read straight into the
69929         output buffer from the resampler and do everything in-place.
69930         */
69931         const float* pRunningFramesIn;
69932         float* pRunningFramesOut;
69933         float* pWorkingBuffer;   /* This is the buffer that we'll be processing frames in. This is in input channels. */
69934         float temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE / sizeof(float)];
69935         ma_uint32 tempCapInFrames = ma_countof(temp) / channelsIn;
69936         ma_uint32 framesAvailableIn;
69937         ma_uint32 framesAvailableOut;
69938         ma_uint32 framesJustProcessedIn;
69939         ma_uint32 framesJustProcessedOut;
69940         ma_bool32 isWorkingBufferValid = MA_FALSE;
69941
69942         framesAvailableIn  = frameCountIn  - totalFramesProcessedIn;
69943         framesAvailableOut = frameCountOut - totalFramesProcessedOut;
69944
69945         pRunningFramesIn  = ma_offset_pcm_frames_const_ptr_f32(ppFramesIn[0], totalFramesProcessedIn, channelsIn);
69946         pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesProcessedOut, channelsOut);
69947
69948         if (channelsIn == channelsOut) {
69949             /* Fast path. Channel counts are the same. No need for an intermediary input buffer. */
69950             pWorkingBuffer = pRunningFramesOut;
69951         } else {
69952             /* Slow path. Channel counts are different. Need to use an intermediary input buffer. */
69953             pWorkingBuffer = temp;
69954             if (framesAvailableOut > tempCapInFrames) {
69955                 framesAvailableOut = tempCapInFrames;
69956             }
69957         }
69958
69959         /* First is resampler. */
69960         if (isPitchingEnabled) {
69961             ma_uint64 resampleFrameCountIn  = framesAvailableIn;
69962             ma_uint64 resampleFrameCountOut = framesAvailableOut;
69963
69964             ma_linear_resampler_process_pcm_frames(&pEngineNode->resampler, pRunningFramesIn, &resampleFrameCountIn, pWorkingBuffer, &resampleFrameCountOut);
69965             isWorkingBufferValid = MA_TRUE;
69966
69967             framesJustProcessedIn  = (ma_uint32)resampleFrameCountIn;
69968             framesJustProcessedOut = (ma_uint32)resampleFrameCountOut;
69969         } else {
69970             framesJustProcessedIn  = framesAvailableIn;
69971             framesJustProcessedOut = framesAvailableOut;
69972         }
69973
69974         /* Fading. */
69975         if (isFadingEnabled) {
69976             if (isWorkingBufferValid) {
69977                 ma_fader_process_pcm_frames(&pEngineNode->fader, pWorkingBuffer, pWorkingBuffer, framesJustProcessedOut);   /* In-place processing. */
69978             } else {
69979                 ma_fader_process_pcm_frames(&pEngineNode->fader, pWorkingBuffer, pRunningFramesIn, framesJustProcessedOut);
69980                 isWorkingBufferValid = MA_TRUE;
69981             }
69982         }
69983
69984         /*
69985         If at this point we still haven't actually done anything with the working buffer we need
69986         to just read straight from the input buffer.
69987         */
69988         if (isWorkingBufferValid == MA_FALSE) {
69989             pWorkingBuffer = (float*)pRunningFramesIn;  /* Naughty const cast, but it's safe at this point because we won't ever be writing to it from this point out. */
69990         }
69991
69992         /* Spatialization. */
69993         if (isSpatializationEnabled) {
69994             ma_uint32 iListener;
69995
69996             /*
69997             When determining the listener to use, we first check to see if the sound is pinned to a
69998             specific listener. If so, we use that. Otherwise we just use the closest listener.
69999             */
70000             if (pEngineNode->pinnedListenerIndex != MA_LISTENER_INDEX_CLOSEST && pEngineNode->pinnedListenerIndex < ma_engine_get_listener_count(pEngineNode->pEngine)) {
70001                 iListener = pEngineNode->pinnedListenerIndex;
70002             } else {
70003                 iListener = ma_engine_find_closest_listener(pEngineNode->pEngine, pEngineNode->spatializer.position.x, pEngineNode->spatializer.position.y, pEngineNode->spatializer.position.z);
70004             }
70005
70006             ma_spatializer_process_pcm_frames(&pEngineNode->spatializer, &pEngineNode->pEngine->listeners[iListener], pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut);
70007         } else {
70008             /* No spatialization, but we still need to do channel conversion. */
70009             if (channelsIn == channelsOut) {
70010                 /* No channel conversion required. Just copy straight to the output buffer. */
70011                 ma_copy_pcm_frames(pRunningFramesOut, pWorkingBuffer, framesJustProcessedOut, ma_format_f32, channelsOut);
70012             } else {
70013                 /* Channel conversion required. TODO: Add support for channel maps here. */
70014                 ma_channel_map_apply_f32(pRunningFramesOut, NULL, channelsOut, pWorkingBuffer, NULL, channelsIn, framesJustProcessedOut, ma_channel_mix_mode_simple, pEngineNode->pEngine->monoExpansionMode);
70015             }
70016         }
70017
70018         /* At this point we can guarantee that the output buffer contains valid data. We can process everything in place now. */
70019
70020         /* Panning. */
70021         if (isPanningEnabled) {
70022             ma_panner_process_pcm_frames(&pEngineNode->panner, pRunningFramesOut, pRunningFramesOut, framesJustProcessedOut);   /* In-place processing. */
70023         }
70024
70025         /* We're done for this chunk. */
70026         totalFramesProcessedIn  += framesJustProcessedIn;
70027         totalFramesProcessedOut += framesJustProcessedOut;
70028
70029         /* If we didn't process any output frames this iteration it means we've either run out of input data, or run out of room in the output buffer. */
70030         if (framesJustProcessedOut == 0) {
70031             break;
70032         }
70033     }
70034
70035     /* At this point we're done processing. */
70036     *pFrameCountIn  = totalFramesProcessedIn;
70037     *pFrameCountOut = totalFramesProcessedOut;
70038 }
70039
70040 static void ma_engine_node_process_pcm_frames__sound(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
70041 {
70042     /* For sounds, we need to first read from the data source. Then we need to apply the engine effects (pan, pitch, fades, etc.). */
70043     ma_result result = MA_SUCCESS;
70044     ma_sound* pSound = (ma_sound*)pNode;
70045     ma_uint32 frameCount = *pFrameCountOut;
70046     ma_uint32 totalFramesRead = 0;
70047     ma_format dataSourceFormat;
70048     ma_uint32 dataSourceChannels;
70049     ma_uint8 temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
70050     ma_uint32 tempCapInFrames;
70051
70052     /* This is a data source node which means no input buses. */
70053     (void)ppFramesIn;
70054     (void)pFrameCountIn;
70055
70056     /* If we're marked at the end we need to stop the sound and do nothing. */
70057     if (ma_sound_at_end(pSound)) {
70058         ma_sound_stop(pSound);
70059         *pFrameCountOut = 0;
70060         return;
70061     }
70062
70063     /* If we're seeking, do so now before reading. */
70064     if (pSound->seekTarget != MA_SEEK_TARGET_NONE) {
70065         ma_data_source_seek_to_pcm_frame(pSound->pDataSource, pSound->seekTarget);
70066
70067         /* Any time-dependant effects need to have their times updated. */
70068         ma_node_set_time(pSound, pSound->seekTarget);
70069
70070         pSound->seekTarget  = MA_SEEK_TARGET_NONE;
70071     }
70072
70073     /*
70074     We want to update the pitch once. For sounds, this can be either at the start or at the end. If
70075     we don't force this to only ever be updating once, we could end up in a situation where
70076     retrieving the required input frame count ends up being different to what we actually retrieve.
70077     What could happen is that the required input frame count is calculated, the pitch is update,
70078     and then this processing function is called resulting in a different number of input frames
70079     being processed. Do not call this in ma_engine_node_process_pcm_frames__general() or else
70080     you'll hit the aforementioned bug.
70081     */
70082     ma_engine_node_update_pitch_if_required(&pSound->engineNode);
70083
70084     /*
70085     For the convenience of the caller, we're doing to allow data sources to use non-floating-point formats and channel counts that differ
70086     from the main engine.
70087     */
70088     result = ma_data_source_get_data_format(pSound->pDataSource, &dataSourceFormat, &dataSourceChannels, NULL, NULL, 0);
70089     if (result == MA_SUCCESS) {
70090         tempCapInFrames = sizeof(temp) / ma_get_bytes_per_frame(dataSourceFormat, dataSourceChannels);
70091
70092         /* Keep reading until we've read as much as was requested or we reach the end of the data source. */
70093         while (totalFramesRead < frameCount) {
70094             ma_uint32 framesRemaining = frameCount - totalFramesRead;
70095             ma_uint32 framesToRead;
70096             ma_uint64 framesJustRead;
70097             ma_uint32 frameCountIn;
70098             ma_uint32 frameCountOut;
70099             const float* pRunningFramesIn;
70100             float* pRunningFramesOut;
70101
70102             /*
70103             The first thing we need to do is read into the temporary buffer. We can calculate exactly
70104             how many input frames we'll need after resampling.
70105             */
70106             framesToRead = (ma_uint32)ma_engine_node_get_required_input_frame_count(&pSound->engineNode, framesRemaining);
70107             if (framesToRead > tempCapInFrames) {
70108                 framesToRead = tempCapInFrames;
70109             }
70110
70111             result = ma_data_source_read_pcm_frames(pSound->pDataSource, temp, framesToRead, &framesJustRead);
70112
70113             /* If we reached the end of the sound we'll want to mark it as at the end and stop it. This should never be returned for looping sounds. */
70114             if (result == MA_AT_END) {
70115                 c89atomic_exchange_32(&pSound->atEnd, MA_TRUE); /* This will be set to false in ma_sound_start(). */
70116             }
70117
70118             pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesRead, ma_engine_get_channels(ma_sound_get_engine(pSound)));
70119
70120             frameCountIn = (ma_uint32)framesJustRead;
70121             frameCountOut = framesRemaining;
70122
70123             /* Convert if necessary. */
70124             if (dataSourceFormat == ma_format_f32) {
70125                 /* Fast path. No data conversion necessary. */
70126                 pRunningFramesIn = (float*)temp;
70127                 ma_engine_node_process_pcm_frames__general(&pSound->engineNode, &pRunningFramesIn, &frameCountIn, &pRunningFramesOut, &frameCountOut);
70128             } else {
70129                 /* Slow path. Need to do sample format conversion to f32. If we give the f32 buffer the same count as the first temp buffer, we're guaranteed it'll be large enough. */
70130                 float tempf32[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; /* Do not do `MA_DATA_CONVERTER_STACK_BUFFER_SIZE/sizeof(float)` here like we've done in other places. */
70131                 ma_convert_pcm_frames_format(tempf32, ma_format_f32, temp, dataSourceFormat, framesJustRead, dataSourceChannels, ma_dither_mode_none);
70132
70133                 /* Now that we have our samples in f32 format we can process like normal. */
70134                 pRunningFramesIn = tempf32;
70135                 ma_engine_node_process_pcm_frames__general(&pSound->engineNode, &pRunningFramesIn, &frameCountIn, &pRunningFramesOut, &frameCountOut);
70136             }
70137
70138             /* We should have processed all of our input frames since we calculated the required number of input frames at the top. */
70139             MA_ASSERT(frameCountIn == framesJustRead);
70140             totalFramesRead += (ma_uint32)frameCountOut;   /* Safe cast. */
70141
70142             if (result != MA_SUCCESS || ma_sound_at_end(pSound)) {
70143                 break;  /* Might have reached the end. */
70144             }
70145         }
70146     }
70147
70148     *pFrameCountOut = totalFramesRead;
70149 }
70150
70151 static void ma_engine_node_process_pcm_frames__group(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut)
70152 {
70153     /*
70154     Make sure the pitch is updated before trying to read anything. It's important that this is done
70155     only once and not in ma_engine_node_process_pcm_frames__general(). The reason for this is that
70156     ma_engine_node_process_pcm_frames__general() will call ma_engine_node_get_required_input_frame_count(),
70157     and if another thread modifies the pitch just after that call it can result in a glitch due to
70158     the input rate changing.
70159     */
70160     ma_engine_node_update_pitch_if_required((ma_engine_node*)pNode);
70161
70162     /* For groups, the input data has already been read and we just need to apply the effect. */
70163     ma_engine_node_process_pcm_frames__general((ma_engine_node*)pNode, ppFramesIn, pFrameCountIn, ppFramesOut, pFrameCountOut);
70164 }
70165
70166 static ma_result ma_engine_node_get_required_input_frame_count__group(ma_node* pNode, ma_uint32 outputFrameCount, ma_uint32* pInputFrameCount)
70167 {
70168     ma_uint64 inputFrameCount;
70169
70170     MA_ASSERT(pInputFrameCount != NULL);
70171
70172     /* Our pitch will affect this calculation. We need to update it. */
70173     ma_engine_node_update_pitch_if_required((ma_engine_node*)pNode);
70174
70175     inputFrameCount = ma_engine_node_get_required_input_frame_count((ma_engine_node*)pNode, outputFrameCount);
70176     if (inputFrameCount > 0xFFFFFFFF) {
70177         inputFrameCount = 0xFFFFFFFF;    /* Will never happen because miniaudio will only ever process in relatively small chunks. */
70178     }
70179
70180     *pInputFrameCount = (ma_uint32)inputFrameCount;
70181
70182     return MA_SUCCESS;
70183 }
70184
70185
70186 static ma_node_vtable g_ma_engine_node_vtable__sound =
70187 {
70188     ma_engine_node_process_pcm_frames__sound,
70189     NULL,   /* onGetRequiredInputFrameCount */
70190     0,      /* Sounds are data source nodes which means they have zero inputs (their input is drawn from the data source itself). */
70191     1,      /* Sounds have one output bus. */
70192     0       /* Default flags. */
70193 };
70194
70195 static ma_node_vtable g_ma_engine_node_vtable__group =
70196 {
70197     ma_engine_node_process_pcm_frames__group,
70198     ma_engine_node_get_required_input_frame_count__group,
70199     1,      /* Groups have one input bus. */
70200     1,      /* Groups have one output bus. */
70201     MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES /* The engine node does resampling so should let miniaudio know about it. */
70202 };
70203
70204
70205
70206 static ma_node_config ma_engine_node_base_node_config_init(const ma_engine_node_config* pConfig)
70207 {
70208     ma_node_config baseNodeConfig;
70209
70210     if (pConfig->type == ma_engine_node_type_sound) {
70211         /* Sound. */
70212         baseNodeConfig = ma_node_config_init();
70213         baseNodeConfig.vtable       = &g_ma_engine_node_vtable__sound;
70214         baseNodeConfig.initialState = ma_node_state_stopped;    /* Sounds are stopped by default. */
70215     } else {
70216         /* Group. */
70217         baseNodeConfig = ma_node_config_init();
70218         baseNodeConfig.vtable       = &g_ma_engine_node_vtable__group;
70219         baseNodeConfig.initialState = ma_node_state_started;    /* Groups are started by default. */
70220     }
70221
70222     return baseNodeConfig;
70223 }
70224
70225 static ma_spatializer_config ma_engine_node_spatializer_config_init(const ma_node_config* pBaseNodeConfig)
70226 {
70227     return ma_spatializer_config_init(pBaseNodeConfig->pInputChannels[0], pBaseNodeConfig->pOutputChannels[0]);
70228 }
70229
70230 typedef struct
70231 {
70232     size_t sizeInBytes;
70233     size_t baseNodeOffset;
70234     size_t resamplerOffset;
70235     size_t spatializerOffset;
70236 } ma_engine_node_heap_layout;
70237
70238 static ma_result ma_engine_node_get_heap_layout(const ma_engine_node_config* pConfig, ma_engine_node_heap_layout* pHeapLayout)
70239 {
70240     ma_result result;
70241     size_t tempHeapSize;
70242     ma_node_config baseNodeConfig;
70243     ma_linear_resampler_config resamplerConfig;
70244     ma_spatializer_config spatializerConfig;
70245     ma_uint32 channelsIn;
70246     ma_uint32 channelsOut;
70247
70248     MA_ASSERT(pHeapLayout);
70249
70250     MA_ZERO_OBJECT(pHeapLayout);
70251
70252     if (pConfig == NULL) {
70253         return MA_INVALID_ARGS;
70254     }
70255
70256     if (pConfig->pEngine == NULL) {
70257         return MA_INVALID_ARGS; /* An engine must be specified. */
70258     }
70259
70260     pHeapLayout->sizeInBytes = 0;
70261
70262     channelsIn  = (pConfig->channelsIn  != 0) ? pConfig->channelsIn  : ma_engine_get_channels(pConfig->pEngine);
70263     channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine);
70264
70265
70266     /* Base node. */
70267     baseNodeConfig = ma_engine_node_base_node_config_init(pConfig);
70268     baseNodeConfig.pInputChannels  = &channelsIn;
70269     baseNodeConfig.pOutputChannels = &channelsOut;
70270
70271     result = ma_node_get_heap_size(&baseNodeConfig, &tempHeapSize);
70272     if (result != MA_SUCCESS) {
70273         return result;  /* Failed to retrieve the size of the heap for the base node. */
70274     }
70275
70276     pHeapLayout->baseNodeOffset = pHeapLayout->sizeInBytes;
70277     pHeapLayout->sizeInBytes += ma_align_64(tempHeapSize);
70278
70279
70280     /* Resmapler. */
70281     resamplerConfig = ma_linear_resampler_config_init(ma_format_f32, channelsIn, 1, 1); /* Input and output sample rates don't affect the calculation of the heap size. */
70282     resamplerConfig.lpfOrder = 0;
70283     
70284     result = ma_linear_resampler_get_heap_size(&resamplerConfig, &tempHeapSize);
70285     if (result != MA_SUCCESS) {
70286         return result;  /* Failed to retrieve the size of the heap for the resampler. */
70287     }
70288
70289     pHeapLayout->resamplerOffset = pHeapLayout->sizeInBytes;
70290     pHeapLayout->sizeInBytes += ma_align_64(tempHeapSize);
70291
70292
70293     /* Spatializer. */
70294     spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig);
70295
70296     result = ma_spatializer_get_heap_size(&spatializerConfig, &tempHeapSize);
70297     if (result != MA_SUCCESS) {
70298         return result;  /* Failed to retrieve the size of the heap for the spatializer. */
70299     }
70300
70301     pHeapLayout->spatializerOffset = pHeapLayout->sizeInBytes;
70302     pHeapLayout->sizeInBytes += ma_align_64(tempHeapSize);
70303
70304
70305     return MA_SUCCESS;
70306 }
70307
70308 MA_API ma_result ma_engine_node_get_heap_size(const ma_engine_node_config* pConfig, size_t* pHeapSizeInBytes)
70309 {
70310     ma_result result;
70311     ma_engine_node_heap_layout heapLayout;
70312
70313     if (pHeapSizeInBytes == NULL) {
70314         return MA_INVALID_ARGS;
70315     }
70316
70317     *pHeapSizeInBytes = 0;
70318
70319     result = ma_engine_node_get_heap_layout(pConfig, &heapLayout);
70320     if (result != MA_SUCCESS) {
70321         return result;
70322     }
70323
70324     *pHeapSizeInBytes = heapLayout.sizeInBytes;
70325
70326     return MA_SUCCESS;
70327 }
70328
70329 MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* pConfig, void* pHeap, ma_engine_node* pEngineNode)
70330 {
70331     ma_result result;
70332     ma_engine_node_heap_layout heapLayout;
70333     ma_node_config baseNodeConfig;
70334     ma_linear_resampler_config resamplerConfig;
70335     ma_fader_config faderConfig;
70336     ma_spatializer_config spatializerConfig;
70337     ma_panner_config pannerConfig;
70338     ma_uint32 channelsIn;
70339     ma_uint32 channelsOut;
70340
70341     if (pEngineNode == NULL) {
70342         return MA_INVALID_ARGS;
70343     }
70344
70345     MA_ZERO_OBJECT(pEngineNode);
70346
70347     result = ma_engine_node_get_heap_layout(pConfig, &heapLayout);
70348     if (result != MA_SUCCESS) {
70349         return result;
70350     }
70351
70352     if (pConfig->pinnedListenerIndex != MA_LISTENER_INDEX_CLOSEST && pConfig->pinnedListenerIndex >= ma_engine_get_listener_count(pConfig->pEngine)) {
70353         return MA_INVALID_ARGS; /* Invalid listener. */
70354     }
70355
70356     pEngineNode->_pHeap = pHeap;
70357     MA_ZERO_MEMORY(pHeap, heapLayout.sizeInBytes);
70358
70359     pEngineNode->pEngine                  = pConfig->pEngine;
70360     pEngineNode->sampleRate               = (pConfig->sampleRate > 0) ? pConfig->sampleRate : ma_engine_get_sample_rate(pEngineNode->pEngine);
70361     pEngineNode->pitch                    = 1;
70362     pEngineNode->oldPitch                 = 1;
70363     pEngineNode->oldDopplerPitch          = 1;
70364     pEngineNode->isPitchDisabled          = pConfig->isPitchDisabled;
70365     pEngineNode->isSpatializationDisabled = pConfig->isSpatializationDisabled;
70366     pEngineNode->pinnedListenerIndex      = pConfig->pinnedListenerIndex;
70367
70368
70369     channelsIn  = (pConfig->channelsIn  != 0) ? pConfig->channelsIn  : ma_engine_get_channels(pConfig->pEngine);
70370     channelsOut = (pConfig->channelsOut != 0) ? pConfig->channelsOut : ma_engine_get_channels(pConfig->pEngine);
70371
70372
70373     /* Base node. */
70374     baseNodeConfig = ma_engine_node_base_node_config_init(pConfig);
70375     baseNodeConfig.pInputChannels  = &channelsIn;
70376     baseNodeConfig.pOutputChannels = &channelsOut;
70377
70378     result = ma_node_init_preallocated(&pConfig->pEngine->nodeGraph, &baseNodeConfig, ma_offset_ptr(pHeap, heapLayout.baseNodeOffset), &pEngineNode->baseNode);
70379     if (result != MA_SUCCESS) {
70380         goto error0;
70381     }
70382
70383
70384     /*
70385     We can now initialize the effects we need in order to implement the engine node. There's a
70386     defined order of operations here, mainly centered around when we convert our channels from the
70387     data source's native channel count to the engine's channel count. As a rule, we want to do as
70388     much computation as possible before spatialization because there's a chance that will increase
70389     the channel count, thereby increasing the amount of work needing to be done to process.
70390     */
70391
70392     /* We'll always do resampling first. */
70393     resamplerConfig = ma_linear_resampler_config_init(ma_format_f32, baseNodeConfig.pInputChannels[0], pEngineNode->sampleRate, ma_engine_get_sample_rate(pEngineNode->pEngine));
70394     resamplerConfig.lpfOrder = 0;    /* <-- Need to disable low-pass filtering for pitch shifting for now because there's cases where the biquads are becoming unstable. Need to figure out a better fix for this. */
70395
70396     result = ma_linear_resampler_init_preallocated(&resamplerConfig, ma_offset_ptr(pHeap, heapLayout.resamplerOffset), &pEngineNode->resampler);
70397     if (result != MA_SUCCESS) {
70398         goto error1;
70399     }
70400
70401
70402     /* After resampling will come the fader. */
70403     faderConfig = ma_fader_config_init(ma_format_f32, baseNodeConfig.pInputChannels[0], ma_engine_get_sample_rate(pEngineNode->pEngine));
70404
70405     result = ma_fader_init(&faderConfig, &pEngineNode->fader);
70406     if (result != MA_SUCCESS) {
70407         goto error2;
70408     }
70409
70410
70411     /*
70412     Spatialization comes next. We spatialize based ont he node's output channel count. It's up the caller to
70413     ensure channels counts link up correctly in the node graph.
70414     */
70415     spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig);
70416     spatializerConfig.gainSmoothTimeInFrames = pEngineNode->pEngine->gainSmoothTimeInFrames;
70417
70418     result = ma_spatializer_init_preallocated(&spatializerConfig, ma_offset_ptr(pHeap, heapLayout.spatializerOffset), &pEngineNode->spatializer);
70419     if (result != MA_SUCCESS) {
70420         goto error2;
70421     }
70422
70423
70424     /*
70425     After spatialization comes panning. We need to do this after spatialization because otherwise we wouldn't
70426     be able to pan mono sounds.
70427     */
70428     pannerConfig = ma_panner_config_init(ma_format_f32, baseNodeConfig.pOutputChannels[0]);
70429
70430     result = ma_panner_init(&pannerConfig, &pEngineNode->panner);
70431     if (result != MA_SUCCESS) {
70432         goto error3;
70433     }
70434
70435     return MA_SUCCESS;
70436
70437     /* No need for allocation callbacks here because we use a preallocated heap. */
70438 error3: ma_spatializer_uninit(&pEngineNode->spatializer, NULL);
70439 error2: ma_linear_resampler_uninit(&pEngineNode->resampler, NULL);
70440 error1: ma_node_uninit(&pEngineNode->baseNode, NULL);
70441 error0: return result;
70442 }
70443
70444 MA_API ma_result ma_engine_node_init(const ma_engine_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_engine_node* pEngineNode)
70445 {
70446     ma_result result;
70447     size_t heapSizeInBytes;
70448     void* pHeap;
70449
70450     result = ma_engine_node_get_heap_size(pConfig, &heapSizeInBytes);
70451     if (result != MA_SUCCESS) {
70452         return result;
70453     }
70454
70455     if (heapSizeInBytes > 0) {
70456         pHeap = ma_malloc(heapSizeInBytes, pAllocationCallbacks);
70457         if (pHeap == NULL) {
70458             return MA_OUT_OF_MEMORY;
70459         }
70460     } else {
70461         pHeap = NULL;
70462     }
70463
70464     result = ma_engine_node_init_preallocated(pConfig, pHeap, pEngineNode);
70465     if (result != MA_SUCCESS) {
70466         ma_free(pHeap, pAllocationCallbacks);
70467         return result;
70468     }
70469
70470     pEngineNode->_ownsHeap = MA_TRUE;
70471     return MA_SUCCESS;
70472 }
70473
70474 MA_API void ma_engine_node_uninit(ma_engine_node* pEngineNode, const ma_allocation_callbacks* pAllocationCallbacks)
70475 {
70476     /*
70477     The base node always needs to be uninitialized first to ensure it's detached from the graph completely before we
70478     destroy anything that might be in the middle of being used by the processing function.
70479     */
70480     ma_node_uninit(&pEngineNode->baseNode, pAllocationCallbacks);
70481
70482     /* Now that the node has been uninitialized we can safely uninitialize the rest. */
70483     ma_spatializer_uninit(&pEngineNode->spatializer, pAllocationCallbacks);
70484     ma_linear_resampler_uninit(&pEngineNode->resampler, pAllocationCallbacks);
70485
70486     /* Free the heap last. */
70487     if (pEngineNode->_ownsHeap) {
70488         ma_free(pEngineNode->_pHeap, pAllocationCallbacks);
70489     }
70490 }
70491
70492
70493 MA_API ma_sound_config ma_sound_config_init(void)
70494 {
70495     ma_sound_config config;
70496
70497     MA_ZERO_OBJECT(&config);
70498     config.rangeEndInPCMFrames     = ~((ma_uint64)0);
70499     config.loopPointEndInPCMFrames = ~((ma_uint64)0);
70500
70501     return config;
70502 }
70503
70504 MA_API ma_sound_group_config ma_sound_group_config_init(void)
70505 {
70506     ma_sound_group_config config;
70507
70508     MA_ZERO_OBJECT(&config);
70509
70510     return config;
70511 }
70512
70513
70514 MA_API ma_engine_config ma_engine_config_init(void)
70515 {
70516     ma_engine_config config;
70517
70518     MA_ZERO_OBJECT(&config);
70519     config.listenerCount     = 1;   /* Always want at least one listener. */
70520     config.monoExpansionMode = ma_mono_expansion_mode_default;
70521
70522     return config;
70523 }
70524
70525
70526 #if !defined(MA_NO_DEVICE_IO)
70527 static void ma_engine_data_callback_internal(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
70528 {
70529     ma_engine* pEngine = (ma_engine*)pDevice->pUserData;
70530
70531     (void)pFramesIn;
70532
70533     /*
70534     Experiment: Try processing a resource manager job if we're on the Emscripten build.
70535
70536     This serves two purposes:
70537
70538         1) It ensures jobs are actually processed at some point since we cannot guarantee that the
70539            caller is doing the right thing and calling ma_resource_manager_process_next_job(); and
70540
70541         2) It's an attempt at working around an issue where processing jobs on the Emscripten main
70542            loop doesn't work as well as it should. When trying to load sounds without the `DECODE`
70543            flag or with the `ASYNC` flag, the sound data is just not able to be loaded in time
70544            before the callback is processed. I think it's got something to do with the single-
70545            threaded nature of Web, but I'm not entirely sure.
70546     */
70547     #if !defined(MA_NO_RESOURCE_MANAGER) && defined(MA_EMSCRIPTEN)
70548     {
70549         if (pEngine->pResourceManager != NULL) {
70550             if ((pEngine->pResourceManager->config.flags & MA_RESOURCE_MANAGER_FLAG_NO_THREADING) != 0) {
70551                 ma_resource_manager_process_next_job(pEngine->pResourceManager);
70552             }
70553         }
70554     }
70555     #endif
70556
70557     ma_engine_read_pcm_frames(pEngine, pFramesOut, frameCount, NULL);
70558 }
70559 #endif
70560
70561 MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine)
70562 {
70563     ma_result result;
70564     ma_node_graph_config nodeGraphConfig;
70565     ma_engine_config engineConfig;
70566     ma_spatializer_listener_config listenerConfig;
70567     ma_uint32 iListener;
70568
70569     if (pEngine == NULL) {
70570         return MA_INVALID_ARGS;
70571     }
70572
70573     MA_ZERO_OBJECT(pEngine);
70574
70575     /* The config is allowed to be NULL in which case we use defaults for everything. */
70576     if (pConfig != NULL) {
70577         engineConfig = *pConfig;
70578     } else {
70579         engineConfig = ma_engine_config_init();
70580     }
70581
70582     pEngine->monoExpansionMode = engineConfig.monoExpansionMode;
70583     ma_allocation_callbacks_init_copy(&pEngine->allocationCallbacks, &engineConfig.allocationCallbacks);
70584
70585     #if !defined(MA_NO_RESOURCE_MANAGER)
70586     {
70587         pEngine->pResourceManager = engineConfig.pResourceManager;
70588     }
70589     #endif
70590
70591     #if !defined(MA_NO_DEVICE_IO)
70592     {
70593         pEngine->pDevice = engineConfig.pDevice;
70594     
70595         /* If we don't have a device, we need one. */
70596         if (pEngine->pDevice == NULL && engineConfig.noDevice == MA_FALSE) {
70597             ma_device_config deviceConfig;
70598
70599             pEngine->pDevice = (ma_device*)ma_malloc(sizeof(*pEngine->pDevice), &pEngine->allocationCallbacks);
70600             if (pEngine->pDevice == NULL) {
70601                 return MA_OUT_OF_MEMORY;
70602             }
70603
70604             deviceConfig = ma_device_config_init(ma_device_type_playback);
70605             deviceConfig.playback.pDeviceID        = engineConfig.pPlaybackDeviceID;
70606             deviceConfig.playback.format           = ma_format_f32;
70607             deviceConfig.playback.channels         = engineConfig.channels;
70608             deviceConfig.sampleRate                = engineConfig.sampleRate;
70609             deviceConfig.dataCallback              = ma_engine_data_callback_internal;
70610             deviceConfig.pUserData                 = pEngine;
70611             deviceConfig.periodSizeInFrames        = engineConfig.periodSizeInFrames;
70612             deviceConfig.periodSizeInMilliseconds  = engineConfig.periodSizeInMilliseconds;
70613             deviceConfig.noPreSilencedOutputBuffer = MA_TRUE;    /* We'll always be outputting to every frame in the callback so there's no need for a pre-silenced buffer. */
70614             deviceConfig.noClip                    = MA_TRUE;    /* The engine will do clipping itself. */
70615
70616             if (engineConfig.pContext == NULL) {
70617                 ma_context_config contextConfig = ma_context_config_init();
70618                 contextConfig.allocationCallbacks = pEngine->allocationCallbacks;
70619                 contextConfig.pLog = engineConfig.pLog;
70620
70621                 /* If the engine config does not specify a log, use the resource manager's if we have one. */
70622                 #ifndef MA_NO_RESOURCE_MANAGER
70623                 {
70624                     if (contextConfig.pLog == NULL && engineConfig.pResourceManager != NULL) {
70625                         contextConfig.pLog = ma_resource_manager_get_log(engineConfig.pResourceManager);
70626                     }
70627                 }
70628                 #endif
70629
70630                 result = ma_device_init_ex(NULL, 0, &contextConfig, &deviceConfig, pEngine->pDevice);
70631             } else {
70632                 result = ma_device_init(engineConfig.pContext, &deviceConfig, pEngine->pDevice);
70633             }
70634
70635             if (result != MA_SUCCESS) {
70636                 ma_free(pEngine->pDevice, &pEngine->allocationCallbacks);
70637                 pEngine->pDevice = NULL;
70638                 return result;
70639             }
70640
70641             pEngine->ownsDevice = MA_TRUE;
70642         }
70643
70644         /* Update the channel count and sample rate of the engine config so we can reference it below. */
70645         if (pEngine->pDevice != NULL) {
70646             engineConfig.channels   = pEngine->pDevice->playback.channels;
70647             engineConfig.sampleRate = pEngine->pDevice->sampleRate;
70648         }
70649     }
70650     #endif
70651
70652     if (engineConfig.channels == 0 || engineConfig.sampleRate == 0) {
70653         return MA_INVALID_ARGS;
70654     }
70655
70656     pEngine->sampleRate = engineConfig.sampleRate;
70657
70658     /* The engine always uses either the log that was passed into the config, or the context's log is available. */
70659     if (engineConfig.pLog != NULL) {
70660         pEngine->pLog = engineConfig.pLog;
70661     } else {
70662         #if !defined(MA_NO_DEVICE_IO)
70663         {
70664             pEngine->pLog = ma_device_get_log(pEngine->pDevice);
70665         }
70666         #else
70667         {
70668             pEngine->pLog = NULL;
70669         }
70670         #endif
70671     }
70672
70673
70674     /* The engine is a node graph. This needs to be initialized after we have the device so we can can determine the channel count. */
70675     nodeGraphConfig = ma_node_graph_config_init(engineConfig.channels);
70676
70677     result = ma_node_graph_init(&nodeGraphConfig, &pEngine->allocationCallbacks, &pEngine->nodeGraph);
70678     if (result != MA_SUCCESS) {
70679         goto on_error_1;
70680     }
70681
70682
70683     /* We need at least one listener. */
70684     if (engineConfig.listenerCount == 0) {
70685         engineConfig.listenerCount = 1;
70686     }
70687
70688     if (engineConfig.listenerCount > MA_ENGINE_MAX_LISTENERS) {
70689         result = MA_INVALID_ARGS;   /* Too many listeners. */
70690         goto on_error_1;
70691     }
70692
70693     for (iListener = 0; iListener < engineConfig.listenerCount; iListener += 1) {
70694         listenerConfig = ma_spatializer_listener_config_init(ma_node_graph_get_channels(&pEngine->nodeGraph));
70695
70696         /*
70697         If we're using a device, use the device's channel map for the listener. Otherwise just use
70698         miniaudio's default channel map.
70699         */
70700         #if !defined(MA_NO_DEVICE_IO)
70701         {
70702             if (pEngine->pDevice != NULL) {
70703                 /*
70704                 Temporarily disabled. There is a subtle bug here where front-left and front-right
70705                 will be used by the device's channel map, but this is not what we want to use for
70706                 spatialization. Instead we want to use side-left and side-right. I need to figure
70707                 out a better solution for this. For now, disabling the user of device channel maps.
70708                 */
70709                 /*listenerConfig.pChannelMapOut = pEngine->pDevice->playback.channelMap;*/
70710             }
70711         }
70712         #endif
70713
70714         result = ma_spatializer_listener_init(&listenerConfig, &pEngine->allocationCallbacks, &pEngine->listeners[iListener]);  /* TODO: Change this to a pre-allocated heap. */
70715         if (result != MA_SUCCESS) {
70716             goto on_error_2;
70717         }
70718
70719         pEngine->listenerCount += 1;
70720     }
70721
70722
70723     /* Gain smoothing for spatialized sounds. */
70724     pEngine->gainSmoothTimeInFrames = engineConfig.gainSmoothTimeInFrames;
70725     if (pEngine->gainSmoothTimeInFrames == 0) {
70726         ma_uint32 gainSmoothTimeInMilliseconds = engineConfig.gainSmoothTimeInMilliseconds;
70727         if (gainSmoothTimeInMilliseconds == 0) {
70728             gainSmoothTimeInMilliseconds = 8;
70729         }
70730
70731         pEngine->gainSmoothTimeInFrames = (gainSmoothTimeInMilliseconds * ma_engine_get_sample_rate(pEngine)) / 1000;  /* 8ms by default. */
70732     }
70733
70734
70735     /* We need a resource manager. */
70736     #ifndef MA_NO_RESOURCE_MANAGER
70737     {
70738         if (pEngine->pResourceManager == NULL) {
70739             ma_resource_manager_config resourceManagerConfig;
70740
70741             pEngine->pResourceManager = (ma_resource_manager*)ma_malloc(sizeof(*pEngine->pResourceManager), &pEngine->allocationCallbacks);
70742             if (pEngine->pResourceManager == NULL) {
70743                 result = MA_OUT_OF_MEMORY;
70744                 goto on_error_2;
70745             }
70746
70747             resourceManagerConfig = ma_resource_manager_config_init();
70748             resourceManagerConfig.pLog              = pEngine->pLog;    /* Always use the engine's log for internally-managed resource managers. */
70749             resourceManagerConfig.decodedFormat     = ma_format_f32;
70750             resourceManagerConfig.decodedChannels   = 0;  /* Leave the decoded channel count as 0 so we can get good spatialization. */
70751             resourceManagerConfig.decodedSampleRate = ma_engine_get_sample_rate(pEngine);
70752             ma_allocation_callbacks_init_copy(&resourceManagerConfig.allocationCallbacks, &pEngine->allocationCallbacks);
70753             resourceManagerConfig.pVFS              = engineConfig.pResourceManagerVFS;
70754
70755             /* The Emscripten build cannot use threads. */
70756             #if defined(MA_EMSCRIPTEN)
70757             {
70758                 resourceManagerConfig.jobThreadCount = 0;
70759                 resourceManagerConfig.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING;
70760             }
70761             #endif
70762
70763             result = ma_resource_manager_init(&resourceManagerConfig, pEngine->pResourceManager);
70764             if (result != MA_SUCCESS) {
70765                 goto on_error_3;
70766             }
70767
70768             pEngine->ownsResourceManager = MA_TRUE;
70769         }
70770     }
70771     #endif
70772
70773     /* Setup some stuff for inlined sounds. That is sounds played with ma_engine_play_sound(). */
70774     pEngine->inlinedSoundLock  = 0;
70775     pEngine->pInlinedSoundHead = NULL;
70776
70777     /* Start the engine if required. This should always be the last step. */
70778     #if !defined(MA_NO_DEVICE_IO)
70779     {
70780         if (engineConfig.noAutoStart == MA_FALSE && pEngine->pDevice != NULL) {
70781             result = ma_engine_start(pEngine);
70782             if (result != MA_SUCCESS) {
70783                 goto on_error_4;    /* Failed to start the engine. */
70784             }
70785         }
70786     }
70787     #endif
70788
70789     return MA_SUCCESS;
70790
70791 #if !defined(MA_NO_DEVICE_IO)
70792 on_error_4:
70793 #endif
70794 #if !defined(MA_NO_RESOURCE_MANAGER)
70795 on_error_3:
70796     if (pEngine->ownsResourceManager) {
70797         ma_free(pEngine->pResourceManager, &pEngine->allocationCallbacks);
70798     }
70799 #endif  /* MA_NO_RESOURCE_MANAGER */
70800 on_error_2:
70801     for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) {
70802         ma_spatializer_listener_uninit(&pEngine->listeners[iListener], &pEngine->allocationCallbacks);
70803     }
70804
70805     ma_node_graph_uninit(&pEngine->nodeGraph, &pEngine->allocationCallbacks);
70806 on_error_1:
70807     #if !defined(MA_NO_DEVICE_IO)
70808     {
70809         if (pEngine->ownsDevice) {
70810             ma_device_uninit(pEngine->pDevice);
70811             ma_free(pEngine->pDevice, &pEngine->allocationCallbacks);
70812         }
70813     }
70814     #endif
70815
70816     return result;
70817 }
70818
70819 MA_API void ma_engine_uninit(ma_engine* pEngine)
70820 {
70821     ma_uint32 iListener;
70822
70823     if (pEngine == NULL) {
70824         return;
70825     }
70826
70827     /* The device must be uninitialized before the node graph to ensure the audio thread doesn't try accessing it. */
70828     #if !defined(MA_NO_DEVICE_IO)
70829     {
70830         if (pEngine->ownsDevice) {
70831             ma_device_uninit(pEngine->pDevice);
70832             ma_free(pEngine->pDevice, &pEngine->allocationCallbacks);
70833         } else {
70834             if (pEngine->pDevice != NULL) {
70835                 ma_device_stop(pEngine->pDevice);
70836             }
70837         }
70838     }
70839     #endif
70840
70841     /*
70842     All inlined sounds need to be deleted. I'm going to use a lock here just to future proof in case
70843     I want to do some kind of garbage collection later on.
70844     */
70845     ma_spinlock_lock(&pEngine->inlinedSoundLock);
70846     {
70847         for (;;) {
70848             ma_sound_inlined* pSoundToDelete = pEngine->pInlinedSoundHead;
70849             if (pSoundToDelete == NULL) {
70850                 break;  /* Done. */
70851             }
70852
70853             pEngine->pInlinedSoundHead = pSoundToDelete->pNext;
70854
70855             ma_sound_uninit(&pSoundToDelete->sound);
70856             ma_free(pSoundToDelete, &pEngine->allocationCallbacks);
70857         }
70858     }
70859     ma_spinlock_unlock(&pEngine->inlinedSoundLock);
70860
70861     for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) {
70862         ma_spatializer_listener_uninit(&pEngine->listeners[iListener], &pEngine->allocationCallbacks);
70863     }
70864
70865     /* Make sure the node graph is uninitialized after the audio thread has been shutdown to prevent accessing of the node graph after being uninitialized. */
70866     ma_node_graph_uninit(&pEngine->nodeGraph, &pEngine->allocationCallbacks);
70867
70868     /* Uninitialize the resource manager last to ensure we don't have a thread still trying to access it. */
70869 #ifndef MA_NO_RESOURCE_MANAGER
70870     if (pEngine->ownsResourceManager) {
70871         ma_resource_manager_uninit(pEngine->pResourceManager);
70872         ma_free(pEngine->pResourceManager, &pEngine->allocationCallbacks);
70873     }
70874 #endif
70875 }
70876
70877 MA_API ma_result ma_engine_read_pcm_frames(ma_engine* pEngine, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
70878 {
70879     return ma_node_graph_read_pcm_frames(&pEngine->nodeGraph, pFramesOut, frameCount, pFramesRead);
70880 }
70881
70882 MA_API ma_node_graph* ma_engine_get_node_graph(ma_engine* pEngine)
70883 {
70884     if (pEngine == NULL) {
70885         return NULL;
70886     }
70887
70888     return &pEngine->nodeGraph;
70889 }
70890
70891 #if !defined(MA_NO_RESOURCE_MANAGER)
70892 MA_API ma_resource_manager* ma_engine_get_resource_manager(ma_engine* pEngine)
70893 {
70894     if (pEngine == NULL) {
70895         return NULL;
70896     }
70897
70898     #if !defined(MA_NO_RESOURCE_MANAGER)
70899     {
70900         return pEngine->pResourceManager;
70901     }
70902     #else
70903     {
70904         return NULL;
70905     }
70906     #endif
70907 }
70908 #endif
70909
70910 MA_API ma_device* ma_engine_get_device(ma_engine* pEngine)
70911 {
70912     if (pEngine == NULL) {
70913         return NULL;
70914     }
70915
70916     #if !defined(MA_NO_DEVICE_IO)
70917     {
70918         return pEngine->pDevice;
70919     }
70920     #else
70921     {
70922         return NULL;
70923     }
70924     #endif
70925 }
70926
70927 MA_API ma_log* ma_engine_get_log(ma_engine* pEngine)
70928 {
70929     if (pEngine == NULL) {
70930         return NULL;
70931     }
70932
70933     if (pEngine->pLog != NULL) {
70934         return pEngine->pLog;
70935     } else {
70936         #if !defined(MA_NO_DEVICE_IO)
70937         {
70938             return ma_device_get_log(ma_engine_get_device(pEngine));
70939         }
70940         #else
70941         {
70942             return NULL;
70943         }
70944         #endif
70945     }
70946 }
70947
70948 MA_API ma_node* ma_engine_get_endpoint(ma_engine* pEngine)
70949 {
70950     return ma_node_graph_get_endpoint(&pEngine->nodeGraph);
70951 }
70952
70953 MA_API ma_uint64 ma_engine_get_time(const ma_engine* pEngine)
70954 {
70955     return ma_node_graph_get_time(&pEngine->nodeGraph);
70956 }
70957
70958 MA_API ma_uint64 ma_engine_set_time(ma_engine* pEngine, ma_uint64 globalTime)
70959 {
70960     return ma_node_graph_set_time(&pEngine->nodeGraph, globalTime);
70961 }
70962
70963 MA_API ma_uint32 ma_engine_get_channels(const ma_engine* pEngine)
70964 {
70965     return ma_node_graph_get_channels(&pEngine->nodeGraph);
70966 }
70967
70968 MA_API ma_uint32 ma_engine_get_sample_rate(const ma_engine* pEngine)
70969 {
70970     if (pEngine == NULL) {
70971         return 0;
70972     }
70973
70974     return pEngine->sampleRate;
70975 }
70976
70977
70978 MA_API ma_result ma_engine_start(ma_engine* pEngine)
70979 {
70980     ma_result result;
70981
70982     if (pEngine == NULL) {
70983         return MA_INVALID_ARGS;
70984     }
70985
70986     #if !defined(MA_NO_DEVICE_IO)
70987     {
70988         if (pEngine->pDevice != NULL) {
70989             result = ma_device_start(pEngine->pDevice);
70990         } else {
70991             result = MA_INVALID_OPERATION;  /* The engine is running without a device which means there's no real notion of "starting" the engine. */
70992         }
70993     }
70994     #else
70995     {
70996         result = MA_INVALID_OPERATION;  /* Device IO is disabled, so there's no real notion of "starting" the engine. */
70997     }
70998     #endif
70999
71000     if (result != MA_SUCCESS) {
71001         return result;
71002     }
71003
71004     return MA_SUCCESS;
71005 }
71006
71007 MA_API ma_result ma_engine_stop(ma_engine* pEngine)
71008 {
71009     ma_result result;
71010
71011     if (pEngine == NULL) {
71012         return MA_INVALID_ARGS;
71013     }
71014
71015     #if !defined(MA_NO_DEVICE_IO)
71016     {
71017         if (pEngine->pDevice != NULL) {
71018             result = ma_device_stop(pEngine->pDevice);
71019         } else {
71020             result = MA_INVALID_OPERATION;  /* The engine is running without a device which means there's no real notion of "stopping" the engine. */
71021         }
71022     }
71023     #else
71024     {
71025         result = MA_INVALID_OPERATION;  /* Device IO is disabled, so there's no real notion of "stopping" the engine. */
71026     }
71027     #endif
71028
71029     if (result != MA_SUCCESS) {
71030         return result;
71031     }
71032
71033     return MA_SUCCESS;
71034 }
71035
71036 MA_API ma_result ma_engine_set_volume(ma_engine* pEngine, float volume)
71037 {
71038     if (pEngine == NULL) {
71039         return MA_INVALID_ARGS;
71040     }
71041
71042     return ma_node_set_output_bus_volume(ma_node_graph_get_endpoint(&pEngine->nodeGraph), 0, volume);
71043 }
71044
71045 MA_API ma_result ma_engine_set_gain_db(ma_engine* pEngine, float gainDB)
71046 {
71047     if (pEngine == NULL) {
71048         return MA_INVALID_ARGS;
71049     }
71050
71051     return ma_node_set_output_bus_volume(ma_node_graph_get_endpoint(&pEngine->nodeGraph), 0, ma_volume_db_to_linear(gainDB));
71052 }
71053
71054
71055 MA_API ma_uint32 ma_engine_get_listener_count(const ma_engine* pEngine)
71056 {
71057     if (pEngine == NULL) {
71058         return 0;
71059     }
71060
71061     return pEngine->listenerCount;
71062 }
71063
71064 MA_API ma_uint32 ma_engine_find_closest_listener(const ma_engine* pEngine, float absolutePosX, float absolutePosY, float absolutePosZ)
71065 {
71066     ma_uint32 iListener;
71067     ma_uint32 iListenerClosest;
71068     float closestLen2 = MA_FLT_MAX;
71069
71070     if (pEngine == NULL || pEngine->listenerCount == 1) {
71071         return 0;
71072     }
71073
71074     iListenerClosest = 0;
71075     for (iListener = 0; iListener < pEngine->listenerCount; iListener += 1) {
71076         if (ma_engine_listener_is_enabled(pEngine, iListener)) {
71077             float len2 = ma_vec3f_len2(ma_vec3f_sub(pEngine->listeners[iListener].position, ma_vec3f_init_3f(absolutePosX, absolutePosY, absolutePosZ)));
71078             if (closestLen2 > len2) {
71079                 closestLen2 = len2;
71080                 iListenerClosest = iListener;
71081             }
71082         }
71083     }
71084
71085     MA_ASSERT(iListenerClosest < 255);
71086     return iListenerClosest;
71087 }
71088
71089 MA_API void ma_engine_listener_set_position(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z)
71090 {
71091     if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) {
71092         return;
71093     }
71094
71095     ma_spatializer_listener_set_position(&pEngine->listeners[listenerIndex], x, y, z);
71096 }
71097
71098 MA_API ma_vec3f ma_engine_listener_get_position(const ma_engine* pEngine, ma_uint32 listenerIndex)
71099 {
71100     if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) {
71101         return ma_vec3f_init_3f(0, 0, 0);
71102     }
71103
71104     return ma_spatializer_listener_get_position(&pEngine->listeners[listenerIndex]);
71105 }
71106
71107 MA_API void ma_engine_listener_set_direction(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z)
71108 {
71109     if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) {
71110         return;
71111     }
71112
71113     ma_spatializer_listener_set_direction(&pEngine->listeners[listenerIndex], x, y, z);
71114 }
71115
71116 MA_API ma_vec3f ma_engine_listener_get_direction(const ma_engine* pEngine, ma_uint32 listenerIndex)
71117 {
71118     if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) {
71119         return ma_vec3f_init_3f(0, 0, -1);
71120     }
71121
71122     return ma_spatializer_listener_get_direction(&pEngine->listeners[listenerIndex]);
71123 }
71124
71125 MA_API void ma_engine_listener_set_velocity(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z)
71126 {
71127     if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) {
71128         return;
71129     }
71130
71131     ma_spatializer_listener_set_velocity(&pEngine->listeners[listenerIndex], x, y, z);
71132 }
71133
71134 MA_API ma_vec3f ma_engine_listener_get_velocity(const ma_engine* pEngine, ma_uint32 listenerIndex)
71135 {
71136     if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) {
71137         return ma_vec3f_init_3f(0, 0, 0);
71138     }
71139
71140     return ma_spatializer_listener_get_velocity(&pEngine->listeners[listenerIndex]);
71141 }
71142
71143 MA_API void ma_engine_listener_set_cone(ma_engine* pEngine, ma_uint32 listenerIndex, float innerAngleInRadians, float outerAngleInRadians, float outerGain)
71144 {
71145     if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) {
71146         return;
71147     }
71148
71149     ma_spatializer_listener_set_cone(&pEngine->listeners[listenerIndex], innerAngleInRadians, outerAngleInRadians, outerGain);
71150 }
71151
71152 MA_API void ma_engine_listener_get_cone(const ma_engine* pEngine, ma_uint32 listenerIndex, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain)
71153 {
71154     if (pInnerAngleInRadians != NULL) {
71155         *pInnerAngleInRadians = 0;
71156     }
71157
71158     if (pOuterAngleInRadians != NULL) {
71159         *pOuterAngleInRadians = 0;
71160     }
71161
71162     if (pOuterGain != NULL) {
71163         *pOuterGain = 0;
71164     }
71165
71166     ma_spatializer_listener_get_cone(&pEngine->listeners[listenerIndex], pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain);
71167 }
71168
71169 MA_API void ma_engine_listener_set_world_up(ma_engine* pEngine, ma_uint32 listenerIndex, float x, float y, float z)
71170 {
71171     if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) {
71172         return;
71173     }
71174
71175     ma_spatializer_listener_set_world_up(&pEngine->listeners[listenerIndex], x, y, z);
71176 }
71177
71178 MA_API ma_vec3f ma_engine_listener_get_world_up(const ma_engine* pEngine, ma_uint32 listenerIndex)
71179 {
71180     if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) {
71181         return ma_vec3f_init_3f(0, 1, 0);
71182     }
71183
71184     return ma_spatializer_listener_get_world_up(&pEngine->listeners[listenerIndex]);
71185 }
71186
71187 MA_API void ma_engine_listener_set_enabled(ma_engine* pEngine, ma_uint32 listenerIndex, ma_bool32 isEnabled)
71188 {
71189     if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) {
71190         return;
71191     }
71192
71193     ma_spatializer_listener_set_enabled(&pEngine->listeners[listenerIndex], isEnabled);
71194 }
71195
71196 MA_API ma_bool32 ma_engine_listener_is_enabled(const ma_engine* pEngine, ma_uint32 listenerIndex)
71197 {
71198     if (pEngine == NULL || listenerIndex >= pEngine->listenerCount) {
71199         return MA_FALSE;
71200     }
71201
71202     return ma_spatializer_listener_is_enabled(&pEngine->listeners[listenerIndex]);
71203 }
71204
71205
71206 #ifndef MA_NO_RESOURCE_MANAGER
71207 MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePath, ma_node* pNode, ma_uint32 nodeInputBusIndex)
71208 {
71209     ma_result result = MA_SUCCESS;
71210     ma_sound_inlined* pSound = NULL;
71211     ma_sound_inlined* pNextSound = NULL;
71212
71213     if (pEngine == NULL || pFilePath == NULL) {
71214         return MA_INVALID_ARGS;
71215     }
71216
71217     /* Attach to the endpoint node if nothing is specicied. */
71218     if (pNode == NULL) {
71219         pNode = ma_node_graph_get_endpoint(&pEngine->nodeGraph);
71220         nodeInputBusIndex = 0;
71221     }
71222
71223     /*
71224     We want to check if we can recycle an already-allocated inlined sound. Since this is just a
71225     helper I'm not *too* concerned about performance here and I'm happy to use a lock to keep
71226     the implementation simple. Maybe this can be optimized later if there's enough demand, but
71227     if this function is being used it probably means the caller doesn't really care too much.
71228
71229     What we do is check the atEnd flag. When this is true, we can recycle the sound. Otherwise
71230     we just keep iterating. If we reach the end without finding a sound to recycle we just
71231     allocate a new one. This doesn't scale well for a massive number of sounds being played
71232     simultaneously as we don't ever actually free the sound objects. Some kind of garbage
71233     collection routine might be valuable for this which I'll think about.
71234     */
71235     ma_spinlock_lock(&pEngine->inlinedSoundLock);
71236     {
71237         ma_uint32 soundFlags = 0;
71238
71239         for (pNextSound = pEngine->pInlinedSoundHead; pNextSound != NULL; pNextSound = pNextSound->pNext) {
71240             if (ma_sound_at_end(&pNextSound->sound)) {
71241                 /*
71242                 The sound is at the end which means it's available for recycling. All we need to do
71243                 is uninitialize it and reinitialize it. All we're doing is recycling memory.
71244                 */
71245                 pSound = pNextSound;
71246                 c89atomic_fetch_sub_32(&pEngine->inlinedSoundCount, 1);
71247                 break;
71248             }
71249         }
71250
71251         if (pSound != NULL) {
71252             /*
71253             We actually want to detach the sound from the list here. The reason is because we want the sound
71254             to be in a consistent state at the non-recycled case to simplify the logic below.
71255             */
71256             if (pEngine->pInlinedSoundHead == pSound) {
71257                 pEngine->pInlinedSoundHead =  pSound->pNext;
71258             }
71259
71260             if (pSound->pPrev != NULL) {
71261                 pSound->pPrev->pNext = pSound->pNext;
71262             }
71263             if (pSound->pNext != NULL) {
71264                 pSound->pNext->pPrev = pSound->pPrev;
71265             }
71266
71267             /* Now the previous sound needs to be uninitialized. */
71268             ma_sound_uninit(&pNextSound->sound);
71269         } else {
71270             /* No sound available for recycling. Allocate one now. */
71271             pSound = (ma_sound_inlined*)ma_malloc(sizeof(*pSound), &pEngine->allocationCallbacks);
71272         }
71273
71274         if (pSound != NULL) {   /* Safety check for the allocation above. */
71275             /*
71276             At this point we should have memory allocated for the inlined sound. We just need
71277             to initialize it like a normal sound now.
71278             */
71279             soundFlags |= MA_SOUND_FLAG_ASYNC;                 /* For inlined sounds we don't want to be sitting around waiting for stuff to load so force an async load. */
71280             soundFlags |= MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT; /* We want specific control over where the sound is attached in the graph. We'll attach it manually just before playing the sound. */
71281             soundFlags |= MA_SOUND_FLAG_NO_PITCH;              /* Pitching isn't usable with inlined sounds, so disable it to save on speed. */
71282             soundFlags |= MA_SOUND_FLAG_NO_SPATIALIZATION;     /* Not currently doing spatialization with inlined sounds, but this might actually change later. For now disable spatialization. Will be removed if we ever add support for spatialization here. */
71283
71284             result = ma_sound_init_from_file(pEngine, pFilePath, soundFlags, NULL, NULL, &pSound->sound);
71285             if (result == MA_SUCCESS) {
71286                 /* Now attach the sound to the graph. */
71287                 result = ma_node_attach_output_bus(pSound, 0, pNode, nodeInputBusIndex);
71288                 if (result == MA_SUCCESS) {
71289                     /* At this point the sound should be loaded and we can go ahead and add it to the list. The new item becomes the new head. */
71290                     pSound->pNext = pEngine->pInlinedSoundHead;
71291                     pSound->pPrev = NULL;
71292
71293                     pEngine->pInlinedSoundHead = pSound;    /* <-- This is what attaches the sound to the list. */
71294                     if (pSound->pNext != NULL) {
71295                         pSound->pNext->pPrev = pSound;
71296                     }
71297                 } else {
71298                     ma_free(pSound, &pEngine->allocationCallbacks);
71299                 }
71300             } else {
71301                 ma_free(pSound, &pEngine->allocationCallbacks);
71302             }
71303         } else {
71304             result = MA_OUT_OF_MEMORY;
71305         }
71306     }
71307     ma_spinlock_unlock(&pEngine->inlinedSoundLock);
71308
71309     if (result != MA_SUCCESS) {
71310         return result;
71311     }
71312
71313     /* Finally we can start playing the sound. */
71314     result = ma_sound_start(&pSound->sound);
71315     if (result != MA_SUCCESS) {
71316         /* Failed to start the sound. We need to mark it for recycling and return an error. */
71317         c89atomic_exchange_32(&pSound->sound.atEnd, MA_TRUE);
71318         return result;
71319     }
71320
71321     c89atomic_fetch_add_32(&pEngine->inlinedSoundCount, 1);
71322     return result;
71323 }
71324
71325 MA_API ma_result ma_engine_play_sound(ma_engine* pEngine, const char* pFilePath, ma_sound_group* pGroup)
71326 {
71327     return ma_engine_play_sound_ex(pEngine, pFilePath, pGroup, 0);
71328 }
71329 #endif
71330
71331
71332 static ma_result ma_sound_preinit(ma_engine* pEngine, ma_sound* pSound)
71333 {
71334     if (pSound == NULL) {
71335         return MA_INVALID_ARGS;
71336     }
71337
71338     MA_ZERO_OBJECT(pSound);
71339     pSound->seekTarget = MA_SEEK_TARGET_NONE;
71340
71341     if (pEngine == NULL) {
71342         return MA_INVALID_ARGS;
71343     }
71344
71345     return MA_SUCCESS;
71346 }
71347
71348 static ma_result ma_sound_init_from_data_source_internal(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound)
71349 {
71350     ma_result result;
71351     ma_engine_node_config engineNodeConfig;
71352     ma_engine_node_type type;   /* Will be set to ma_engine_node_type_group if no data source is specified. */
71353
71354     /* Do not clear pSound to zero here - that's done at a higher level with ma_sound_preinit(). */
71355     MA_ASSERT(pEngine != NULL);
71356     MA_ASSERT(pSound  != NULL);
71357
71358     if (pConfig == NULL) {
71359         return MA_INVALID_ARGS;
71360     }
71361
71362     pSound->pDataSource = pConfig->pDataSource;
71363
71364     if (pConfig->pDataSource != NULL) {
71365         type = ma_engine_node_type_sound;
71366     } else {
71367         type = ma_engine_node_type_group;
71368     }
71369
71370     /*
71371     Sounds are engine nodes. Before we can initialize this we need to determine the channel count.
71372     If we can't do this we need to abort. It's up to the caller to ensure they're using a data
71373     source that provides this information upfront.
71374     */
71375     engineNodeConfig = ma_engine_node_config_init(pEngine, type, pConfig->flags);
71376     engineNodeConfig.channelsIn  = pConfig->channelsIn;
71377     engineNodeConfig.channelsOut = pConfig->channelsOut;
71378
71379     /* If we're loading from a data source the input channel count needs to be the data source's native channel count. */
71380     if (pConfig->pDataSource != NULL) {
71381         result = ma_data_source_get_data_format(pConfig->pDataSource, NULL, &engineNodeConfig.channelsIn, &engineNodeConfig.sampleRate, NULL, 0);
71382         if (result != MA_SUCCESS) {
71383             return result;  /* Failed to retrieve the channel count. */
71384         }
71385
71386         if (engineNodeConfig.channelsIn == 0) {
71387             return MA_INVALID_OPERATION;    /* Invalid channel count. */
71388         }
71389
71390         if (engineNodeConfig.channelsOut == MA_SOUND_SOURCE_CHANNEL_COUNT) {
71391             engineNodeConfig.channelsOut = engineNodeConfig.channelsIn;
71392         }
71393     }
71394
71395
71396     /* Getting here means we should have a valid channel count and we can initialize the engine node. */
71397     result = ma_engine_node_init(&engineNodeConfig, &pEngine->allocationCallbacks, &pSound->engineNode);
71398     if (result != MA_SUCCESS) {
71399         return result;
71400     }
71401
71402     /* If no attachment is specified, attach the sound straight to the endpoint. */
71403     if (pConfig->pInitialAttachment == NULL) {
71404         /* No group. Attach straight to the endpoint by default, unless the caller has requested that do not. */
71405         if ((pConfig->flags & MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT) == 0) {
71406             result = ma_node_attach_output_bus(pSound, 0, ma_node_graph_get_endpoint(&pEngine->nodeGraph), 0);
71407         }
71408     } else {
71409         /* An attachment is specified. Attach to it by default. The sound has only a single output bus, and the config will specify which input bus to attach to. */
71410         result = ma_node_attach_output_bus(pSound, 0, pConfig->pInitialAttachment, pConfig->initialAttachmentInputBusIndex);
71411     }
71412
71413     if (result != MA_SUCCESS) {
71414         ma_engine_node_uninit(&pSound->engineNode, &pEngine->allocationCallbacks);
71415         return result;
71416     }
71417
71418
71419     /* Apply initial range and looping state to the data source if applicable. */
71420     if (pConfig->rangeBegInPCMFrames != 0 || pConfig->rangeEndInPCMFrames != ~((ma_uint64)0)) {
71421         ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames);
71422     }
71423
71424     if (pConfig->loopPointBegInPCMFrames != 0 || pConfig->loopPointEndInPCMFrames != ~((ma_uint64)0)) {
71425         ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames);
71426     }
71427
71428     ma_sound_set_looping(pSound, pConfig->isLooping);
71429
71430     return MA_SUCCESS;
71431 }
71432
71433 #ifndef MA_NO_RESOURCE_MANAGER
71434 MA_API ma_result ma_sound_init_from_file_internal(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound)
71435 {
71436     ma_result result = MA_SUCCESS;
71437     ma_uint32 flags;
71438     ma_sound_config config;
71439     ma_resource_manager_pipeline_notifications notifications;
71440
71441     /*
71442     The engine requires knowledge of the channel count of the underlying data source before it can
71443     initialize the sound. Therefore, we need to make the resource manager wait until initialization
71444     of the underlying data source to be initialized so we can get access to the channel count. To
71445     do this, the MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT is forced.
71446
71447     Because we're initializing the data source before the sound, there's a chance the notification
71448     will get triggered before this function returns. This is OK, so long as the caller is aware of
71449     it and can avoid accessing the sound from within the notification.
71450     */
71451     flags = pConfig->flags | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT;
71452
71453     pSound->pResourceManagerDataSource = (ma_resource_manager_data_source*)ma_malloc(sizeof(*pSound->pResourceManagerDataSource), &pEngine->allocationCallbacks);
71454     if (pSound->pResourceManagerDataSource == NULL) {
71455         return MA_OUT_OF_MEMORY;
71456     }
71457
71458     notifications = ma_resource_manager_pipeline_notifications_init();
71459     notifications.done.pFence = pConfig->pDoneFence;
71460
71461     /*
71462     We must wrap everything around the fence if one was specified. This ensures ma_fence_wait() does
71463     not return prematurely before the sound has finished initializing.
71464     */
71465     if (notifications.done.pFence) { ma_fence_acquire(notifications.done.pFence); }
71466     {
71467         ma_resource_manager_data_source_config resourceManagerDataSourceConfig = ma_resource_manager_data_source_config_init();
71468         resourceManagerDataSourceConfig.pFilePath                   = pConfig->pFilePath;
71469         resourceManagerDataSourceConfig.pFilePathW                  = pConfig->pFilePathW;
71470         resourceManagerDataSourceConfig.flags                       = flags;
71471         resourceManagerDataSourceConfig.pNotifications              = &notifications;
71472         resourceManagerDataSourceConfig.initialSeekPointInPCMFrames = pConfig->initialSeekPointInPCMFrames;
71473         resourceManagerDataSourceConfig.rangeBegInPCMFrames         = pConfig->rangeBegInPCMFrames;
71474         resourceManagerDataSourceConfig.rangeEndInPCMFrames         = pConfig->rangeEndInPCMFrames;
71475         resourceManagerDataSourceConfig.loopPointBegInPCMFrames     = pConfig->loopPointBegInPCMFrames;
71476         resourceManagerDataSourceConfig.loopPointEndInPCMFrames     = pConfig->loopPointEndInPCMFrames;
71477         resourceManagerDataSourceConfig.isLooping                   = pConfig->isLooping;
71478
71479         result = ma_resource_manager_data_source_init_ex(pEngine->pResourceManager, &resourceManagerDataSourceConfig, pSound->pResourceManagerDataSource);
71480         if (result != MA_SUCCESS) {
71481             goto done;
71482         }
71483
71484         pSound->ownsDataSource = MA_TRUE;   /* <-- Important. Not setting this will result in the resource manager data source never getting uninitialized. */
71485
71486         /* We need to use a slightly customized version of the config so we'll need to make a copy. */
71487         config = *pConfig;
71488         config.pFilePath   = NULL;
71489         config.pFilePathW  = NULL;
71490         config.pDataSource = pSound->pResourceManagerDataSource;
71491
71492         result = ma_sound_init_from_data_source_internal(pEngine, &config, pSound);
71493         if (result != MA_SUCCESS) {
71494             ma_resource_manager_data_source_uninit(pSound->pResourceManagerDataSource);
71495             ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks);
71496             MA_ZERO_OBJECT(pSound);
71497             goto done;
71498         }
71499     }
71500 done:
71501     if (notifications.done.pFence) { ma_fence_release(notifications.done.pFence); }
71502     return result;
71503 }
71504
71505 MA_API ma_result ma_sound_init_from_file(ma_engine* pEngine, const char* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound)
71506 {
71507     ma_sound_config config = ma_sound_config_init();
71508     config.pFilePath          = pFilePath;
71509     config.flags              = flags;
71510     config.pInitialAttachment = pGroup;
71511     config.pDoneFence         = pDoneFence;
71512     return ma_sound_init_ex(pEngine, &config, pSound);
71513 }
71514
71515 MA_API ma_result ma_sound_init_from_file_w(ma_engine* pEngine, const wchar_t* pFilePath, ma_uint32 flags, ma_sound_group* pGroup, ma_fence* pDoneFence, ma_sound* pSound)
71516 {
71517     ma_sound_config config = ma_sound_config_init();
71518     config.pFilePathW         = pFilePath;
71519     config.flags              = flags;
71520     config.pInitialAttachment = pGroup;
71521     config.pDoneFence         = pDoneFence;
71522     return ma_sound_init_ex(pEngine, &config, pSound);
71523 }
71524
71525 MA_API ma_result ma_sound_init_copy(ma_engine* pEngine, const ma_sound* pExistingSound, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound)
71526 {
71527     ma_result result;
71528     ma_sound_config config;
71529
71530     result = ma_sound_preinit(pEngine, pSound);
71531     if (result != MA_SUCCESS) {
71532         return result;
71533     }
71534
71535     if (pExistingSound == NULL) {
71536         return MA_INVALID_ARGS;
71537     }
71538
71539     /* Cloning only works for data buffers (not streams) that are loaded from the resource manager. */
71540     if (pExistingSound->pResourceManagerDataSource == NULL) {
71541         return MA_INVALID_OPERATION;
71542     }
71543
71544     /*
71545     We need to make a clone of the data source. If the data source is not a data buffer (i.e. a stream)
71546     the this will fail.
71547     */
71548     pSound->pResourceManagerDataSource = (ma_resource_manager_data_source*)ma_malloc(sizeof(*pSound->pResourceManagerDataSource), &pEngine->allocationCallbacks);
71549     if (pSound->pResourceManagerDataSource == NULL) {
71550         return MA_OUT_OF_MEMORY;
71551     }
71552
71553     result = ma_resource_manager_data_source_init_copy(pEngine->pResourceManager, pExistingSound->pResourceManagerDataSource, pSound->pResourceManagerDataSource);
71554     if (result != MA_SUCCESS) {
71555         ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks);
71556         return result;
71557     }
71558
71559     config = ma_sound_config_init();
71560     config.pDataSource        = pSound->pResourceManagerDataSource;
71561     config.flags              = flags;
71562     config.pInitialAttachment = pGroup;
71563
71564     result = ma_sound_init_from_data_source_internal(pEngine, &config, pSound);
71565     if (result != MA_SUCCESS) {
71566         ma_resource_manager_data_source_uninit(pSound->pResourceManagerDataSource);
71567         ma_free(pSound->pResourceManagerDataSource, &pEngine->allocationCallbacks);
71568         MA_ZERO_OBJECT(pSound);
71569         return result;
71570     }
71571
71572     return MA_SUCCESS;
71573 }
71574 #endif
71575
71576 MA_API ma_result ma_sound_init_from_data_source(ma_engine* pEngine, ma_data_source* pDataSource, ma_uint32 flags, ma_sound_group* pGroup, ma_sound* pSound)
71577 {
71578     ma_sound_config config = ma_sound_config_init();
71579     config.pDataSource        = pDataSource;
71580     config.flags              = flags;
71581     config.pInitialAttachment = pGroup;
71582     return ma_sound_init_ex(pEngine, &config, pSound);
71583 }
71584
71585 MA_API ma_result ma_sound_init_ex(ma_engine* pEngine, const ma_sound_config* pConfig, ma_sound* pSound)
71586 {
71587     ma_result result;
71588
71589     result = ma_sound_preinit(pEngine, pSound);
71590     if (result != MA_SUCCESS) {
71591         return result;
71592     }
71593
71594     if (pConfig == NULL) {
71595         return MA_INVALID_ARGS;
71596     }
71597
71598     /* We need to load the sound differently depending on whether or not we're loading from a file. */
71599 #ifndef MA_NO_RESOURCE_MANAGER
71600     if (pConfig->pFilePath != NULL || pConfig->pFilePathW != NULL) {
71601         return ma_sound_init_from_file_internal(pEngine, pConfig, pSound);
71602     } else
71603 #endif
71604     {
71605         /*
71606         Getting here means we're not loading from a file. We may be loading from an already-initialized
71607         data source, or none at all. If we aren't specifying any data source, we'll be initializing the
71608         the equivalent to a group. ma_data_source_init_from_data_source_internal() will deal with this
71609         for us, so no special treatment required here.
71610         */
71611         return ma_sound_init_from_data_source_internal(pEngine, pConfig, pSound);
71612     }
71613 }
71614
71615 MA_API void ma_sound_uninit(ma_sound* pSound)
71616 {
71617     if (pSound == NULL) {
71618         return;
71619     }
71620
71621     /*
71622     Always uninitialize the node first. This ensures it's detached from the graph and does not return until it has done
71623     so which makes thread safety beyond this point trivial.
71624     */
71625     ma_engine_node_uninit(&pSound->engineNode, &pSound->engineNode.pEngine->allocationCallbacks);
71626
71627     /* Once the sound is detached from the group we can guarantee that it won't be referenced by the mixer thread which means it's safe for us to destroy the data source. */
71628 #ifndef MA_NO_RESOURCE_MANAGER
71629     if (pSound->ownsDataSource) {
71630         ma_resource_manager_data_source_uninit(pSound->pResourceManagerDataSource);
71631         ma_free(pSound->pResourceManagerDataSource, &pSound->engineNode.pEngine->allocationCallbacks);
71632         pSound->pDataSource = NULL;
71633     }
71634 #else
71635     MA_ASSERT(pSound->ownsDataSource == MA_FALSE);
71636 #endif
71637 }
71638
71639 MA_API ma_engine* ma_sound_get_engine(const ma_sound* pSound)
71640 {
71641     if (pSound == NULL) {
71642         return NULL;
71643     }
71644
71645     return pSound->engineNode.pEngine;
71646 }
71647
71648 MA_API ma_data_source* ma_sound_get_data_source(const ma_sound* pSound)
71649 {
71650     if (pSound == NULL) {
71651         return NULL;
71652     }
71653
71654     return pSound->pDataSource;
71655 }
71656
71657 MA_API ma_result ma_sound_start(ma_sound* pSound)
71658 {
71659     if (pSound == NULL) {
71660         return MA_INVALID_ARGS;
71661     }
71662
71663     /* If the sound is already playing, do nothing. */
71664     if (ma_sound_is_playing(pSound)) {
71665         return MA_SUCCESS;
71666     }
71667
71668     /* If the sound is at the end it means we want to start from the start again. */
71669     if (ma_sound_at_end(pSound)) {
71670         ma_result result = ma_data_source_seek_to_pcm_frame(pSound->pDataSource, 0);
71671         if (result != MA_SUCCESS && result != MA_NOT_IMPLEMENTED) {
71672             return result;  /* Failed to seek back to the start. */
71673         }
71674
71675         /* Make sure we clear the end indicator. */
71676         c89atomic_exchange_32(&pSound->atEnd, MA_FALSE);
71677     }
71678
71679     /* Make sure the sound is started. If there's a start delay, the sound won't actually start until the start time is reached. */
71680     ma_node_set_state(pSound, ma_node_state_started);
71681
71682     return MA_SUCCESS;
71683 }
71684
71685 MA_API ma_result ma_sound_stop(ma_sound* pSound)
71686 {
71687     if (pSound == NULL) {
71688         return MA_INVALID_ARGS;
71689     }
71690
71691     /* This will stop the sound immediately. Use ma_sound_set_stop_time() to stop the sound at a specific time. */
71692     ma_node_set_state(pSound, ma_node_state_stopped);
71693
71694     return MA_SUCCESS;
71695 }
71696
71697 MA_API void ma_sound_set_volume(ma_sound* pSound, float volume)
71698 {
71699     if (pSound == NULL) {
71700         return;
71701     }
71702
71703     /* The volume is controlled via the output bus. */
71704     ma_node_set_output_bus_volume(pSound, 0, volume);
71705 }
71706
71707 MA_API float ma_sound_get_volume(const ma_sound* pSound)
71708 {
71709     if (pSound == NULL) {
71710         return 0;
71711     }
71712
71713     return ma_node_get_output_bus_volume(pSound, 0);
71714 }
71715
71716 MA_API void ma_sound_set_pan(ma_sound* pSound, float pan)
71717 {
71718     if (pSound == NULL) {
71719         return;
71720     }
71721
71722     ma_panner_set_pan(&pSound->engineNode.panner, pan);
71723 }
71724
71725 MA_API float ma_sound_get_pan(const ma_sound* pSound)
71726 {
71727     if (pSound == NULL) {
71728         return 0;
71729     }
71730
71731     return ma_panner_get_pan(&pSound->engineNode.panner);
71732 }
71733
71734 MA_API void ma_sound_set_pan_mode(ma_sound* pSound, ma_pan_mode panMode)
71735 {
71736     if (pSound == NULL) {
71737         return;
71738     }
71739
71740     ma_panner_set_mode(&pSound->engineNode.panner, panMode);
71741 }
71742
71743 MA_API ma_pan_mode ma_sound_get_pan_mode(const ma_sound* pSound)
71744 {
71745     if (pSound == NULL) {
71746         return ma_pan_mode_balance;
71747     }
71748
71749     return ma_panner_get_mode(&pSound->engineNode.panner);
71750 }
71751
71752 MA_API void ma_sound_set_pitch(ma_sound* pSound, float pitch)
71753 {
71754     if (pSound == NULL) {
71755         return;
71756     }
71757
71758     c89atomic_exchange_explicit_f32(&pSound->engineNode.pitch, pitch, c89atomic_memory_order_release);
71759 }
71760
71761 MA_API float ma_sound_get_pitch(const ma_sound* pSound)
71762 {
71763     if (pSound == NULL) {
71764         return 0;
71765     }
71766
71767     return c89atomic_load_f32(&pSound->engineNode.pitch);    /* Naughty const-cast for this. */
71768 }
71769
71770 MA_API void ma_sound_set_spatialization_enabled(ma_sound* pSound, ma_bool32 enabled)
71771 {
71772     if (pSound == NULL) {
71773         return;
71774     }
71775
71776     c89atomic_exchange_explicit_32(&pSound->engineNode.isSpatializationDisabled, !enabled, c89atomic_memory_order_release);
71777 }
71778
71779 MA_API ma_bool32 ma_sound_is_spatialization_enabled(const ma_sound* pSound)
71780 {
71781     if (pSound == NULL) {
71782         return MA_FALSE;
71783     }
71784
71785     return ma_engine_node_is_spatialization_enabled(&pSound->engineNode);
71786 }
71787
71788 MA_API void ma_sound_set_pinned_listener_index(ma_sound* pSound, ma_uint32 listenerIndex)
71789 {
71790     if (pSound == NULL || listenerIndex >= ma_engine_get_listener_count(ma_sound_get_engine(pSound))) {
71791         return;
71792     }
71793
71794     c89atomic_exchange_explicit_32(&pSound->engineNode.pinnedListenerIndex, listenerIndex, c89atomic_memory_order_release);
71795 }
71796
71797 MA_API ma_uint32 ma_sound_get_pinned_listener_index(const ma_sound* pSound)
71798 {
71799     if (pSound == NULL) {
71800         return MA_LISTENER_INDEX_CLOSEST;
71801     }
71802
71803     return c89atomic_load_explicit_32(&pSound->engineNode.pinnedListenerIndex, c89atomic_memory_order_acquire);
71804 }
71805
71806 MA_API ma_uint32 ma_sound_get_listener_index(const ma_sound* pSound)
71807 {
71808     ma_uint32 listenerIndex;
71809
71810     if (pSound == NULL) {
71811         return 0;
71812     }
71813
71814     listenerIndex = ma_sound_get_pinned_listener_index(pSound);
71815     if (listenerIndex == MA_LISTENER_INDEX_CLOSEST) {
71816         ma_vec3f position = ma_sound_get_position(pSound);
71817         return ma_engine_find_closest_listener(ma_sound_get_engine(pSound), position.x, position.y, position.z);
71818     }
71819
71820     return listenerIndex;
71821 }
71822
71823 MA_API ma_vec3f ma_sound_get_direction_to_listener(const ma_sound* pSound)
71824 {
71825     ma_vec3f relativePos;
71826     ma_engine* pEngine;
71827
71828     if (pSound == NULL) {
71829         return ma_vec3f_init_3f(0, 0, -1);
71830     }
71831
71832     pEngine = ma_sound_get_engine(pSound);
71833     if (pEngine == NULL) {
71834         return ma_vec3f_init_3f(0, 0, -1);
71835     }
71836
71837     ma_spatializer_get_relative_position_and_direction(&pSound->engineNode.spatializer, &pEngine->listeners[ma_sound_get_listener_index(pSound)], &relativePos, NULL);
71838
71839     return ma_vec3f_normalize(ma_vec3f_neg(relativePos));
71840 }
71841
71842 MA_API void ma_sound_set_position(ma_sound* pSound, float x, float y, float z)
71843 {
71844     if (pSound == NULL) {
71845         return;
71846     }
71847
71848     ma_spatializer_set_position(&pSound->engineNode.spatializer, x, y, z);
71849 }
71850
71851 MA_API ma_vec3f ma_sound_get_position(const ma_sound* pSound)
71852 {
71853     if (pSound == NULL) {
71854         return ma_vec3f_init_3f(0, 0, 0);
71855     }
71856
71857     return ma_spatializer_get_position(&pSound->engineNode.spatializer);
71858 }
71859
71860 MA_API void ma_sound_set_direction(ma_sound* pSound, float x, float y, float z)
71861 {
71862     if (pSound == NULL) {
71863         return;
71864     }
71865
71866     ma_spatializer_set_direction(&pSound->engineNode.spatializer, x, y, z);
71867 }
71868
71869 MA_API ma_vec3f ma_sound_get_direction(const ma_sound* pSound)
71870 {
71871     if (pSound == NULL) {
71872         return ma_vec3f_init_3f(0, 0, 0);
71873     }
71874
71875     return ma_spatializer_get_direction(&pSound->engineNode.spatializer);
71876 }
71877
71878 MA_API void ma_sound_set_velocity(ma_sound* pSound, float x, float y, float z)
71879 {
71880     if (pSound == NULL) {
71881         return;
71882     }
71883
71884     ma_spatializer_set_velocity(&pSound->engineNode.spatializer, x, y, z);
71885 }
71886
71887 MA_API ma_vec3f ma_sound_get_velocity(const ma_sound* pSound)
71888 {
71889     if (pSound == NULL) {
71890         return ma_vec3f_init_3f(0, 0, 0);
71891     }
71892
71893     return ma_spatializer_get_velocity(&pSound->engineNode.spatializer);
71894 }
71895
71896 MA_API void ma_sound_set_attenuation_model(ma_sound* pSound, ma_attenuation_model attenuationModel)
71897 {
71898     if (pSound == NULL) {
71899         return;
71900     }
71901
71902     ma_spatializer_set_attenuation_model(&pSound->engineNode.spatializer, attenuationModel);
71903 }
71904
71905 MA_API ma_attenuation_model ma_sound_get_attenuation_model(const ma_sound* pSound)
71906 {
71907     if (pSound == NULL) {
71908         return ma_attenuation_model_none;
71909     }
71910
71911     return ma_spatializer_get_attenuation_model(&pSound->engineNode.spatializer);
71912 }
71913
71914 MA_API void ma_sound_set_positioning(ma_sound* pSound, ma_positioning positioning)
71915 {
71916     if (pSound == NULL) {
71917         return;
71918     }
71919
71920     ma_spatializer_set_positioning(&pSound->engineNode.spatializer, positioning);
71921 }
71922
71923 MA_API ma_positioning ma_sound_get_positioning(const ma_sound* pSound)
71924 {
71925     if (pSound == NULL) {
71926         return ma_positioning_absolute;
71927     }
71928
71929     return ma_spatializer_get_positioning(&pSound->engineNode.spatializer);
71930 }
71931
71932 MA_API void ma_sound_set_rolloff(ma_sound* pSound, float rolloff)
71933 {
71934     if (pSound == NULL) {
71935         return;
71936     }
71937
71938     ma_spatializer_set_rolloff(&pSound->engineNode.spatializer, rolloff);
71939 }
71940
71941 MA_API float ma_sound_get_rolloff(const ma_sound* pSound)
71942 {
71943     if (pSound == NULL) {
71944         return 0;
71945     }
71946
71947     return ma_spatializer_get_rolloff(&pSound->engineNode.spatializer);
71948 }
71949
71950 MA_API void ma_sound_set_min_gain(ma_sound* pSound, float minGain)
71951 {
71952     if (pSound == NULL) {
71953         return;
71954     }
71955
71956     ma_spatializer_set_min_gain(&pSound->engineNode.spatializer, minGain);
71957 }
71958
71959 MA_API float ma_sound_get_min_gain(const ma_sound* pSound)
71960 {
71961     if (pSound == NULL) {
71962         return 0;
71963     }
71964
71965     return ma_spatializer_get_min_gain(&pSound->engineNode.spatializer);
71966 }
71967
71968 MA_API void ma_sound_set_max_gain(ma_sound* pSound, float maxGain)
71969 {
71970     if (pSound == NULL) {
71971         return;
71972     }
71973
71974     ma_spatializer_set_max_gain(&pSound->engineNode.spatializer, maxGain);
71975 }
71976
71977 MA_API float ma_sound_get_max_gain(const ma_sound* pSound)
71978 {
71979     if (pSound == NULL) {
71980         return 0;
71981     }
71982
71983     return ma_spatializer_get_max_gain(&pSound->engineNode.spatializer);
71984 }
71985
71986 MA_API void ma_sound_set_min_distance(ma_sound* pSound, float minDistance)
71987 {
71988     if (pSound == NULL) {
71989         return;
71990     }
71991
71992     ma_spatializer_set_min_distance(&pSound->engineNode.spatializer, minDistance);
71993 }
71994
71995 MA_API float ma_sound_get_min_distance(const ma_sound* pSound)
71996 {
71997     if (pSound == NULL) {
71998         return 0;
71999     }
72000
72001     return ma_spatializer_get_min_distance(&pSound->engineNode.spatializer);
72002 }
72003
72004 MA_API void ma_sound_set_max_distance(ma_sound* pSound, float maxDistance)
72005 {
72006     if (pSound == NULL) {
72007         return;
72008     }
72009
72010     ma_spatializer_set_max_distance(&pSound->engineNode.spatializer, maxDistance);
72011 }
72012
72013 MA_API float ma_sound_get_max_distance(const ma_sound* pSound)
72014 {
72015     if (pSound == NULL) {
72016         return 0;
72017     }
72018
72019     return ma_spatializer_get_max_distance(&pSound->engineNode.spatializer);
72020 }
72021
72022 MA_API void ma_sound_set_cone(ma_sound* pSound, float innerAngleInRadians, float outerAngleInRadians, float outerGain)
72023 {
72024     if (pSound == NULL) {
72025         return;
72026     }
72027
72028     ma_spatializer_set_cone(&pSound->engineNode.spatializer, innerAngleInRadians, outerAngleInRadians, outerGain);
72029 }
72030
72031 MA_API void ma_sound_get_cone(const ma_sound* pSound, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain)
72032 {
72033     if (pInnerAngleInRadians != NULL) {
72034         *pInnerAngleInRadians = 0;
72035     }
72036
72037     if (pOuterAngleInRadians != NULL) {
72038         *pOuterAngleInRadians = 0;
72039     }
72040
72041     if (pOuterGain != NULL) {
72042         *pOuterGain = 0;
72043     }
72044
72045     ma_spatializer_get_cone(&pSound->engineNode.spatializer, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain);
72046 }
72047
72048 MA_API void ma_sound_set_doppler_factor(ma_sound* pSound, float dopplerFactor)
72049 {
72050     if (pSound == NULL) {
72051         return;
72052     }
72053
72054     ma_spatializer_set_doppler_factor(&pSound->engineNode.spatializer, dopplerFactor);
72055 }
72056
72057 MA_API float ma_sound_get_doppler_factor(const ma_sound* pSound)
72058 {
72059     if (pSound == NULL) {
72060         return 0;
72061     }
72062
72063     return ma_spatializer_get_doppler_factor(&pSound->engineNode.spatializer);
72064 }
72065
72066 MA_API void ma_sound_set_directional_attenuation_factor(ma_sound* pSound, float directionalAttenuationFactor)
72067 {
72068     if (pSound == NULL) {
72069         return;
72070     }
72071
72072     ma_spatializer_set_directional_attenuation_factor(&pSound->engineNode.spatializer, directionalAttenuationFactor);
72073 }
72074
72075 MA_API float ma_sound_get_directional_attenuation_factor(const ma_sound* pSound)
72076 {
72077     if (pSound == NULL) {
72078         return 1;
72079     }
72080
72081     return ma_spatializer_get_directional_attenuation_factor(&pSound->engineNode.spatializer);
72082 }
72083
72084
72085 MA_API void ma_sound_set_fade_in_pcm_frames(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames)
72086 {
72087     if (pSound == NULL) {
72088         return;
72089     }
72090
72091     ma_fader_set_fade(&pSound->engineNode.fader, volumeBeg, volumeEnd, fadeLengthInFrames);
72092 }
72093
72094 MA_API void ma_sound_set_fade_in_milliseconds(ma_sound* pSound, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds)
72095 {
72096     if (pSound == NULL) {
72097         return;
72098     }
72099
72100     ma_sound_set_fade_in_pcm_frames(pSound, volumeBeg, volumeEnd, (fadeLengthInMilliseconds * pSound->engineNode.fader.config.sampleRate) / 1000);
72101 }
72102
72103 MA_API float ma_sound_get_current_fade_volume(ma_sound* pSound)
72104 {
72105     if (pSound == NULL) {
72106         return MA_INVALID_ARGS;
72107     }
72108
72109     return ma_fader_get_current_volume(&pSound->engineNode.fader);
72110 }
72111
72112 MA_API void ma_sound_set_start_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames)
72113 {
72114     if (pSound == NULL) {
72115         return;
72116     }
72117
72118     ma_node_set_state_time(pSound, ma_node_state_started, absoluteGlobalTimeInFrames);
72119 }
72120
72121 MA_API void ma_sound_set_start_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds)
72122 {
72123     if (pSound == NULL) {
72124         return;
72125     }
72126
72127     ma_sound_set_start_time_in_pcm_frames(pSound, absoluteGlobalTimeInMilliseconds * ma_engine_get_sample_rate(ma_sound_get_engine(pSound)) / 1000);
72128 }
72129
72130 MA_API void ma_sound_set_stop_time_in_pcm_frames(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInFrames)
72131 {
72132     if (pSound == NULL) {
72133         return;
72134     }
72135
72136     ma_node_set_state_time(pSound, ma_node_state_stopped, absoluteGlobalTimeInFrames);
72137 }
72138
72139 MA_API void ma_sound_set_stop_time_in_milliseconds(ma_sound* pSound, ma_uint64 absoluteGlobalTimeInMilliseconds)
72140 {
72141     if (pSound == NULL) {
72142         return;
72143     }
72144
72145     ma_sound_set_stop_time_in_pcm_frames(pSound, absoluteGlobalTimeInMilliseconds * ma_engine_get_sample_rate(ma_sound_get_engine(pSound)) / 1000);
72146 }
72147
72148 MA_API ma_bool32 ma_sound_is_playing(const ma_sound* pSound)
72149 {
72150     if (pSound == NULL) {
72151         return MA_FALSE;
72152     }
72153
72154     return ma_node_get_state_by_time(pSound, ma_engine_get_time(ma_sound_get_engine(pSound))) == ma_node_state_started;
72155 }
72156
72157 MA_API ma_uint64 ma_sound_get_time_in_pcm_frames(const ma_sound* pSound)
72158 {
72159     if (pSound == NULL) {
72160         return 0;
72161     }
72162
72163     return ma_node_get_time(pSound);
72164 }
72165
72166 MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping)
72167 {
72168     if (pSound == NULL) {
72169         return;
72170     }
72171
72172     /* Looping is only a valid concept if the sound is backed by a data source. */
72173     if (pSound->pDataSource == NULL) {
72174         return;
72175     }
72176
72177     /* The looping state needs to be applied to the data source in order for any looping to actually happen. */
72178     ma_data_source_set_looping(pSound->pDataSource, isLooping);
72179 }
72180
72181 MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound)
72182 {
72183     if (pSound == NULL) {
72184         return MA_FALSE;
72185     }
72186
72187     /* There is no notion of looping for sounds that are not backed by a data source. */
72188     if (pSound->pDataSource == NULL) {
72189         return MA_FALSE;
72190     }
72191
72192     return ma_data_source_is_looping(pSound->pDataSource);
72193 }
72194
72195 MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound)
72196 {
72197     if (pSound == NULL) {
72198         return MA_FALSE;
72199     }
72200
72201     /* There is no notion of an end of a sound if it's not backed by a data source. */
72202     if (pSound->pDataSource == NULL) {
72203         return MA_FALSE;
72204     }
72205
72206     return c89atomic_load_32(&pSound->atEnd);
72207 }
72208
72209 MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex)
72210 {
72211     if (pSound == NULL) {
72212         return MA_INVALID_ARGS;
72213     }
72214
72215     /* Seeking is only valid for sounds that are backed by a data source. */
72216     if (pSound->pDataSource == NULL) {
72217         return MA_INVALID_OPERATION;
72218     }
72219
72220     /*
72221     Resource manager data sources are thread safe which means we can just seek immediately. However, we cannot guarantee that other data sources are
72222     thread safe as well so in that case we'll need to get the mixing thread to seek for us to ensure we don't try seeking at the same time as reading.
72223     */
72224 #ifndef MA_NO_RESOURCE_MANAGER
72225     if (pSound->pDataSource == pSound->pResourceManagerDataSource) {
72226         ma_result result = ma_resource_manager_data_source_seek_to_pcm_frame(pSound->pResourceManagerDataSource, frameIndex);
72227         if (result != MA_SUCCESS) {
72228             return result;
72229         }
72230
72231         /* Time dependant effects need to have their timers updated. */
72232         return ma_node_set_time(&pSound->engineNode, frameIndex);
72233     }
72234 #endif
72235
72236     /* Getting here means the data source is not a resource manager data source so we'll need to get the mixing thread to do the seeking for us. */
72237     pSound->seekTarget = frameIndex;
72238
72239     return MA_SUCCESS;
72240 }
72241
72242 MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
72243 {
72244     if (pSound == NULL) {
72245         return MA_INVALID_ARGS;
72246     }
72247
72248     /* The data format is retrieved directly from the data source if the sound is backed by one. Otherwise we pull it from the node. */
72249     if (pSound->pDataSource == NULL) {
72250         ma_uint32 channels;
72251
72252         if (pFormat != NULL) {
72253             *pFormat = ma_format_f32;
72254         }
72255
72256         channels = ma_node_get_input_channels(&pSound->engineNode, 0);
72257         if (pChannels != NULL) {
72258             *pChannels = channels;
72259         }
72260
72261         if (pSampleRate != NULL) {
72262             *pSampleRate = pSound->engineNode.resampler.config.sampleRateIn;
72263         }
72264
72265         if (pChannelMap != NULL) {
72266             ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, channels);
72267         }
72268
72269         return MA_SUCCESS;
72270     } else {
72271         return ma_data_source_get_data_format(pSound->pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
72272     }
72273 }
72274
72275 MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor)
72276 {
72277     if (pSound == NULL) {
72278         return MA_INVALID_ARGS;
72279     }
72280
72281     /* The notion of a cursor is only valid for sounds that are backed by a data source. */
72282     if (pSound->pDataSource == NULL) {
72283         return MA_INVALID_OPERATION;
72284     }
72285
72286     return ma_data_source_get_cursor_in_pcm_frames(pSound->pDataSource, pCursor);
72287 }
72288
72289 MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength)
72290 {
72291     if (pSound == NULL) {
72292         return MA_INVALID_ARGS;
72293     }
72294
72295     /* The notion of a sound length is only valid for sounds that are backed by a data source. */
72296     if (pSound->pDataSource == NULL) {
72297         return MA_INVALID_OPERATION;
72298     }
72299
72300     return ma_data_source_get_length_in_pcm_frames(pSound->pDataSource, pLength);
72301 }
72302
72303
72304 MA_API ma_result ma_sound_group_init(ma_engine* pEngine, ma_uint32 flags, ma_sound_group* pParentGroup, ma_sound_group* pGroup)
72305 {
72306     ma_sound_group_config config = ma_sound_group_config_init();
72307     config.flags              = flags;
72308     config.pInitialAttachment = pParentGroup;
72309     return ma_sound_group_init_ex(pEngine, &config, pGroup);
72310 }
72311
72312 MA_API ma_result ma_sound_group_init_ex(ma_engine* pEngine, const ma_sound_group_config* pConfig, ma_sound_group* pGroup)
72313 {
72314     ma_sound_config soundConfig;
72315
72316     if (pGroup == NULL) {
72317         return MA_INVALID_ARGS;
72318     }
72319
72320     MA_ZERO_OBJECT(pGroup);
72321
72322     if (pConfig == NULL) {
72323         return MA_INVALID_ARGS;
72324     }
72325
72326     /* A sound group is just a sound without a data source. */
72327     soundConfig = *pConfig;
72328     soundConfig.pFilePath   = NULL;
72329     soundConfig.pFilePathW  = NULL;
72330     soundConfig.pDataSource = NULL;
72331
72332     /*
72333     Groups need to have spatialization disabled by default because I think it'll be pretty rare
72334     that programs will want to spatialize groups (but not unheard of). Certainly it feels like
72335     disabling this by default feels like the right option. Spatialization can be enabled with a
72336     call to ma_sound_group_set_spatialization_enabled().
72337     */
72338     soundConfig.flags |= MA_SOUND_FLAG_NO_SPATIALIZATION;
72339
72340     return ma_sound_init_ex(pEngine, &soundConfig, pGroup);
72341 }
72342
72343 MA_API void ma_sound_group_uninit(ma_sound_group* pGroup)
72344 {
72345     ma_sound_uninit(pGroup);
72346 }
72347
72348 MA_API ma_engine* ma_sound_group_get_engine(const ma_sound_group* pGroup)
72349 {
72350     return ma_sound_get_engine(pGroup);
72351 }
72352
72353 MA_API ma_result ma_sound_group_start(ma_sound_group* pGroup)
72354 {
72355     return ma_sound_start(pGroup);
72356 }
72357
72358 MA_API ma_result ma_sound_group_stop(ma_sound_group* pGroup)
72359 {
72360     return ma_sound_stop(pGroup);
72361 }
72362
72363 MA_API void ma_sound_group_set_volume(ma_sound_group* pGroup, float volume)
72364 {
72365     ma_sound_set_volume(pGroup, volume);
72366 }
72367
72368 MA_API float ma_sound_group_get_volume(const ma_sound_group* pGroup)
72369 {
72370     return ma_sound_get_volume(pGroup);
72371 }
72372
72373 MA_API void ma_sound_group_set_pan(ma_sound_group* pGroup, float pan)
72374 {
72375     ma_sound_set_pan(pGroup, pan);
72376 }
72377
72378 MA_API float ma_sound_group_get_pan(const ma_sound_group* pGroup)
72379 {
72380     return ma_sound_get_pan(pGroup);
72381 }
72382
72383 MA_API void ma_sound_group_set_pan_mode(ma_sound_group* pGroup, ma_pan_mode panMode)
72384 {
72385     ma_sound_set_pan_mode(pGroup, panMode);
72386 }
72387
72388 MA_API ma_pan_mode ma_sound_group_get_pan_mode(const ma_sound_group* pGroup)
72389 {
72390     return ma_sound_get_pan_mode(pGroup);
72391 }
72392
72393 MA_API void ma_sound_group_set_pitch(ma_sound_group* pGroup, float pitch)
72394 {
72395     ma_sound_set_pitch(pGroup, pitch);
72396 }
72397
72398 MA_API float ma_sound_group_get_pitch(const ma_sound_group* pGroup)
72399 {
72400     return ma_sound_get_pitch(pGroup);
72401 }
72402
72403 MA_API void ma_sound_group_set_spatialization_enabled(ma_sound_group* pGroup, ma_bool32 enabled)
72404 {
72405     ma_sound_set_spatialization_enabled(pGroup, enabled);
72406 }
72407
72408 MA_API ma_bool32 ma_sound_group_is_spatialization_enabled(const ma_sound_group* pGroup)
72409 {
72410     return ma_sound_is_spatialization_enabled(pGroup);
72411 }
72412
72413 MA_API void ma_sound_group_set_pinned_listener_index(ma_sound_group* pGroup, ma_uint32 listenerIndex)
72414 {
72415     ma_sound_set_pinned_listener_index(pGroup, listenerIndex);
72416 }
72417
72418 MA_API ma_uint32 ma_sound_group_get_pinned_listener_index(const ma_sound_group* pGroup)
72419 {
72420     return ma_sound_get_pinned_listener_index(pGroup);
72421 }
72422
72423 MA_API ma_uint32 ma_sound_group_get_listener_index(const ma_sound_group* pGroup)
72424 {
72425     return ma_sound_get_listener_index(pGroup);
72426 }
72427
72428 MA_API ma_vec3f ma_sound_group_get_direction_to_listener(const ma_sound_group* pGroup)
72429 {
72430     return ma_sound_get_direction_to_listener(pGroup);
72431 }
72432
72433 MA_API void ma_sound_group_set_position(ma_sound_group* pGroup, float x, float y, float z)
72434 {
72435     ma_sound_set_position(pGroup, x, y, z);
72436 }
72437
72438 MA_API ma_vec3f ma_sound_group_get_position(const ma_sound_group* pGroup)
72439 {
72440     return ma_sound_get_position(pGroup);
72441 }
72442
72443 MA_API void ma_sound_group_set_direction(ma_sound_group* pGroup, float x, float y, float z)
72444 {
72445     ma_sound_set_direction(pGroup, x, y, z);
72446 }
72447
72448 MA_API ma_vec3f ma_sound_group_get_direction(const ma_sound_group* pGroup)
72449 {
72450     return ma_sound_get_direction(pGroup);
72451 }
72452
72453 MA_API void ma_sound_group_set_velocity(ma_sound_group* pGroup, float x, float y, float z)
72454 {
72455     ma_sound_set_velocity(pGroup, x, y, z);
72456 }
72457
72458 MA_API ma_vec3f ma_sound_group_get_velocity(const ma_sound_group* pGroup)
72459 {
72460     return ma_sound_get_velocity(pGroup);
72461 }
72462
72463 MA_API void ma_sound_group_set_attenuation_model(ma_sound_group* pGroup, ma_attenuation_model attenuationModel)
72464 {
72465     ma_sound_set_attenuation_model(pGroup, attenuationModel);
72466 }
72467
72468 MA_API ma_attenuation_model ma_sound_group_get_attenuation_model(const ma_sound_group* pGroup)
72469 {
72470     return ma_sound_get_attenuation_model(pGroup);
72471 }
72472
72473 MA_API void ma_sound_group_set_positioning(ma_sound_group* pGroup, ma_positioning positioning)
72474 {
72475     ma_sound_set_positioning(pGroup, positioning);
72476 }
72477
72478 MA_API ma_positioning ma_sound_group_get_positioning(const ma_sound_group* pGroup)
72479 {
72480     return ma_sound_get_positioning(pGroup);
72481 }
72482
72483 MA_API void ma_sound_group_set_rolloff(ma_sound_group* pGroup, float rolloff)
72484 {
72485     ma_sound_set_rolloff(pGroup, rolloff);
72486 }
72487
72488 MA_API float ma_sound_group_get_rolloff(const ma_sound_group* pGroup)
72489 {
72490     return ma_sound_get_rolloff(pGroup);
72491 }
72492
72493 MA_API void ma_sound_group_set_min_gain(ma_sound_group* pGroup, float minGain)
72494 {
72495     ma_sound_set_min_gain(pGroup, minGain);
72496 }
72497
72498 MA_API float ma_sound_group_get_min_gain(const ma_sound_group* pGroup)
72499 {
72500     return ma_sound_get_min_gain(pGroup);
72501 }
72502
72503 MA_API void ma_sound_group_set_max_gain(ma_sound_group* pGroup, float maxGain)
72504 {
72505     ma_sound_set_max_gain(pGroup, maxGain);
72506 }
72507
72508 MA_API float ma_sound_group_get_max_gain(const ma_sound_group* pGroup)
72509 {
72510     return ma_sound_get_max_gain(pGroup);
72511 }
72512
72513 MA_API void ma_sound_group_set_min_distance(ma_sound_group* pGroup, float minDistance)
72514 {
72515     ma_sound_set_min_distance(pGroup, minDistance);
72516 }
72517
72518 MA_API float ma_sound_group_get_min_distance(const ma_sound_group* pGroup)
72519 {
72520     return ma_sound_get_min_distance(pGroup);
72521 }
72522
72523 MA_API void ma_sound_group_set_max_distance(ma_sound_group* pGroup, float maxDistance)
72524 {
72525     ma_sound_set_max_distance(pGroup, maxDistance);
72526 }
72527
72528 MA_API float ma_sound_group_get_max_distance(const ma_sound_group* pGroup)
72529 {
72530     return ma_sound_get_max_distance(pGroup);
72531 }
72532
72533 MA_API void ma_sound_group_set_cone(ma_sound_group* pGroup, float innerAngleInRadians, float outerAngleInRadians, float outerGain)
72534 {
72535     ma_sound_set_cone(pGroup, innerAngleInRadians, outerAngleInRadians, outerGain);
72536 }
72537
72538 MA_API void ma_sound_group_get_cone(const ma_sound_group* pGroup, float* pInnerAngleInRadians, float* pOuterAngleInRadians, float* pOuterGain)
72539 {
72540     ma_sound_get_cone(pGroup, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain);
72541 }
72542
72543 MA_API void ma_sound_group_set_doppler_factor(ma_sound_group* pGroup, float dopplerFactor)
72544 {
72545     ma_sound_set_doppler_factor(pGroup, dopplerFactor);
72546 }
72547
72548 MA_API float ma_sound_group_get_doppler_factor(const ma_sound_group* pGroup)
72549 {
72550     return ma_sound_get_doppler_factor(pGroup);
72551 }
72552
72553 MA_API void ma_sound_group_set_directional_attenuation_factor(ma_sound_group* pGroup, float directionalAttenuationFactor)
72554 {
72555     ma_sound_set_directional_attenuation_factor(pGroup, directionalAttenuationFactor);
72556 }
72557
72558 MA_API float ma_sound_group_get_directional_attenuation_factor(const ma_sound_group* pGroup)
72559 {
72560     return ma_sound_get_directional_attenuation_factor(pGroup);
72561 }
72562
72563 MA_API void ma_sound_group_set_fade_in_pcm_frames(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInFrames)
72564 {
72565     ma_sound_set_fade_in_pcm_frames(pGroup, volumeBeg, volumeEnd, fadeLengthInFrames);
72566 }
72567
72568 MA_API void ma_sound_group_set_fade_in_milliseconds(ma_sound_group* pGroup, float volumeBeg, float volumeEnd, ma_uint64 fadeLengthInMilliseconds)
72569 {
72570     ma_sound_set_fade_in_milliseconds(pGroup, volumeBeg, volumeEnd, fadeLengthInMilliseconds);
72571 }
72572
72573 MA_API float ma_sound_group_get_current_fade_volume(ma_sound_group* pGroup)
72574 {
72575     return ma_sound_get_current_fade_volume(pGroup);
72576 }
72577
72578 MA_API void ma_sound_group_set_start_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames)
72579 {
72580     ma_sound_set_start_time_in_pcm_frames(pGroup, absoluteGlobalTimeInFrames);
72581 }
72582
72583 MA_API void ma_sound_group_set_start_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds)
72584 {
72585     ma_sound_set_start_time_in_milliseconds(pGroup, absoluteGlobalTimeInMilliseconds);
72586 }
72587
72588 MA_API void ma_sound_group_set_stop_time_in_pcm_frames(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInFrames)
72589 {
72590     ma_sound_set_stop_time_in_pcm_frames(pGroup, absoluteGlobalTimeInFrames);
72591 }
72592
72593 MA_API void ma_sound_group_set_stop_time_in_milliseconds(ma_sound_group* pGroup, ma_uint64 absoluteGlobalTimeInMilliseconds)
72594 {
72595     ma_sound_set_stop_time_in_milliseconds(pGroup, absoluteGlobalTimeInMilliseconds);
72596 }
72597
72598 MA_API ma_bool32 ma_sound_group_is_playing(const ma_sound_group* pGroup)
72599 {
72600     return ma_sound_is_playing(pGroup);
72601 }
72602
72603 MA_API ma_uint64 ma_sound_group_get_time_in_pcm_frames(const ma_sound_group* pGroup)
72604 {
72605     return ma_sound_get_time_in_pcm_frames(pGroup);
72606 }
72607 #endif  /* MA_NO_ENGINE */
72608
72609
72610
72611 /**************************************************************************************************************************************************************
72612 ***************************************************************************************************************************************************************
72613
72614 Auto Generated
72615 ==============
72616 All code below is auto-generated from a tool. This mostly consists of decoding backend implementations such as dr_wav, dr_flac, etc. If you find a bug in the
72617 code below please report the bug to the respective repository for the relevant project (probably dr_libs).
72618
72619 ***************************************************************************************************************************************************************
72620 **************************************************************************************************************************************************************/
72621 #if !defined(MA_NO_WAV) && (!defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING))
72622 #if !defined(DR_WAV_IMPLEMENTATION) && !defined(DRWAV_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */
72623 /* dr_wav_c begin */
72624 #ifndef dr_wav_c
72625 #define dr_wav_c
72626 #include <stdlib.h>
72627 #include <string.h>
72628 #include <limits.h>
72629 #ifndef DR_WAV_NO_STDIO
72630 #include <stdio.h>
72631 #include <wchar.h>
72632 #endif
72633 #ifndef DRWAV_ASSERT
72634 #include <assert.h>
72635 #define DRWAV_ASSERT(expression)           assert(expression)
72636 #endif
72637 #ifndef DRWAV_MALLOC
72638 #define DRWAV_MALLOC(sz)                   malloc((sz))
72639 #endif
72640 #ifndef DRWAV_REALLOC
72641 #define DRWAV_REALLOC(p, sz)               realloc((p), (sz))
72642 #endif
72643 #ifndef DRWAV_FREE
72644 #define DRWAV_FREE(p)                      free((p))
72645 #endif
72646 #ifndef DRWAV_COPY_MEMORY
72647 #define DRWAV_COPY_MEMORY(dst, src, sz)    memcpy((dst), (src), (sz))
72648 #endif
72649 #ifndef DRWAV_ZERO_MEMORY
72650 #define DRWAV_ZERO_MEMORY(p, sz)           memset((p), 0, (sz))
72651 #endif
72652 #ifndef DRWAV_ZERO_OBJECT
72653 #define DRWAV_ZERO_OBJECT(p)               DRWAV_ZERO_MEMORY((p), sizeof(*p))
72654 #endif
72655 #define drwav_countof(x)                   (sizeof(x) / sizeof(x[0]))
72656 #define drwav_align(x, a)                  ((((x) + (a) - 1) / (a)) * (a))
72657 #define drwav_min(a, b)                    (((a) < (b)) ? (a) : (b))
72658 #define drwav_max(a, b)                    (((a) > (b)) ? (a) : (b))
72659 #define drwav_clamp(x, lo, hi)             (drwav_max((lo), drwav_min((hi), (x))))
72660 #define drwav_offset_ptr(p, offset)        (((drwav_uint8*)(p)) + (offset))
72661 #define DRWAV_MAX_SIMD_VECTOR_SIZE         64
72662 #if defined(__x86_64__) || defined(_M_X64)
72663     #define DRWAV_X64
72664 #elif defined(__i386) || defined(_M_IX86)
72665     #define DRWAV_X86
72666 #elif defined(__arm__) || defined(_M_ARM)
72667     #define DRWAV_ARM
72668 #endif
72669 #ifdef _MSC_VER
72670     #define DRWAV_INLINE __forceinline
72671 #elif defined(__GNUC__)
72672     #if defined(__STRICT_ANSI__)
72673         #define DRWAV_INLINE __inline__ __attribute__((always_inline))
72674     #else
72675         #define DRWAV_INLINE inline __attribute__((always_inline))
72676     #endif
72677 #elif defined(__WATCOMC__)
72678     #define DRWAV_INLINE __inline
72679 #else
72680     #define DRWAV_INLINE
72681 #endif
72682 #if defined(SIZE_MAX)
72683     #define DRWAV_SIZE_MAX  SIZE_MAX
72684 #else
72685     #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
72686         #define DRWAV_SIZE_MAX  ((drwav_uint64)0xFFFFFFFFFFFFFFFF)
72687     #else
72688         #define DRWAV_SIZE_MAX  0xFFFFFFFF
72689     #endif
72690 #endif
72691 #if defined(_MSC_VER) && _MSC_VER >= 1400
72692     #define DRWAV_HAS_BYTESWAP16_INTRINSIC
72693     #define DRWAV_HAS_BYTESWAP32_INTRINSIC
72694     #define DRWAV_HAS_BYTESWAP64_INTRINSIC
72695 #elif defined(__clang__)
72696     #if defined(__has_builtin)
72697         #if __has_builtin(__builtin_bswap16)
72698             #define DRWAV_HAS_BYTESWAP16_INTRINSIC
72699         #endif
72700         #if __has_builtin(__builtin_bswap32)
72701             #define DRWAV_HAS_BYTESWAP32_INTRINSIC
72702         #endif
72703         #if __has_builtin(__builtin_bswap64)
72704             #define DRWAV_HAS_BYTESWAP64_INTRINSIC
72705         #endif
72706     #endif
72707 #elif defined(__GNUC__)
72708     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
72709         #define DRWAV_HAS_BYTESWAP32_INTRINSIC
72710         #define DRWAV_HAS_BYTESWAP64_INTRINSIC
72711     #endif
72712     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
72713         #define DRWAV_HAS_BYTESWAP16_INTRINSIC
72714     #endif
72715 #endif
72716 DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision)
72717 {
72718     if (pMajor) {
72719         *pMajor = DRWAV_VERSION_MAJOR;
72720     }
72721     if (pMinor) {
72722         *pMinor = DRWAV_VERSION_MINOR;
72723     }
72724     if (pRevision) {
72725         *pRevision = DRWAV_VERSION_REVISION;
72726     }
72727 }
72728 DRWAV_API const char* drwav_version_string(void)
72729 {
72730     return DRWAV_VERSION_STRING;
72731 }
72732 #ifndef DRWAV_MAX_SAMPLE_RATE
72733 #define DRWAV_MAX_SAMPLE_RATE       384000
72734 #endif
72735 #ifndef DRWAV_MAX_CHANNELS
72736 #define DRWAV_MAX_CHANNELS          256
72737 #endif
72738 #ifndef DRWAV_MAX_BITS_PER_SAMPLE
72739 #define DRWAV_MAX_BITS_PER_SAMPLE   64
72740 #endif
72741 static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00};
72742 static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};
72743 static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};
72744 static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};
72745 static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};
72746 static DRWAV_INLINE int drwav__is_little_endian(void)
72747 {
72748 #if defined(DRWAV_X86) || defined(DRWAV_X64)
72749     return DRWAV_TRUE;
72750 #elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
72751     return DRWAV_TRUE;
72752 #else
72753     int n = 1;
72754     return (*(char*)&n) == 1;
72755 #endif
72756 }
72757 static DRWAV_INLINE void drwav_bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid)
72758 {
72759     int i;
72760     for (i = 0; i < 16; ++i) {
72761         guid[i] = data[i];
72762     }
72763 }
72764 static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n)
72765 {
72766 #ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC
72767     #if defined(_MSC_VER)
72768         return _byteswap_ushort(n);
72769     #elif defined(__GNUC__) || defined(__clang__)
72770         return __builtin_bswap16(n);
72771     #else
72772         #error "This compiler does not support the byte swap intrinsic."
72773     #endif
72774 #else
72775     return ((n & 0xFF00) >> 8) |
72776            ((n & 0x00FF) << 8);
72777 #endif
72778 }
72779 static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n)
72780 {
72781 #ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC
72782     #if defined(_MSC_VER)
72783         return _byteswap_ulong(n);
72784     #elif defined(__GNUC__) || defined(__clang__)
72785         #if defined(DRWAV_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRWAV_64BIT)
72786             drwav_uint32 r;
72787             __asm__ __volatile__ (
72788             #if defined(DRWAV_64BIT)
72789                 "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n)
72790             #else
72791                 "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
72792             #endif
72793             );
72794             return r;
72795         #else
72796             return __builtin_bswap32(n);
72797         #endif
72798     #else
72799         #error "This compiler does not support the byte swap intrinsic."
72800     #endif
72801 #else
72802     return ((n & 0xFF000000) >> 24) |
72803            ((n & 0x00FF0000) >>  8) |
72804            ((n & 0x0000FF00) <<  8) |
72805            ((n & 0x000000FF) << 24);
72806 #endif
72807 }
72808 static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n)
72809 {
72810 #ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC
72811     #if defined(_MSC_VER)
72812         return _byteswap_uint64(n);
72813     #elif defined(__GNUC__) || defined(__clang__)
72814         return __builtin_bswap64(n);
72815     #else
72816         #error "This compiler does not support the byte swap intrinsic."
72817     #endif
72818 #else
72819     return ((n & ((drwav_uint64)0xFF000000 << 32)) >> 56) |
72820            ((n & ((drwav_uint64)0x00FF0000 << 32)) >> 40) |
72821            ((n & ((drwav_uint64)0x0000FF00 << 32)) >> 24) |
72822            ((n & ((drwav_uint64)0x000000FF << 32)) >>  8) |
72823            ((n & ((drwav_uint64)0xFF000000      )) <<  8) |
72824            ((n & ((drwav_uint64)0x00FF0000      )) << 24) |
72825            ((n & ((drwav_uint64)0x0000FF00      )) << 40) |
72826            ((n & ((drwav_uint64)0x000000FF      )) << 56);
72827 #endif
72828 }
72829 static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n)
72830 {
72831     return (drwav_int16)drwav__bswap16((drwav_uint16)n);
72832 }
72833 static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount)
72834 {
72835     drwav_uint64 iSample;
72836     for (iSample = 0; iSample < sampleCount; iSample += 1) {
72837         pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]);
72838     }
72839 }
72840 static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p)
72841 {
72842     drwav_uint8 t;
72843     t = p[0];
72844     p[0] = p[2];
72845     p[2] = t;
72846 }
72847 static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount)
72848 {
72849     drwav_uint64 iSample;
72850     for (iSample = 0; iSample < sampleCount; iSample += 1) {
72851         drwav_uint8* pSample = pSamples + (iSample*3);
72852         drwav__bswap_s24(pSample);
72853     }
72854 }
72855 static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n)
72856 {
72857     return (drwav_int32)drwav__bswap32((drwav_uint32)n);
72858 }
72859 static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount)
72860 {
72861     drwav_uint64 iSample;
72862     for (iSample = 0; iSample < sampleCount; iSample += 1) {
72863         pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]);
72864     }
72865 }
72866 static DRWAV_INLINE float drwav__bswap_f32(float n)
72867 {
72868     union {
72869         drwav_uint32 i;
72870         float f;
72871     } x;
72872     x.f = n;
72873     x.i = drwav__bswap32(x.i);
72874     return x.f;
72875 }
72876 static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount)
72877 {
72878     drwav_uint64 iSample;
72879     for (iSample = 0; iSample < sampleCount; iSample += 1) {
72880         pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]);
72881     }
72882 }
72883 static DRWAV_INLINE double drwav__bswap_f64(double n)
72884 {
72885     union {
72886         drwav_uint64 i;
72887         double f;
72888     } x;
72889     x.f = n;
72890     x.i = drwav__bswap64(x.i);
72891     return x.f;
72892 }
72893 static DRWAV_INLINE void drwav__bswap_samples_f64(double* pSamples, drwav_uint64 sampleCount)
72894 {
72895     drwav_uint64 iSample;
72896     for (iSample = 0; iSample < sampleCount; iSample += 1) {
72897         pSamples[iSample] = drwav__bswap_f64(pSamples[iSample]);
72898     }
72899 }
72900 static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
72901 {
72902     switch (bytesPerSample)
72903     {
72904         case 1:
72905         {
72906         } break;
72907         case 2:
72908         {
72909             drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
72910         } break;
72911         case 3:
72912         {
72913             drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount);
72914         } break;
72915         case 4:
72916         {
72917             drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount);
72918         } break;
72919         default:
72920         {
72921             DRWAV_ASSERT(DRWAV_FALSE);
72922         } break;
72923     }
72924 }
72925 static DRWAV_INLINE void drwav__bswap_samples_ieee(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
72926 {
72927     switch (bytesPerSample)
72928     {
72929     #if 0
72930         case 2:
72931         {
72932             drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount);
72933         } break;
72934     #endif
72935         case 4:
72936         {
72937             drwav__bswap_samples_f32((float*)pSamples, sampleCount);
72938         } break;
72939         case 8:
72940         {
72941             drwav__bswap_samples_f64((double*)pSamples, sampleCount);
72942         } break;
72943         default:
72944         {
72945             DRWAV_ASSERT(DRWAV_FALSE);
72946         } break;
72947     }
72948 }
72949 static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format)
72950 {
72951     switch (format)
72952     {
72953         case DR_WAVE_FORMAT_PCM:
72954         {
72955             drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample);
72956         } break;
72957         case DR_WAVE_FORMAT_IEEE_FLOAT:
72958         {
72959             drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample);
72960         } break;
72961         case DR_WAVE_FORMAT_ALAW:
72962         case DR_WAVE_FORMAT_MULAW:
72963         {
72964             drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
72965         } break;
72966         case DR_WAVE_FORMAT_ADPCM:
72967         case DR_WAVE_FORMAT_DVI_ADPCM:
72968         default:
72969         {
72970             DRWAV_ASSERT(DRWAV_FALSE);
72971         } break;
72972     }
72973 }
72974 DRWAV_PRIVATE void* drwav__malloc_default(size_t sz, void* pUserData)
72975 {
72976     (void)pUserData;
72977     return DRWAV_MALLOC(sz);
72978 }
72979 DRWAV_PRIVATE void* drwav__realloc_default(void* p, size_t sz, void* pUserData)
72980 {
72981     (void)pUserData;
72982     return DRWAV_REALLOC(p, sz);
72983 }
72984 DRWAV_PRIVATE void drwav__free_default(void* p, void* pUserData)
72985 {
72986     (void)pUserData;
72987     DRWAV_FREE(p);
72988 }
72989 DRWAV_PRIVATE void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks)
72990 {
72991     if (pAllocationCallbacks == NULL) {
72992         return NULL;
72993     }
72994     if (pAllocationCallbacks->onMalloc != NULL) {
72995         return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
72996     }
72997     if (pAllocationCallbacks->onRealloc != NULL) {
72998         return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
72999     }
73000     return NULL;
73001 }
73002 DRWAV_PRIVATE void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks)
73003 {
73004     if (pAllocationCallbacks == NULL) {
73005         return NULL;
73006     }
73007     if (pAllocationCallbacks->onRealloc != NULL) {
73008         return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
73009     }
73010     if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
73011         void* p2;
73012         p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
73013         if (p2 == NULL) {
73014             return NULL;
73015         }
73016         if (p != NULL) {
73017             DRWAV_COPY_MEMORY(p2, p, szOld);
73018             pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
73019         }
73020         return p2;
73021     }
73022     return NULL;
73023 }
73024 DRWAV_PRIVATE void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
73025 {
73026     if (p == NULL || pAllocationCallbacks == NULL) {
73027         return;
73028     }
73029     if (pAllocationCallbacks->onFree != NULL) {
73030         pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
73031     }
73032 }
73033 DRWAV_PRIVATE drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks)
73034 {
73035     if (pAllocationCallbacks != NULL) {
73036         return *pAllocationCallbacks;
73037     } else {
73038         drwav_allocation_callbacks allocationCallbacks;
73039         allocationCallbacks.pUserData = NULL;
73040         allocationCallbacks.onMalloc  = drwav__malloc_default;
73041         allocationCallbacks.onRealloc = drwav__realloc_default;
73042         allocationCallbacks.onFree    = drwav__free_default;
73043         return allocationCallbacks;
73044     }
73045 }
73046 static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag)
73047 {
73048     return
73049         formatTag == DR_WAVE_FORMAT_ADPCM ||
73050         formatTag == DR_WAVE_FORMAT_DVI_ADPCM;
73051 }
73052 DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize)
73053 {
73054     return (unsigned int)(chunkSize % 2);
73055 }
73056 DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize)
73057 {
73058     return (unsigned int)(chunkSize % 8);
73059 }
73060 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
73061 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
73062 DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
73063 DRWAV_PRIVATE drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut)
73064 {
73065     if (container == drwav_container_riff || container == drwav_container_rf64) {
73066         drwav_uint8 sizeInBytes[4];
73067         if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
73068             return DRWAV_AT_END;
73069         }
73070         if (onRead(pUserData, sizeInBytes, 4) != 4) {
73071             return DRWAV_INVALID_FILE;
73072         }
73073         pHeaderOut->sizeInBytes = drwav_bytes_to_u32(sizeInBytes);
73074         pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes);
73075         *pRunningBytesReadOut += 8;
73076     } else {
73077         drwav_uint8 sizeInBytes[8];
73078         if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
73079             return DRWAV_AT_END;
73080         }
73081         if (onRead(pUserData, sizeInBytes, 8) != 8) {
73082             return DRWAV_INVALID_FILE;
73083         }
73084         pHeaderOut->sizeInBytes = drwav_bytes_to_u64(sizeInBytes) - 24;
73085         pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes);
73086         *pRunningBytesReadOut += 24;
73087     }
73088     return DRWAV_SUCCESS;
73089 }
73090 DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
73091 {
73092     drwav_uint64 bytesRemainingToSeek = offset;
73093     while (bytesRemainingToSeek > 0) {
73094         if (bytesRemainingToSeek > 0x7FFFFFFF) {
73095             if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
73096                 return DRWAV_FALSE;
73097             }
73098             bytesRemainingToSeek -= 0x7FFFFFFF;
73099         } else {
73100             if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
73101                 return DRWAV_FALSE;
73102             }
73103             bytesRemainingToSeek = 0;
73104         }
73105     }
73106     return DRWAV_TRUE;
73107 }
73108 DRWAV_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
73109 {
73110     if (offset <= 0x7FFFFFFF) {
73111         return onSeek(pUserData, (int)offset, drwav_seek_origin_start);
73112     }
73113     if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) {
73114         return DRWAV_FALSE;
73115     }
73116     offset -= 0x7FFFFFFF;
73117     for (;;) {
73118         if (offset <= 0x7FFFFFFF) {
73119             return onSeek(pUserData, (int)offset, drwav_seek_origin_current);
73120         }
73121         if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
73122             return DRWAV_FALSE;
73123         }
73124         offset -= 0x7FFFFFFF;
73125     }
73126 }
73127 DRWAV_PRIVATE drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut)
73128 {
73129     drwav_chunk_header header;
73130     drwav_uint8 fmt[16];
73131     if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
73132         return DRWAV_FALSE;
73133     }
73134     while (((container == drwav_container_riff || container == drwav_container_rf64) && !drwav_fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
73135         if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) {
73136             return DRWAV_FALSE;
73137         }
73138         *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize;
73139         if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
73140             return DRWAV_FALSE;
73141         }
73142     }
73143     if (container == drwav_container_riff || container == drwav_container_rf64) {
73144         if (!drwav_fourcc_equal(header.id.fourcc, "fmt ")) {
73145             return DRWAV_FALSE;
73146         }
73147     } else {
73148         if (!drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT)) {
73149             return DRWAV_FALSE;
73150         }
73151     }
73152     if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) {
73153         return DRWAV_FALSE;
73154     }
73155     *pRunningBytesReadOut += sizeof(fmt);
73156     fmtOut->formatTag      = drwav_bytes_to_u16(fmt + 0);
73157     fmtOut->channels       = drwav_bytes_to_u16(fmt + 2);
73158     fmtOut->sampleRate     = drwav_bytes_to_u32(fmt + 4);
73159     fmtOut->avgBytesPerSec = drwav_bytes_to_u32(fmt + 8);
73160     fmtOut->blockAlign     = drwav_bytes_to_u16(fmt + 12);
73161     fmtOut->bitsPerSample  = drwav_bytes_to_u16(fmt + 14);
73162     fmtOut->extendedSize       = 0;
73163     fmtOut->validBitsPerSample = 0;
73164     fmtOut->channelMask        = 0;
73165     memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat));
73166     if (header.sizeInBytes > 16) {
73167         drwav_uint8 fmt_cbSize[2];
73168         int bytesReadSoFar = 0;
73169         if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) {
73170             return DRWAV_FALSE;
73171         }
73172         *pRunningBytesReadOut += sizeof(fmt_cbSize);
73173         bytesReadSoFar = 18;
73174         fmtOut->extendedSize = drwav_bytes_to_u16(fmt_cbSize);
73175         if (fmtOut->extendedSize > 0) {
73176             if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
73177                 if (fmtOut->extendedSize != 22) {
73178                     return DRWAV_FALSE;
73179                 }
73180             }
73181             if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
73182                 drwav_uint8 fmtext[22];
73183                 if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) {
73184                     return DRWAV_FALSE;
73185                 }
73186                 fmtOut->validBitsPerSample = drwav_bytes_to_u16(fmtext + 0);
73187                 fmtOut->channelMask        = drwav_bytes_to_u32(fmtext + 2);
73188                 drwav_bytes_to_guid(fmtext + 6, fmtOut->subFormat);
73189             } else {
73190                 if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) {
73191                     return DRWAV_FALSE;
73192                 }
73193             }
73194             *pRunningBytesReadOut += fmtOut->extendedSize;
73195             bytesReadSoFar += fmtOut->extendedSize;
73196         }
73197         if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) {
73198             return DRWAV_FALSE;
73199         }
73200         *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar);
73201     }
73202     if (header.paddingSize > 0) {
73203         if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) {
73204             return DRWAV_FALSE;
73205         }
73206         *pRunningBytesReadOut += header.paddingSize;
73207     }
73208     return DRWAV_TRUE;
73209 }
73210 DRWAV_PRIVATE size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
73211 {
73212     size_t bytesRead;
73213     DRWAV_ASSERT(onRead != NULL);
73214     DRWAV_ASSERT(pCursor != NULL);
73215     bytesRead = onRead(pUserData, pBufferOut, bytesToRead);
73216     *pCursor += bytesRead;
73217     return bytesRead;
73218 }
73219 #if 0
73220 DRWAV_PRIVATE drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor)
73221 {
73222     DRWAV_ASSERT(onSeek != NULL);
73223     DRWAV_ASSERT(pCursor != NULL);
73224     if (!onSeek(pUserData, offset, origin)) {
73225         return DRWAV_FALSE;
73226     }
73227     if (origin == drwav_seek_origin_start) {
73228         *pCursor = offset;
73229     } else {
73230         *pCursor += offset;
73231     }
73232     return DRWAV_TRUE;
73233 }
73234 #endif
73235 #define DRWAV_SMPL_BYTES                    36
73236 #define DRWAV_SMPL_LOOP_BYTES               24
73237 #define DRWAV_INST_BYTES                    7
73238 #define DRWAV_ACID_BYTES                    24
73239 #define DRWAV_CUE_BYTES                     4
73240 #define DRWAV_BEXT_BYTES                    602
73241 #define DRWAV_BEXT_DESCRIPTION_BYTES        256
73242 #define DRWAV_BEXT_ORIGINATOR_NAME_BYTES    32
73243 #define DRWAV_BEXT_ORIGINATOR_REF_BYTES     32
73244 #define DRWAV_BEXT_RESERVED_BYTES           180
73245 #define DRWAV_BEXT_UMID_BYTES               64
73246 #define DRWAV_CUE_POINT_BYTES               24
73247 #define DRWAV_LIST_LABEL_OR_NOTE_BYTES      4
73248 #define DRWAV_LIST_LABELLED_TEXT_BYTES      20
73249 #define DRWAV_METADATA_ALIGNMENT            8
73250 typedef enum
73251 {
73252     drwav__metadata_parser_stage_count,
73253     drwav__metadata_parser_stage_read
73254 } drwav__metadata_parser_stage;
73255 typedef struct
73256 {
73257     drwav_read_proc onRead;
73258     drwav_seek_proc onSeek;
73259     void *pReadSeekUserData;
73260     drwav__metadata_parser_stage stage;
73261     drwav_metadata *pMetadata;
73262     drwav_uint32 metadataCount;
73263     drwav_uint8 *pData;
73264     drwav_uint8 *pDataCursor;
73265     drwav_uint64 metadataCursor;
73266     drwav_uint64 extraCapacity;
73267 } drwav__metadata_parser;
73268 DRWAV_PRIVATE size_t drwav__metadata_memory_capacity(drwav__metadata_parser* pParser)
73269 {
73270     drwav_uint64 cap = sizeof(drwav_metadata) * (drwav_uint64)pParser->metadataCount + pParser->extraCapacity;
73271     if (cap > DRWAV_SIZE_MAX) {
73272         return 0;
73273     }
73274     return (size_t)cap;
73275 }
73276 DRWAV_PRIVATE drwav_uint8* drwav__metadata_get_memory(drwav__metadata_parser* pParser, size_t size, size_t align)
73277 {
73278     drwav_uint8* pResult;
73279     if (align) {
73280         drwav_uintptr modulo = (drwav_uintptr)pParser->pDataCursor % align;
73281         if (modulo != 0) {
73282             pParser->pDataCursor += align - modulo;
73283         }
73284     }
73285     pResult = pParser->pDataCursor;
73286     DRWAV_ASSERT((pResult + size) <= (pParser->pData + drwav__metadata_memory_capacity(pParser)));
73287     pParser->pDataCursor += size;
73288     return pResult;
73289 }
73290 DRWAV_PRIVATE void drwav__metadata_request_extra_memory_for_stage_2(drwav__metadata_parser* pParser, size_t bytes, size_t align)
73291 {
73292     size_t extra = bytes + (align ? (align - 1) : 0);
73293     pParser->extraCapacity += extra;
73294 }
73295 DRWAV_PRIVATE drwav_result drwav__metadata_alloc(drwav__metadata_parser* pParser, drwav_allocation_callbacks* pAllocationCallbacks)
73296 {
73297     if (pParser->extraCapacity != 0 || pParser->metadataCount != 0) {
73298         free(pParser->pData);
73299         pParser->pData = (drwav_uint8*)pAllocationCallbacks->onMalloc(drwav__metadata_memory_capacity(pParser), pAllocationCallbacks->pUserData);
73300         pParser->pDataCursor = pParser->pData;
73301         if (pParser->pData == NULL) {
73302             return DRWAV_OUT_OF_MEMORY;
73303         }
73304         pParser->pMetadata = (drwav_metadata*)drwav__metadata_get_memory(pParser, sizeof(drwav_metadata) * pParser->metadataCount, 1);
73305         pParser->metadataCursor = 0;
73306     }
73307     return DRWAV_SUCCESS;
73308 }
73309 DRWAV_PRIVATE size_t drwav__metadata_parser_read(drwav__metadata_parser* pParser, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
73310 {
73311     if (pCursor != NULL) {
73312         return drwav__on_read(pParser->onRead, pParser->pReadSeekUserData, pBufferOut, bytesToRead, pCursor);
73313     } else {
73314         return pParser->onRead(pParser->pReadSeekUserData, pBufferOut, bytesToRead);
73315     }
73316 }
73317 DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata)
73318 {
73319     drwav_uint8 smplHeaderData[DRWAV_SMPL_BYTES];
73320     drwav_uint64 totalBytesRead = 0;
73321     size_t bytesJustRead = drwav__metadata_parser_read(pParser, smplHeaderData, sizeof(smplHeaderData), &totalBytesRead);
73322     DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
73323     DRWAV_ASSERT(pChunkHeader != NULL);
73324     if (bytesJustRead == sizeof(smplHeaderData)) {
73325         drwav_uint32 iSampleLoop;
73326         pMetadata->type                                     = drwav_metadata_type_smpl;
73327         pMetadata->data.smpl.manufacturerId                 = drwav_bytes_to_u32(smplHeaderData + 0);
73328         pMetadata->data.smpl.productId                      = drwav_bytes_to_u32(smplHeaderData + 4);
73329         pMetadata->data.smpl.samplePeriodNanoseconds        = drwav_bytes_to_u32(smplHeaderData + 8);
73330         pMetadata->data.smpl.midiUnityNote                  = drwav_bytes_to_u32(smplHeaderData + 12);
73331         pMetadata->data.smpl.midiPitchFraction              = drwav_bytes_to_u32(smplHeaderData + 16);
73332         pMetadata->data.smpl.smpteFormat                    = drwav_bytes_to_u32(smplHeaderData + 20);
73333         pMetadata->data.smpl.smpteOffset                    = drwav_bytes_to_u32(smplHeaderData + 24);
73334         pMetadata->data.smpl.sampleLoopCount                = drwav_bytes_to_u32(smplHeaderData + 28);
73335         pMetadata->data.smpl.samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(smplHeaderData + 32);
73336         if (pMetadata->data.smpl.sampleLoopCount == (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES) {
73337             pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT);
73338             for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) {
73339                 drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES];
73340                 bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead);
73341                 if (bytesJustRead == sizeof(smplLoopData)) {
73342                     pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId            = drwav_bytes_to_u32(smplLoopData + 0);
73343                     pMetadata->data.smpl.pLoops[iSampleLoop].type                  = drwav_bytes_to_u32(smplLoopData + 4);
73344                     pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8);
73345                     pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset  = drwav_bytes_to_u32(smplLoopData + 12);
73346                     pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction        = drwav_bytes_to_u32(smplLoopData + 16);
73347                     pMetadata->data.smpl.pLoops[iSampleLoop].playCount             = drwav_bytes_to_u32(smplLoopData + 20);
73348                 } else {
73349                     break;
73350                 }
73351             }
73352             if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) {
73353                 pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1);
73354                 DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL);
73355                 drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead);
73356             }
73357         }
73358     }
73359     return totalBytesRead;
73360 }
73361 DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata)
73362 {
73363     drwav_uint8 cueHeaderSectionData[DRWAV_CUE_BYTES];
73364     drwav_uint64 totalBytesRead = 0;
73365     size_t bytesJustRead = drwav__metadata_parser_read(pParser, cueHeaderSectionData, sizeof(cueHeaderSectionData), &totalBytesRead);
73366     DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
73367     if (bytesJustRead == sizeof(cueHeaderSectionData)) {
73368         pMetadata->type                   = drwav_metadata_type_cue;
73369         pMetadata->data.cue.cuePointCount = drwav_bytes_to_u32(cueHeaderSectionData);
73370         if (pMetadata->data.cue.cuePointCount == (pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES) {
73371             pMetadata->data.cue.pCuePoints    = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT);
73372             DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL);
73373             if (pMetadata->data.cue.cuePointCount > 0) {
73374                 drwav_uint32 iCuePoint;
73375                 for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) {
73376                     drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES];
73377                     bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead);
73378                     if (bytesJustRead == sizeof(cuePointData)) {
73379                         pMetadata->data.cue.pCuePoints[iCuePoint].id                = drwav_bytes_to_u32(cuePointData + 0);
73380                         pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4);
73381                         pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0]    = cuePointData[8];
73382                         pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1]    = cuePointData[9];
73383                         pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2]    = cuePointData[10];
73384                         pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3]    = cuePointData[11];
73385                         pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart        = drwav_bytes_to_u32(cuePointData + 12);
73386                         pMetadata->data.cue.pCuePoints[iCuePoint].blockStart        = drwav_bytes_to_u32(cuePointData + 16);
73387                         pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset  = drwav_bytes_to_u32(cuePointData + 20);
73388                     } else {
73389                         break;
73390                     }
73391                 }
73392             }
73393         }
73394     }
73395     return totalBytesRead;
73396 }
73397 DRWAV_PRIVATE drwav_uint64 drwav__read_inst_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata)
73398 {
73399     drwav_uint8 instData[DRWAV_INST_BYTES];
73400     drwav_uint64 bytesRead = drwav__metadata_parser_read(pParser, instData, sizeof(instData), NULL);
73401     DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
73402     if (bytesRead == sizeof(instData)) {
73403         pMetadata->type                    = drwav_metadata_type_inst;
73404         pMetadata->data.inst.midiUnityNote = (drwav_int8)instData[0];
73405         pMetadata->data.inst.fineTuneCents = (drwav_int8)instData[1];
73406         pMetadata->data.inst.gainDecibels  = (drwav_int8)instData[2];
73407         pMetadata->data.inst.lowNote       = (drwav_int8)instData[3];
73408         pMetadata->data.inst.highNote      = (drwav_int8)instData[4];
73409         pMetadata->data.inst.lowVelocity   = (drwav_int8)instData[5];
73410         pMetadata->data.inst.highVelocity  = (drwav_int8)instData[6];
73411     }
73412     return bytesRead;
73413 }
73414 DRWAV_PRIVATE drwav_uint64 drwav__read_acid_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata)
73415 {
73416     drwav_uint8 acidData[DRWAV_ACID_BYTES];
73417     drwav_uint64 bytesRead = drwav__metadata_parser_read(pParser, acidData, sizeof(acidData), NULL);
73418     DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
73419     if (bytesRead == sizeof(acidData)) {
73420         pMetadata->type                       = drwav_metadata_type_acid;
73421         pMetadata->data.acid.flags            = drwav_bytes_to_u32(acidData + 0);
73422         pMetadata->data.acid.midiUnityNote    = drwav_bytes_to_u16(acidData + 4);
73423         pMetadata->data.acid.reserved1        = drwav_bytes_to_u16(acidData + 6);
73424         pMetadata->data.acid.reserved2        = drwav_bytes_to_f32(acidData + 8);
73425         pMetadata->data.acid.numBeats         = drwav_bytes_to_u32(acidData + 12);
73426         pMetadata->data.acid.meterDenominator = drwav_bytes_to_u16(acidData + 16);
73427         pMetadata->data.acid.meterNumerator   = drwav_bytes_to_u16(acidData + 18);
73428         pMetadata->data.acid.tempo            = drwav_bytes_to_f32(acidData + 20);
73429     }
73430     return bytesRead;
73431 }
73432 DRWAV_PRIVATE size_t drwav__strlen_clamped(const char* str, size_t maxToRead)
73433 {
73434     size_t result = 0;
73435     while (*str++ && result < maxToRead) {
73436         result += 1;
73437     }
73438     return result;
73439 }
73440 DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, const char* str, size_t maxToRead)
73441 {
73442     size_t len = drwav__strlen_clamped(str, maxToRead);
73443     if (len) {
73444         char* result = (char*)drwav__metadata_get_memory(pParser, len + 1, 1);
73445         DRWAV_ASSERT(result != NULL);
73446         memcpy(result, str, len);
73447         result[len] = '\0';
73448         return result;
73449     } else {
73450         return NULL;
73451     }
73452 }
73453 typedef struct
73454 {
73455     const void* pBuffer;
73456     size_t sizeInBytes;
73457     size_t cursor;
73458 } drwav_buffer_reader;
73459 DRWAV_PRIVATE drwav_result drwav_buffer_reader_init(const void* pBuffer, size_t sizeInBytes, drwav_buffer_reader* pReader)
73460 {
73461     DRWAV_ASSERT(pBuffer != NULL);
73462     DRWAV_ASSERT(pReader != NULL);
73463     DRWAV_ZERO_OBJECT(pReader);
73464     pReader->pBuffer     = pBuffer;
73465     pReader->sizeInBytes = sizeInBytes;
73466     pReader->cursor      = 0;
73467     return DRWAV_SUCCESS;
73468 }
73469 DRWAV_PRIVATE const void* drwav_buffer_reader_ptr(const drwav_buffer_reader* pReader)
73470 {
73471     DRWAV_ASSERT(pReader != NULL);
73472     return drwav_offset_ptr(pReader->pBuffer, pReader->cursor);
73473 }
73474 DRWAV_PRIVATE drwav_result drwav_buffer_reader_seek(drwav_buffer_reader* pReader, size_t bytesToSeek)
73475 {
73476     DRWAV_ASSERT(pReader != NULL);
73477     if (pReader->cursor + bytesToSeek > pReader->sizeInBytes) {
73478         return DRWAV_BAD_SEEK;
73479     }
73480     pReader->cursor += bytesToSeek;
73481     return DRWAV_SUCCESS;
73482 }
73483 DRWAV_PRIVATE drwav_result drwav_buffer_reader_read(drwav_buffer_reader* pReader, void* pDst, size_t bytesToRead, size_t* pBytesRead)
73484 {
73485     drwav_result result = DRWAV_SUCCESS;
73486     size_t bytesRemaining;
73487     DRWAV_ASSERT(pReader != NULL);
73488     if (pBytesRead != NULL) {
73489         *pBytesRead = 0;
73490     }
73491     bytesRemaining = (pReader->sizeInBytes - pReader->cursor);
73492     if (bytesToRead > bytesRemaining) {
73493         bytesToRead = bytesRemaining;
73494     }
73495     if (pDst == NULL) {
73496         result = drwav_buffer_reader_seek(pReader, bytesToRead);
73497     } else {
73498         DRWAV_COPY_MEMORY(pDst, drwav_buffer_reader_ptr(pReader), bytesToRead);
73499         pReader->cursor += bytesToRead;
73500     }
73501     DRWAV_ASSERT(pReader->cursor <= pReader->sizeInBytes);
73502     if (result == DRWAV_SUCCESS) {
73503         if (pBytesRead != NULL) {
73504             *pBytesRead = bytesToRead;
73505         }
73506     }
73507     return DRWAV_SUCCESS;
73508 }
73509 DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u16(drwav_buffer_reader* pReader, drwav_uint16* pDst)
73510 {
73511     drwav_result result;
73512     size_t bytesRead;
73513     drwav_uint8 data[2];
73514     DRWAV_ASSERT(pReader != NULL);
73515     DRWAV_ASSERT(pDst != NULL);
73516     *pDst = 0;
73517     result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead);
73518     if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) {
73519         return result;
73520     }
73521     *pDst = drwav_bytes_to_u16(data);
73522     return DRWAV_SUCCESS;
73523 }
73524 DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u32(drwav_buffer_reader* pReader, drwav_uint32* pDst)
73525 {
73526     drwav_result result;
73527     size_t bytesRead;
73528     drwav_uint8 data[4];
73529     DRWAV_ASSERT(pReader != NULL);
73530     DRWAV_ASSERT(pDst != NULL);
73531     *pDst = 0;
73532     result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead);
73533     if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) {
73534         return result;
73535     }
73536     *pDst = drwav_bytes_to_u32(data);
73537     return DRWAV_SUCCESS;
73538 }
73539 DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize)
73540 {
73541     drwav_uint8 bextData[DRWAV_BEXT_BYTES];
73542     size_t bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL);
73543     DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
73544     if (bytesRead == sizeof(bextData)) {
73545         drwav_buffer_reader reader;
73546         drwav_uint32 timeReferenceLow;
73547         drwav_uint32 timeReferenceHigh;
73548         size_t extraBytes;
73549         pMetadata->type = drwav_metadata_type_bext;
73550         if (drwav_buffer_reader_init(bextData, bytesRead, &reader) == DRWAV_SUCCESS) {
73551             pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_DESCRIPTION_BYTES);
73552             drwav_buffer_reader_seek(&reader, DRWAV_BEXT_DESCRIPTION_BYTES);
73553             pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_NAME_BYTES);
73554             drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_NAME_BYTES);
73555             pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_REF_BYTES);
73556             drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_REF_BYTES);
73557             drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate), NULL);
73558             drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime), NULL);
73559             drwav_buffer_reader_read_u32(&reader, &timeReferenceLow);
73560             drwav_buffer_reader_read_u32(&reader, &timeReferenceHigh);
73561             pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow;
73562             drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.version);
73563             pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1);
73564             drwav_buffer_reader_read(&reader, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES, NULL);
73565             drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessValue);
73566             drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessRange);
73567             drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxTruePeakLevel);
73568             drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxMomentaryLoudness);
73569             drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxShortTermLoudness);
73570             DRWAV_ASSERT((drwav_offset_ptr(drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_RESERVED_BYTES)) == (bextData + DRWAV_BEXT_BYTES));
73571             extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES);
73572             if (extraBytes > 0) {
73573                 pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1);
73574                 DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL);
73575                 bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL);
73576                 pMetadata->data.bext.codingHistorySize = (drwav_uint32)strlen(pMetadata->data.bext.pCodingHistory);
73577             } else {
73578                 pMetadata->data.bext.pCodingHistory    = NULL;
73579                 pMetadata->data.bext.codingHistorySize = 0;
73580             }
73581         }
73582     }
73583     return bytesRead;
73584 }
73585 DRWAV_PRIVATE drwav_uint64 drwav__read_list_label_or_note_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize, drwav_metadata_type type)
73586 {
73587     drwav_uint8 cueIDBuffer[DRWAV_LIST_LABEL_OR_NOTE_BYTES];
73588     drwav_uint64 totalBytesRead = 0;
73589     size_t bytesJustRead = drwav__metadata_parser_read(pParser, cueIDBuffer, sizeof(cueIDBuffer), &totalBytesRead);
73590     DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
73591     if (bytesJustRead == sizeof(cueIDBuffer)) {
73592         drwav_uint32 sizeIncludingNullTerminator;
73593         pMetadata->type = type;
73594         pMetadata->data.labelOrNote.cuePointId = drwav_bytes_to_u32(cueIDBuffer);
73595         sizeIncludingNullTerminator = (drwav_uint32)chunkSize - DRWAV_LIST_LABEL_OR_NOTE_BYTES;
73596         if (sizeIncludingNullTerminator > 0) {
73597             pMetadata->data.labelOrNote.stringLength = sizeIncludingNullTerminator - 1;
73598             pMetadata->data.labelOrNote.pString      = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1);
73599             DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL);
73600             drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead);
73601         } else {
73602             pMetadata->data.labelOrNote.stringLength = 0;
73603             pMetadata->data.labelOrNote.pString      = NULL;
73604         }
73605     }
73606     return totalBytesRead;
73607 }
73608 DRWAV_PRIVATE drwav_uint64 drwav__read_list_labelled_cue_region_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize)
73609 {
73610     drwav_uint8 buffer[DRWAV_LIST_LABELLED_TEXT_BYTES];
73611     drwav_uint64 totalBytesRead = 0;
73612     size_t bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &totalBytesRead);
73613     DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
73614     if (bytesJustRead == sizeof(buffer)) {
73615         drwav_uint32 sizeIncludingNullTerminator;
73616         pMetadata->type                                = drwav_metadata_type_list_labelled_cue_region;
73617         pMetadata->data.labelledCueRegion.cuePointId   = drwav_bytes_to_u32(buffer + 0);
73618         pMetadata->data.labelledCueRegion.sampleLength = drwav_bytes_to_u32(buffer + 4);
73619         pMetadata->data.labelledCueRegion.purposeId[0] = buffer[8];
73620         pMetadata->data.labelledCueRegion.purposeId[1] = buffer[9];
73621         pMetadata->data.labelledCueRegion.purposeId[2] = buffer[10];
73622         pMetadata->data.labelledCueRegion.purposeId[3] = buffer[11];
73623         pMetadata->data.labelledCueRegion.country      = drwav_bytes_to_u16(buffer + 12);
73624         pMetadata->data.labelledCueRegion.language     = drwav_bytes_to_u16(buffer + 14);
73625         pMetadata->data.labelledCueRegion.dialect      = drwav_bytes_to_u16(buffer + 16);
73626         pMetadata->data.labelledCueRegion.codePage     = drwav_bytes_to_u16(buffer + 18);
73627         sizeIncludingNullTerminator = (drwav_uint32)chunkSize - DRWAV_LIST_LABELLED_TEXT_BYTES;
73628         if (sizeIncludingNullTerminator > 0) {
73629             pMetadata->data.labelledCueRegion.stringLength = sizeIncludingNullTerminator - 1;
73630             pMetadata->data.labelledCueRegion.pString      = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1);
73631             DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL);
73632             drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead);
73633         } else {
73634             pMetadata->data.labelledCueRegion.stringLength = 0;
73635             pMetadata->data.labelledCueRegion.pString      = NULL;
73636         }
73637     }
73638     return totalBytesRead;
73639 }
73640 DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_info_text_chunk(drwav__metadata_parser* pParser, drwav_uint64 chunkSize, drwav_metadata_type type)
73641 {
73642     drwav_uint64 bytesRead = 0;
73643     drwav_uint32 stringSizeWithNullTerminator = (drwav_uint32)chunkSize;
73644     if (pParser->stage == drwav__metadata_parser_stage_count) {
73645         pParser->metadataCount += 1;
73646         drwav__metadata_request_extra_memory_for_stage_2(pParser, stringSizeWithNullTerminator, 1);
73647     } else {
73648         drwav_metadata* pMetadata = &pParser->pMetadata[pParser->metadataCursor];
73649         pMetadata->type = type;
73650         if (stringSizeWithNullTerminator > 0) {
73651             pMetadata->data.infoText.stringLength = stringSizeWithNullTerminator - 1;
73652             pMetadata->data.infoText.pString = (char*)drwav__metadata_get_memory(pParser, stringSizeWithNullTerminator, 1);
73653             DRWAV_ASSERT(pMetadata->data.infoText.pString != NULL);
73654             bytesRead = drwav__metadata_parser_read(pParser, pMetadata->data.infoText.pString, (size_t)stringSizeWithNullTerminator, NULL);
73655             if (bytesRead == chunkSize) {
73656                 pParser->metadataCursor += 1;
73657             } else {
73658             }
73659         } else {
73660             pMetadata->data.infoText.stringLength = 0;
73661             pMetadata->data.infoText.pString      = NULL;
73662             pParser->metadataCursor += 1;
73663         }
73664     }
73665     return bytesRead;
73666 }
73667 DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_unknown_chunk(drwav__metadata_parser* pParser, const drwav_uint8* pChunkId, drwav_uint64 chunkSize, drwav_metadata_location location)
73668 {
73669     drwav_uint64 bytesRead = 0;
73670     if (location == drwav_metadata_location_invalid) {
73671         return 0;
73672     }
73673     if (drwav_fourcc_equal(pChunkId, "data") || drwav_fourcc_equal(pChunkId, "fmt") || drwav_fourcc_equal(pChunkId, "fact")) {
73674         return 0;
73675     }
73676     if (pParser->stage == drwav__metadata_parser_stage_count) {
73677         pParser->metadataCount += 1;
73678         drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)chunkSize, 1);
73679     } else {
73680         drwav_metadata* pMetadata = &pParser->pMetadata[pParser->metadataCursor];
73681         pMetadata->type                         = drwav_metadata_type_unknown;
73682         pMetadata->data.unknown.chunkLocation   = location;
73683         pMetadata->data.unknown.id[0]           = pChunkId[0];
73684         pMetadata->data.unknown.id[1]           = pChunkId[1];
73685         pMetadata->data.unknown.id[2]           = pChunkId[2];
73686         pMetadata->data.unknown.id[3]           = pChunkId[3];
73687         pMetadata->data.unknown.dataSizeInBytes = (drwav_uint32)chunkSize;
73688         pMetadata->data.unknown.pData           = (drwav_uint8 *)drwav__metadata_get_memory(pParser, (size_t)chunkSize, 1);
73689         DRWAV_ASSERT(pMetadata->data.unknown.pData != NULL);
73690         bytesRead = drwav__metadata_parser_read(pParser, pMetadata->data.unknown.pData, pMetadata->data.unknown.dataSizeInBytes, NULL);
73691         if (bytesRead == pMetadata->data.unknown.dataSizeInBytes) {
73692             pParser->metadataCursor += 1;
73693         } else {
73694         }
73695     }
73696     return bytesRead;
73697 }
73698 DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_metadata_type allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID)
73699 {
73700     return (allowedMetadataTypes & type) && drwav_fourcc_equal(pChunkID, pID);
73701 }
73702 DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata_type allowedMetadataTypes)
73703 {
73704     const drwav_uint8 *pChunkID = pChunkHeader->id.fourcc;
73705     drwav_uint64 bytesRead = 0;
73706     if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_smpl, "smpl")) {
73707         if (pChunkHeader->sizeInBytes >= DRWAV_SMPL_BYTES) {
73708             if (pParser->stage == drwav__metadata_parser_stage_count) {
73709                 drwav_uint8 buffer[4];
73710                 size_t bytesJustRead;
73711                 if (!pParser->onSeek(pParser->pReadSeekUserData, 28, drwav_seek_origin_current)) {
73712                     return bytesRead;
73713                 }
73714                 bytesRead += 28;
73715                 bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead);
73716                 if (bytesJustRead == sizeof(buffer)) {
73717                     drwav_uint32 loopCount = drwav_bytes_to_u32(buffer);
73718                     drwav_uint64 calculatedLoopCount;
73719                     calculatedLoopCount = (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES;
73720                     if (calculatedLoopCount == loopCount) {
73721                         bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead);
73722                         if (bytesJustRead == sizeof(buffer)) {
73723                             drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer);
73724                             pParser->metadataCount += 1;
73725                             drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT);
73726                             drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1);
73727                         }
73728                     } else {
73729                     }
73730                 }
73731             } else {
73732                 bytesRead = drwav__read_smpl_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]);
73733                 if (bytesRead == pChunkHeader->sizeInBytes) {
73734                     pParser->metadataCursor += 1;
73735                 } else {
73736                 }
73737             }
73738         } else {
73739         }
73740     } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_inst, "inst")) {
73741         if (pChunkHeader->sizeInBytes == DRWAV_INST_BYTES) {
73742             if (pParser->stage == drwav__metadata_parser_stage_count) {
73743                 pParser->metadataCount += 1;
73744             } else {
73745                 bytesRead = drwav__read_inst_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]);
73746                 if (bytesRead == pChunkHeader->sizeInBytes) {
73747                     pParser->metadataCursor += 1;
73748                 } else {
73749                 }
73750             }
73751         } else {
73752         }
73753     } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_acid, "acid")) {
73754         if (pChunkHeader->sizeInBytes == DRWAV_ACID_BYTES) {
73755             if (pParser->stage == drwav__metadata_parser_stage_count) {
73756                 pParser->metadataCount += 1;
73757             } else {
73758                 bytesRead = drwav__read_acid_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]);
73759                 if (bytesRead == pChunkHeader->sizeInBytes) {
73760                     pParser->metadataCursor += 1;
73761                 } else {
73762                 }
73763             }
73764         } else {
73765         }
73766     } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_cue, "cue ")) {
73767         if (pChunkHeader->sizeInBytes >= DRWAV_CUE_BYTES) {
73768             if (pParser->stage == drwav__metadata_parser_stage_count) {
73769                 size_t cueCount;
73770                 pParser->metadataCount += 1;
73771                 cueCount = (size_t)(pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES;
73772                 drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_cue_point) * cueCount, DRWAV_METADATA_ALIGNMENT);
73773             } else {
73774                 bytesRead = drwav__read_cue_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]);
73775                 if (bytesRead == pChunkHeader->sizeInBytes) {
73776                     pParser->metadataCursor += 1;
73777                 } else {
73778                 }
73779             }
73780         } else {
73781         }
73782     } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_bext, "bext")) {
73783         if (pChunkHeader->sizeInBytes >= DRWAV_BEXT_BYTES) {
73784             if (pParser->stage == drwav__metadata_parser_stage_count) {
73785                 char buffer[DRWAV_BEXT_DESCRIPTION_BYTES + 1];
73786                 size_t allocSizeNeeded = DRWAV_BEXT_UMID_BYTES;
73787                 size_t bytesJustRead;
73788                 buffer[DRWAV_BEXT_DESCRIPTION_BYTES] = '\0';
73789                 bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_DESCRIPTION_BYTES, &bytesRead);
73790                 if (bytesJustRead != DRWAV_BEXT_DESCRIPTION_BYTES) {
73791                     return bytesRead;
73792                 }
73793                 allocSizeNeeded += strlen(buffer) + 1;
73794                 buffer[DRWAV_BEXT_ORIGINATOR_NAME_BYTES] = '\0';
73795                 bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_NAME_BYTES, &bytesRead);
73796                 if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_NAME_BYTES) {
73797                     return bytesRead;
73798                 }
73799                 allocSizeNeeded += strlen(buffer) + 1;
73800                 buffer[DRWAV_BEXT_ORIGINATOR_REF_BYTES] = '\0';
73801                 bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_REF_BYTES, &bytesRead);
73802                 if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_REF_BYTES) {
73803                     return bytesRead;
73804                 }
73805                 allocSizeNeeded += strlen(buffer) + 1;
73806                 allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES;
73807                 drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1);
73808                 pParser->metadataCount += 1;
73809             } else {
73810                 bytesRead = drwav__read_bext_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], pChunkHeader->sizeInBytes);
73811                 if (bytesRead == pChunkHeader->sizeInBytes) {
73812                     pParser->metadataCursor += 1;
73813                 } else {
73814                 }
73815             }
73816         } else {
73817         }
73818     } else if (drwav_fourcc_equal(pChunkID, "LIST") || drwav_fourcc_equal(pChunkID, "list")) {
73819         drwav_metadata_location listType = drwav_metadata_location_invalid;
73820         while (bytesRead < pChunkHeader->sizeInBytes) {
73821             drwav_uint8 subchunkId[4];
73822             drwav_uint8 subchunkSizeBuffer[4];
73823             drwav_uint64 subchunkDataSize;
73824             drwav_uint64 subchunkBytesRead = 0;
73825             drwav_uint64 bytesJustRead = drwav__metadata_parser_read(pParser, subchunkId, sizeof(subchunkId), &bytesRead);
73826             if (bytesJustRead != sizeof(subchunkId)) {
73827                 break;
73828             }
73829             if (drwav_fourcc_equal(subchunkId, "adtl")) {
73830                 listType = drwav_metadata_location_inside_adtl_list;
73831                 continue;
73832             } else if (drwav_fourcc_equal(subchunkId, "INFO")) {
73833                 listType = drwav_metadata_location_inside_info_list;
73834                 continue;
73835             }
73836             bytesJustRead = drwav__metadata_parser_read(pParser, subchunkSizeBuffer, sizeof(subchunkSizeBuffer), &bytesRead);
73837             if (bytesJustRead != sizeof(subchunkSizeBuffer)) {
73838                 break;
73839             }
73840             subchunkDataSize = drwav_bytes_to_u32(subchunkSizeBuffer);
73841             if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_label, "labl") || drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_note, "note")) {
73842                 if (subchunkDataSize >= DRWAV_LIST_LABEL_OR_NOTE_BYTES) {
73843                     drwav_uint64 stringSizeWithNullTerm = subchunkDataSize - DRWAV_LIST_LABEL_OR_NOTE_BYTES;
73844                     if (pParser->stage == drwav__metadata_parser_stage_count) {
73845                         pParser->metadataCount += 1;
73846                         drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)stringSizeWithNullTerm, 1);
73847                     } else {
73848                         subchunkBytesRead = drwav__read_list_label_or_note_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], subchunkDataSize, drwav_fourcc_equal(subchunkId, "labl") ? drwav_metadata_type_list_label : drwav_metadata_type_list_note);
73849                         if (subchunkBytesRead == subchunkDataSize) {
73850                             pParser->metadataCursor += 1;
73851                         } else {
73852                         }
73853                     }
73854                 } else {
73855                 }
73856             } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_labelled_cue_region, "ltxt")) {
73857                 if (subchunkDataSize >= DRWAV_LIST_LABELLED_TEXT_BYTES) {
73858                     drwav_uint64 stringSizeWithNullTerminator = subchunkDataSize - DRWAV_LIST_LABELLED_TEXT_BYTES;
73859                     if (pParser->stage == drwav__metadata_parser_stage_count) {
73860                         pParser->metadataCount += 1;
73861                         drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)stringSizeWithNullTerminator, 1);
73862                     } else {
73863                         subchunkBytesRead = drwav__read_list_labelled_cue_region_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], subchunkDataSize);
73864                         if (subchunkBytesRead == subchunkDataSize) {
73865                             pParser->metadataCursor += 1;
73866                         } else {
73867                         }
73868                     }
73869                 } else {
73870                 }
73871             } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_software, "ISFT")) {
73872                 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_software);
73873             } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_copyright, "ICOP")) {
73874                 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_copyright);
73875             } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_title, "INAM")) {
73876                 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_title);
73877             } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_artist, "IART")) {
73878                 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_artist);
73879             } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_comment, "ICMT")) {
73880                 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_comment);
73881             } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_date, "ICRD")) {
73882                 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_date);
73883             } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_genre, "IGNR")) {
73884                 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_genre);
73885             } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_album, "IPRD")) {
73886                 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_album);
73887             } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_tracknumber, "ITRK")) {
73888                 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize,  drwav_metadata_type_list_info_tracknumber);
73889             } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) {
73890                 subchunkBytesRead = drwav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType);
73891             }
73892             bytesRead += subchunkBytesRead;
73893             DRWAV_ASSERT(subchunkBytesRead <= subchunkDataSize);
73894             if (subchunkBytesRead < subchunkDataSize) {
73895                 drwav_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead;
73896                 if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, drwav_seek_origin_current)) {
73897                     break;
73898                 }
73899                 bytesRead += bytesToSeek;
73900             }
73901             if ((subchunkDataSize % 2) == 1) {
73902                 if (!pParser->onSeek(pParser->pReadSeekUserData, 1, drwav_seek_origin_current)) {
73903                     break;
73904                 }
73905                 bytesRead += 1;
73906             }
73907         }
73908     } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) {
73909         bytesRead = drwav__metadata_process_unknown_chunk(pParser, pChunkID, pChunkHeader->sizeInBytes, drwav_metadata_location_top_level);
73910     }
73911     return bytesRead;
73912 }
73913 DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav)
73914 {
73915     drwav_uint32 bytesPerFrame;
73916     if ((pWav->bitsPerSample & 0x7) == 0) {
73917         bytesPerFrame = (pWav->bitsPerSample * pWav->fmt.channels) >> 3;
73918     } else {
73919         bytesPerFrame = pWav->fmt.blockAlign;
73920     }
73921     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW || pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
73922         if (bytesPerFrame != pWav->fmt.channels) {
73923             return 0;
73924         }
73925     }
73926     return bytesPerFrame;
73927 }
73928 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT)
73929 {
73930     if (pFMT == NULL) {
73931         return 0;
73932     }
73933     if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) {
73934         return pFMT->formatTag;
73935     } else {
73936         return drwav_bytes_to_u16(pFMT->subFormat);
73937     }
73938 }
73939 DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
73940 {
73941     if (pWav == NULL || onRead == NULL || onSeek == NULL) {
73942         return DRWAV_FALSE;
73943     }
73944     DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
73945     pWav->onRead    = onRead;
73946     pWav->onSeek    = onSeek;
73947     pWav->pUserData = pReadSeekUserData;
73948     pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
73949     if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
73950         return DRWAV_FALSE;
73951     }
73952     return DRWAV_TRUE;
73953 }
73954 DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags)
73955 {
73956     drwav_uint64 cursor;
73957     drwav_bool32 sequential;
73958     drwav_uint8 riff[4];
73959     drwav_fmt fmt;
73960     unsigned short translatedFormatTag;
73961     drwav_bool32 foundDataChunk;
73962     drwav_uint64 dataChunkSize = 0;
73963     drwav_uint64 sampleCountFromFactChunk = 0;
73964     drwav_uint64 chunkSize;
73965     drwav__metadata_parser metadataParser;
73966     cursor = 0;
73967     sequential = (flags & DRWAV_SEQUENTIAL) != 0;
73968     if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) {
73969         return DRWAV_FALSE;
73970     }
73971     if (drwav_fourcc_equal(riff, "RIFF")) {
73972         pWav->container = drwav_container_riff;
73973     } else if (drwav_fourcc_equal(riff, "riff")) {
73974         int i;
73975         drwav_uint8 riff2[12];
73976         pWav->container = drwav_container_w64;
73977         if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) {
73978             return DRWAV_FALSE;
73979         }
73980         for (i = 0; i < 12; ++i) {
73981             if (riff2[i] != drwavGUID_W64_RIFF[i+4]) {
73982                 return DRWAV_FALSE;
73983             }
73984         }
73985     } else if (drwav_fourcc_equal(riff, "RF64")) {
73986         pWav->container = drwav_container_rf64;
73987     } else {
73988         return DRWAV_FALSE;
73989     }
73990     if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
73991         drwav_uint8 chunkSizeBytes[4];
73992         drwav_uint8 wave[4];
73993         if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
73994             return DRWAV_FALSE;
73995         }
73996         if (pWav->container == drwav_container_riff) {
73997             if (drwav_bytes_to_u32(chunkSizeBytes) < 36) {
73998                 return DRWAV_FALSE;
73999             }
74000         } else {
74001             if (drwav_bytes_to_u32(chunkSizeBytes) != 0xFFFFFFFF) {
74002                 return DRWAV_FALSE;
74003             }
74004         }
74005         if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
74006             return DRWAV_FALSE;
74007         }
74008         if (!drwav_fourcc_equal(wave, "WAVE")) {
74009             return DRWAV_FALSE;
74010         }
74011     } else {
74012         drwav_uint8 chunkSizeBytes[8];
74013         drwav_uint8 wave[16];
74014         if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
74015             return DRWAV_FALSE;
74016         }
74017         if (drwav_bytes_to_u64(chunkSizeBytes) < 80) {
74018             return DRWAV_FALSE;
74019         }
74020         if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
74021             return DRWAV_FALSE;
74022         }
74023         if (!drwav_guid_equal(wave, drwavGUID_W64_WAVE)) {
74024             return DRWAV_FALSE;
74025         }
74026     }
74027     if (pWav->container == drwav_container_rf64) {
74028         drwav_uint8 sizeBytes[8];
74029         drwav_uint64 bytesRemainingInChunk;
74030         drwav_chunk_header header;
74031         drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
74032         if (result != DRWAV_SUCCESS) {
74033             return DRWAV_FALSE;
74034         }
74035         if (!drwav_fourcc_equal(header.id.fourcc, "ds64")) {
74036             return DRWAV_FALSE;
74037         }
74038         bytesRemainingInChunk = header.sizeInBytes + header.paddingSize;
74039         if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) {
74040             return DRWAV_FALSE;
74041         }
74042         bytesRemainingInChunk -= 8;
74043         cursor += 8;
74044         if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
74045             return DRWAV_FALSE;
74046         }
74047         bytesRemainingInChunk -= 8;
74048         dataChunkSize = drwav_bytes_to_u64(sizeBytes);
74049         if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
74050             return DRWAV_FALSE;
74051         }
74052         bytesRemainingInChunk -= 8;
74053         sampleCountFromFactChunk = drwav_bytes_to_u64(sizeBytes);
74054         if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) {
74055             return DRWAV_FALSE;
74056         }
74057         cursor += bytesRemainingInChunk;
74058     }
74059     if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) {
74060         return DRWAV_FALSE;
74061     }
74062     if ((fmt.sampleRate    == 0 || fmt.sampleRate    > DRWAV_MAX_SAMPLE_RATE)     ||
74063         (fmt.channels      == 0 || fmt.channels      > DRWAV_MAX_CHANNELS)        ||
74064         (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) ||
74065         fmt.blockAlign == 0) {
74066         return DRWAV_FALSE;
74067     }
74068     translatedFormatTag = fmt.formatTag;
74069     if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
74070         translatedFormatTag = drwav_bytes_to_u16(fmt.subFormat + 0);
74071     }
74072     memset(&metadataParser, 0, sizeof(metadataParser));
74073     if (!sequential && pWav->allowedMetadataTypes != drwav_metadata_type_none && (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64)) {
74074         drwav_uint64 cursorForMetadata = cursor;
74075         metadataParser.onRead = pWav->onRead;
74076         metadataParser.onSeek = pWav->onSeek;
74077         metadataParser.pReadSeekUserData = pWav->pUserData;
74078         metadataParser.stage = drwav__metadata_parser_stage_count;
74079         for (;;) {
74080             drwav_result result;
74081             drwav_uint64 bytesRead;
74082             drwav_uint64 remainingBytes;
74083             drwav_chunk_header header;
74084             result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursorForMetadata, &header);
74085             if (result != DRWAV_SUCCESS) {
74086                 break;
74087             }
74088             bytesRead = drwav__metadata_process_chunk(&metadataParser, &header, pWav->allowedMetadataTypes);
74089             DRWAV_ASSERT(bytesRead <= header.sizeInBytes);
74090             remainingBytes = header.sizeInBytes - bytesRead + header.paddingSize;
74091             if (!drwav__seek_forward(pWav->onSeek, remainingBytes, pWav->pUserData)) {
74092                 break;
74093             }
74094             cursorForMetadata += remainingBytes;
74095         }
74096         if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) {
74097             return DRWAV_FALSE;
74098         }
74099         drwav__metadata_alloc(&metadataParser, &pWav->allocationCallbacks);
74100         metadataParser.stage = drwav__metadata_parser_stage_read;
74101     }
74102     foundDataChunk = DRWAV_FALSE;
74103     for (;;) {
74104         drwav_chunk_header header;
74105         drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
74106         if (result != DRWAV_SUCCESS) {
74107             if (!foundDataChunk) {
74108                 return DRWAV_FALSE;
74109             } else {
74110                 break;
74111             }
74112         }
74113         if (!sequential && onChunk != NULL) {
74114             drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt);
74115             if (callbackBytesRead > 0) {
74116                 if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) {
74117                     return DRWAV_FALSE;
74118                 }
74119             }
74120         }
74121         if (!sequential && pWav->allowedMetadataTypes != drwav_metadata_type_none && (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64)) {
74122             drwav_uint64 bytesRead = drwav__metadata_process_chunk(&metadataParser, &header, pWav->allowedMetadataTypes);
74123             if (bytesRead > 0) {
74124                 if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) {
74125                     return DRWAV_FALSE;
74126                 }
74127             }
74128         }
74129         if (!foundDataChunk) {
74130             pWav->dataChunkDataPos = cursor;
74131         }
74132         chunkSize = header.sizeInBytes;
74133         if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
74134             if (drwav_fourcc_equal(header.id.fourcc, "data")) {
74135                 foundDataChunk = DRWAV_TRUE;
74136                 if (pWav->container != drwav_container_rf64) {
74137                     dataChunkSize = chunkSize;
74138                 }
74139             }
74140         } else {
74141             if (drwav_guid_equal(header.id.guid, drwavGUID_W64_DATA)) {
74142                 foundDataChunk = DRWAV_TRUE;
74143                 dataChunkSize = chunkSize;
74144             }
74145         }
74146         if (foundDataChunk && sequential) {
74147             break;
74148         }
74149         if (pWav->container == drwav_container_riff) {
74150             if (drwav_fourcc_equal(header.id.fourcc, "fact")) {
74151                 drwav_uint32 sampleCount;
74152                 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) {
74153                     return DRWAV_FALSE;
74154                 }
74155                 chunkSize -= 4;
74156                 if (!foundDataChunk) {
74157                     pWav->dataChunkDataPos = cursor;
74158                 }
74159                 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
74160                     sampleCountFromFactChunk = sampleCount;
74161                 } else {
74162                     sampleCountFromFactChunk = 0;
74163                 }
74164             }
74165         } else if (pWav->container == drwav_container_w64) {
74166             if (drwav_guid_equal(header.id.guid, drwavGUID_W64_FACT)) {
74167                 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) {
74168                     return DRWAV_FALSE;
74169                 }
74170                 chunkSize -= 8;
74171                 if (!foundDataChunk) {
74172                     pWav->dataChunkDataPos = cursor;
74173                 }
74174             }
74175         } else if (pWav->container == drwav_container_rf64) {
74176         }
74177         chunkSize += header.paddingSize;
74178         if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) {
74179             break;
74180         }
74181         cursor += chunkSize;
74182         if (!foundDataChunk) {
74183             pWav->dataChunkDataPos = cursor;
74184         }
74185     }
74186     pWav->pMetadata     = metadataParser.pMetadata;
74187     pWav->metadataCount = metadataParser.metadataCount;
74188     if (!foundDataChunk) {
74189         return DRWAV_FALSE;
74190     }
74191     if (!sequential) {
74192         if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) {
74193             return DRWAV_FALSE;
74194         }
74195         cursor = pWav->dataChunkDataPos;
74196     }
74197     pWav->fmt                 = fmt;
74198     pWav->sampleRate          = fmt.sampleRate;
74199     pWav->channels            = fmt.channels;
74200     pWav->bitsPerSample       = fmt.bitsPerSample;
74201     pWav->bytesRemaining      = dataChunkSize;
74202     pWav->translatedFormatTag = translatedFormatTag;
74203     pWav->dataChunkDataSize   = dataChunkSize;
74204     if (sampleCountFromFactChunk != 0) {
74205         pWav->totalPCMFrameCount = sampleCountFromFactChunk;
74206     } else {
74207         drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
74208         if (bytesPerFrame == 0) {
74209             return DRWAV_FALSE;
74210         }
74211         pWav->totalPCMFrameCount = dataChunkSize / bytesPerFrame;
74212         if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
74213             drwav_uint64 totalBlockHeaderSizeInBytes;
74214             drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
74215             if ((blockCount * fmt.blockAlign) < dataChunkSize) {
74216                 blockCount += 1;
74217             }
74218             totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels);
74219             pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
74220         }
74221         if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
74222             drwav_uint64 totalBlockHeaderSizeInBytes;
74223             drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
74224             if ((blockCount * fmt.blockAlign) < dataChunkSize) {
74225                 blockCount += 1;
74226             }
74227             totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels);
74228             pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
74229             pWav->totalPCMFrameCount += blockCount;
74230         }
74231     }
74232     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
74233         if (pWav->channels > 2) {
74234             return DRWAV_FALSE;
74235         }
74236     }
74237     if (drwav_get_bytes_per_pcm_frame(pWav) == 0) {
74238         return DRWAV_FALSE;
74239     }
74240 #ifdef DR_WAV_LIBSNDFILE_COMPAT
74241     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
74242         drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
74243         pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels;
74244     }
74245     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
74246         drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
74247         pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels;
74248     }
74249 #endif
74250     return DRWAV_TRUE;
74251 }
74252 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
74253 {
74254     return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks);
74255 }
74256 DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
74257 {
74258     if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) {
74259         return DRWAV_FALSE;
74260     }
74261     return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
74262 }
74263 DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
74264 {
74265     if (!drwav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
74266         return DRWAV_FALSE;
74267     }
74268     pWav->allowedMetadataTypes = drwav_metadata_type_all_including_unknown;
74269     return drwav_init__internal(pWav, NULL, NULL, flags);
74270 }
74271 DRWAV_API drwav_metadata* drwav_take_ownership_of_metadata(drwav* pWav)
74272 {
74273     drwav_metadata *result = pWav->pMetadata;
74274     pWav->pMetadata     = NULL;
74275     pWav->metadataCount = 0;
74276     return result;
74277 }
74278 DRWAV_PRIVATE size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize)
74279 {
74280     DRWAV_ASSERT(pWav          != NULL);
74281     DRWAV_ASSERT(pWav->onWrite != NULL);
74282     return pWav->onWrite(pWav->pUserData, pData, dataSize);
74283 }
74284 DRWAV_PRIVATE size_t drwav__write_byte(drwav* pWav, drwav_uint8 byte)
74285 {
74286     DRWAV_ASSERT(pWav          != NULL);
74287     DRWAV_ASSERT(pWav->onWrite != NULL);
74288     return pWav->onWrite(pWav->pUserData, &byte, 1);
74289 }
74290 DRWAV_PRIVATE size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value)
74291 {
74292     DRWAV_ASSERT(pWav          != NULL);
74293     DRWAV_ASSERT(pWav->onWrite != NULL);
74294     if (!drwav__is_little_endian()) {
74295         value = drwav__bswap16(value);
74296     }
74297     return drwav__write(pWav, &value, 2);
74298 }
74299 DRWAV_PRIVATE size_t drwav__write_u32ne_to_le(drwav* pWav, drwav_uint32 value)
74300 {
74301     DRWAV_ASSERT(pWav          != NULL);
74302     DRWAV_ASSERT(pWav->onWrite != NULL);
74303     if (!drwav__is_little_endian()) {
74304         value = drwav__bswap32(value);
74305     }
74306     return drwav__write(pWav, &value, 4);
74307 }
74308 DRWAV_PRIVATE size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value)
74309 {
74310     DRWAV_ASSERT(pWav          != NULL);
74311     DRWAV_ASSERT(pWav->onWrite != NULL);
74312     if (!drwav__is_little_endian()) {
74313         value = drwav__bswap64(value);
74314     }
74315     return drwav__write(pWav, &value, 8);
74316 }
74317 DRWAV_PRIVATE size_t drwav__write_f32ne_to_le(drwav* pWav, float value)
74318 {
74319     union {
74320        drwav_uint32 u32;
74321        float f32;
74322     } u;
74323     DRWAV_ASSERT(pWav          != NULL);
74324     DRWAV_ASSERT(pWav->onWrite != NULL);
74325     u.f32 = value;
74326     if (!drwav__is_little_endian()) {
74327         u.u32 = drwav__bswap32(u.u32);
74328     }
74329     return drwav__write(pWav, &u.u32, 4);
74330 }
74331 DRWAV_PRIVATE size_t drwav__write_or_count(drwav* pWav, const void* pData, size_t dataSize)
74332 {
74333     if (pWav == NULL) {
74334         return dataSize;
74335     }
74336     return drwav__write(pWav, pData, dataSize);
74337 }
74338 DRWAV_PRIVATE size_t drwav__write_or_count_byte(drwav* pWav, drwav_uint8 byte)
74339 {
74340     if (pWav == NULL) {
74341         return 1;
74342     }
74343     return drwav__write_byte(pWav, byte);
74344 }
74345 DRWAV_PRIVATE size_t drwav__write_or_count_u16ne_to_le(drwav* pWav, drwav_uint16 value)
74346 {
74347     if (pWav == NULL) {
74348         return 2;
74349     }
74350     return drwav__write_u16ne_to_le(pWav, value);
74351 }
74352 DRWAV_PRIVATE size_t drwav__write_or_count_u32ne_to_le(drwav* pWav, drwav_uint32 value)
74353 {
74354     if (pWav == NULL) {
74355         return 4;
74356     }
74357     return drwav__write_u32ne_to_le(pWav, value);
74358 }
74359 #if 0
74360 DRWAV_PRIVATE size_t drwav__write_or_count_u64ne_to_le(drwav* pWav, drwav_uint64 value)
74361 {
74362     if (pWav == NULL) {
74363         return 8;
74364     }
74365     return drwav__write_u64ne_to_le(pWav, value);
74366 }
74367 #endif
74368 DRWAV_PRIVATE size_t drwav__write_or_count_f32ne_to_le(drwav* pWav, float value)
74369 {
74370     if (pWav == NULL) {
74371         return 4;
74372     }
74373     return drwav__write_f32ne_to_le(pWav, value);
74374 }
74375 DRWAV_PRIVATE size_t drwav__write_or_count_string_to_fixed_size_buf(drwav* pWav, char* str, size_t bufFixedSize)
74376 {
74377     size_t len;
74378     if (pWav == NULL) {
74379         return bufFixedSize;
74380     }
74381     len = drwav__strlen_clamped(str, bufFixedSize);
74382     drwav__write_or_count(pWav, str, len);
74383     if (len < bufFixedSize) {
74384         size_t i;
74385         for (i = 0; i < bufFixedSize - len; ++i) {
74386             drwav__write_byte(pWav, 0);
74387         }
74388     }
74389     return bufFixedSize;
74390 }
74391 DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata* pMetadatas, drwav_uint32 metadataCount)
74392 {
74393     size_t bytesWritten = 0;
74394     drwav_bool32 hasListAdtl = DRWAV_FALSE;
74395     drwav_bool32 hasListInfo = DRWAV_FALSE;
74396     drwav_uint32 iMetadata;
74397     if (pMetadatas == NULL || metadataCount == 0) {
74398         return 0;
74399     }
74400     for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
74401         drwav_metadata* pMetadata = &pMetadatas[iMetadata];
74402         drwav_uint32 chunkSize = 0;
74403         if ((pMetadata->type & drwav_metadata_type_list_all_info_strings) || (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list)) {
74404             hasListInfo = DRWAV_TRUE;
74405         }
74406         if ((pMetadata->type & drwav_metadata_type_list_all_adtl) || (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list)) {
74407             hasListAdtl = DRWAV_TRUE;
74408         }
74409         switch (pMetadata->type) {
74410             case drwav_metadata_type_smpl:
74411             {
74412                 drwav_uint32 iLoop;
74413                 chunkSize = DRWAV_SMPL_BYTES + DRWAV_SMPL_LOOP_BYTES * pMetadata->data.smpl.sampleLoopCount + pMetadata->data.smpl.samplerSpecificDataSizeInBytes;
74414                 bytesWritten += drwav__write_or_count(pWav, "smpl", 4);
74415                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
74416                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.manufacturerId);
74417                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.productId);
74418                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.samplePeriodNanoseconds);
74419                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.midiUnityNote);
74420                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.midiPitchFraction);
74421                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.smpteFormat);
74422                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.smpteOffset);
74423                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.sampleLoopCount);
74424                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.samplerSpecificDataSizeInBytes);
74425                 for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) {
74426                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId);
74427                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type);
74428                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleByteOffset);
74429                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleByteOffset);
74430                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction);
74431                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount);
74432                 }
74433                 if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) {
74434                     bytesWritten += drwav__write(pWav, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes);
74435                 }
74436             } break;
74437             case drwav_metadata_type_inst:
74438             {
74439                 chunkSize = DRWAV_INST_BYTES;
74440                 bytesWritten += drwav__write_or_count(pWav, "inst", 4);
74441                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
74442                 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.midiUnityNote, 1);
74443                 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.fineTuneCents, 1);
74444                 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.gainDecibels, 1);
74445                 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.lowNote, 1);
74446                 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.highNote, 1);
74447                 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.lowVelocity, 1);
74448                 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.highVelocity, 1);
74449             } break;
74450             case drwav_metadata_type_cue:
74451             {
74452                 drwav_uint32 iCuePoint;
74453                 chunkSize = DRWAV_CUE_BYTES + DRWAV_CUE_POINT_BYTES * pMetadata->data.cue.cuePointCount;
74454                 bytesWritten += drwav__write_or_count(pWav, "cue ", 4);
74455                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
74456                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.cuePointCount);
74457                 for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) {
74458                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].id);
74459                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition);
74460                     bytesWritten += drwav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4);
74461                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart);
74462                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart);
74463                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset);
74464                 }
74465             } break;
74466             case drwav_metadata_type_acid:
74467             {
74468                 chunkSize = DRWAV_ACID_BYTES;
74469                 bytesWritten += drwav__write_or_count(pWav, "acid", 4);
74470                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
74471                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.acid.flags);
74472                 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.midiUnityNote);
74473                 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.reserved1);
74474                 bytesWritten += drwav__write_or_count_f32ne_to_le(pWav, pMetadata->data.acid.reserved2);
74475                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.acid.numBeats);
74476                 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.meterDenominator);
74477                 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.meterNumerator);
74478                 bytesWritten += drwav__write_or_count_f32ne_to_le(pWav, pMetadata->data.acid.tempo);
74479             } break;
74480             case drwav_metadata_type_bext:
74481             {
74482                 char reservedBuf[DRWAV_BEXT_RESERVED_BYTES];
74483                 drwav_uint32 timeReferenceLow;
74484                 drwav_uint32 timeReferenceHigh;
74485                 chunkSize = DRWAV_BEXT_BYTES + pMetadata->data.bext.codingHistorySize;
74486                 bytesWritten += drwav__write_or_count(pWav, "bext", 4);
74487                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
74488                 bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pDescription, DRWAV_BEXT_DESCRIPTION_BYTES);
74489                 bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pOriginatorName, DRWAV_BEXT_ORIGINATOR_NAME_BYTES);
74490                 bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pOriginatorReference, DRWAV_BEXT_ORIGINATOR_REF_BYTES);
74491                 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate));
74492                 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime));
74493                 timeReferenceLow  = (drwav_uint32)(pMetadata->data.bext.timeReference & 0xFFFFFFFF);
74494                 timeReferenceHigh = (drwav_uint32)(pMetadata->data.bext.timeReference >> 32);
74495                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, timeReferenceLow);
74496                 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, timeReferenceHigh);
74497                 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.version);
74498                 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES);
74499                 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.loudnessValue);
74500                 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.loudnessRange);
74501                 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxTruePeakLevel);
74502                 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxMomentaryLoudness);
74503                 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxShortTermLoudness);
74504                 memset(reservedBuf, 0, sizeof(reservedBuf));
74505                 bytesWritten += drwav__write_or_count(pWav, reservedBuf, sizeof(reservedBuf));
74506                 if (pMetadata->data.bext.codingHistorySize > 0) {
74507                     bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pCodingHistory, pMetadata->data.bext.codingHistorySize);
74508                 }
74509             } break;
74510             case drwav_metadata_type_unknown:
74511             {
74512                 if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_top_level) {
74513                     chunkSize = pMetadata->data.unknown.dataSizeInBytes;
74514                     bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4);
74515                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
74516                     bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, pMetadata->data.unknown.dataSizeInBytes);
74517                 }
74518             } break;
74519             default: break;
74520         }
74521         if ((chunkSize % 2) != 0) {
74522             bytesWritten += drwav__write_or_count_byte(pWav, 0);
74523         }
74524     }
74525     if (hasListInfo) {
74526         drwav_uint32 chunkSize = 4;
74527         for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
74528             drwav_metadata* pMetadata = &pMetadatas[iMetadata];
74529             if ((pMetadata->type & drwav_metadata_type_list_all_info_strings)) {
74530                 chunkSize += 8;
74531                 chunkSize += pMetadata->data.infoText.stringLength + 1;
74532             } else if (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list) {
74533                 chunkSize += 8;
74534                 chunkSize += pMetadata->data.unknown.dataSizeInBytes;
74535             }
74536             if ((chunkSize % 2) != 0) {
74537                 chunkSize += 1;
74538             }
74539         }
74540         bytesWritten += drwav__write_or_count(pWav, "LIST", 4);
74541         bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
74542         bytesWritten += drwav__write_or_count(pWav, "INFO", 4);
74543         for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
74544             drwav_metadata* pMetadata = &pMetadatas[iMetadata];
74545             drwav_uint32 subchunkSize = 0;
74546             if (pMetadata->type & drwav_metadata_type_list_all_info_strings) {
74547                 const char* pID = NULL;
74548                 switch (pMetadata->type) {
74549                     case drwav_metadata_type_list_info_software:    pID = "ISFT"; break;
74550                     case drwav_metadata_type_list_info_copyright:   pID = "ICOP"; break;
74551                     case drwav_metadata_type_list_info_title:       pID = "INAM"; break;
74552                     case drwav_metadata_type_list_info_artist:      pID = "IART"; break;
74553                     case drwav_metadata_type_list_info_comment:     pID = "ICMT"; break;
74554                     case drwav_metadata_type_list_info_date:        pID = "ICRD"; break;
74555                     case drwav_metadata_type_list_info_genre:       pID = "IGNR"; break;
74556                     case drwav_metadata_type_list_info_album:       pID = "IPRD"; break;
74557                     case drwav_metadata_type_list_info_tracknumber: pID = "ITRK"; break;
74558                     default: break;
74559                 }
74560                 DRWAV_ASSERT(pID != NULL);
74561                 if (pMetadata->data.infoText.stringLength) {
74562                     subchunkSize = pMetadata->data.infoText.stringLength + 1;
74563                     bytesWritten += drwav__write_or_count(pWav, pID, 4);
74564                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
74565                     bytesWritten += drwav__write_or_count(pWav, pMetadata->data.infoText.pString, pMetadata->data.infoText.stringLength);
74566                     bytesWritten += drwav__write_or_count_byte(pWav, '\0');
74567                 }
74568             } else if (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list) {
74569                 if (pMetadata->data.unknown.dataSizeInBytes) {
74570                     subchunkSize = pMetadata->data.unknown.dataSizeInBytes;
74571                     bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4);
74572                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.unknown.dataSizeInBytes);
74573                     bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, subchunkSize);
74574                 }
74575             }
74576             if ((subchunkSize % 2) != 0) {
74577                 bytesWritten += drwav__write_or_count_byte(pWav, 0);
74578             }
74579         }
74580     }
74581     if (hasListAdtl) {
74582         drwav_uint32 chunkSize = 4;
74583         for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
74584             drwav_metadata* pMetadata = &pMetadatas[iMetadata];
74585             switch (pMetadata->type)
74586             {
74587                 case drwav_metadata_type_list_label:
74588                 case drwav_metadata_type_list_note:
74589                 {
74590                     chunkSize += 8;
74591                     chunkSize += DRWAV_LIST_LABEL_OR_NOTE_BYTES;
74592                     if (pMetadata->data.labelOrNote.stringLength > 0) {
74593                         chunkSize += pMetadata->data.labelOrNote.stringLength + 1;
74594                     }
74595                 } break;
74596                 case drwav_metadata_type_list_labelled_cue_region:
74597                 {
74598                     chunkSize += 8;
74599                     chunkSize += DRWAV_LIST_LABELLED_TEXT_BYTES;
74600                     if (pMetadata->data.labelledCueRegion.stringLength > 0) {
74601                         chunkSize += pMetadata->data.labelledCueRegion.stringLength + 1;
74602                     }
74603                 } break;
74604                 case drwav_metadata_type_unknown:
74605                 {
74606                     if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list) {
74607                         chunkSize += 8;
74608                         chunkSize += pMetadata->data.unknown.dataSizeInBytes;
74609                     }
74610                 } break;
74611                 default: break;
74612             }
74613             if ((chunkSize % 2) != 0) {
74614                 chunkSize += 1;
74615             }
74616         }
74617         bytesWritten += drwav__write_or_count(pWav, "LIST", 4);
74618         bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
74619         bytesWritten += drwav__write_or_count(pWav, "adtl", 4);
74620         for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
74621             drwav_metadata* pMetadata = &pMetadatas[iMetadata];
74622             drwav_uint32 subchunkSize = 0;
74623             switch (pMetadata->type)
74624             {
74625                 case drwav_metadata_type_list_label:
74626                 case drwav_metadata_type_list_note:
74627                 {
74628                     if (pMetadata->data.labelOrNote.stringLength > 0) {
74629                         const char *pID = NULL;
74630                         if (pMetadata->type == drwav_metadata_type_list_label) {
74631                             pID = "labl";
74632                         }
74633                         else if (pMetadata->type == drwav_metadata_type_list_note) {
74634                             pID = "note";
74635                         }
74636                         DRWAV_ASSERT(pID != NULL);
74637                         DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL);
74638                         subchunkSize = DRWAV_LIST_LABEL_OR_NOTE_BYTES;
74639                         bytesWritten += drwav__write_or_count(pWav, pID, 4);
74640                         subchunkSize += pMetadata->data.labelOrNote.stringLength + 1;
74641                         bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
74642                         bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelOrNote.cuePointId);
74643                         bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelOrNote.pString, pMetadata->data.labelOrNote.stringLength);
74644                         bytesWritten += drwav__write_or_count_byte(pWav, '\0');
74645                     }
74646                 } break;
74647                 case drwav_metadata_type_list_labelled_cue_region:
74648                 {
74649                     subchunkSize = DRWAV_LIST_LABELLED_TEXT_BYTES;
74650                     bytesWritten += drwav__write_or_count(pWav, "ltxt", 4);
74651                     if (pMetadata->data.labelledCueRegion.stringLength > 0) {
74652                         subchunkSize += pMetadata->data.labelledCueRegion.stringLength + 1;
74653                     }
74654                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
74655                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelledCueRegion.cuePointId);
74656                     bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelledCueRegion.sampleLength);
74657                     bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelledCueRegion.purposeId, 4);
74658                     bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.country);
74659                     bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.language);
74660                     bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.dialect);
74661                     bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.codePage);
74662                     if (pMetadata->data.labelledCueRegion.stringLength > 0) {
74663                         DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL);
74664                         bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelledCueRegion.pString, pMetadata->data.labelledCueRegion.stringLength);
74665                         bytesWritten += drwav__write_or_count_byte(pWav, '\0');
74666                     }
74667                 } break;
74668                 case drwav_metadata_type_unknown:
74669                 {
74670                     if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list) {
74671                         subchunkSize = pMetadata->data.unknown.dataSizeInBytes;
74672                         DRWAV_ASSERT(pMetadata->data.unknown.pData != NULL);
74673                         bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4);
74674                         bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
74675                         bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, subchunkSize);
74676                     }
74677                 } break;
74678                 default: break;
74679             }
74680             if ((subchunkSize % 2) != 0) {
74681                 bytesWritten += drwav__write_or_count_byte(pWav, 0);
74682             }
74683         }
74684     }
74685     DRWAV_ASSERT((bytesWritten % 2) == 0);
74686     return bytesWritten;
74687 }
74688 DRWAV_PRIVATE drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize, drwav_metadata* pMetadata, drwav_uint32 metadataCount)
74689 {
74690     drwav_uint64 chunkSize = 4 + 24 + (drwav_uint64)drwav__write_or_count_metadata(NULL, pMetadata, metadataCount) + 8 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize);
74691     if (chunkSize > 0xFFFFFFFFUL) {
74692         chunkSize = 0xFFFFFFFFUL;
74693     }
74694     return (drwav_uint32)chunkSize;
74695 }
74696 DRWAV_PRIVATE drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)
74697 {
74698     if (dataChunkSize <= 0xFFFFFFFFUL) {
74699         return (drwav_uint32)dataChunkSize;
74700     } else {
74701         return 0xFFFFFFFFUL;
74702     }
74703 }
74704 DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize)
74705 {
74706     drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize);
74707     return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize;
74708 }
74709 DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)
74710 {
74711     return 24 + dataChunkSize;
74712 }
74713 DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize, drwav_metadata *metadata, drwav_uint32 numMetadata)
74714 {
74715     drwav_uint64 chunkSize = 4 + 36 + 24 + (drwav_uint64)drwav__write_or_count_metadata(NULL, metadata, numMetadata) + 8 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize);
74716     if (chunkSize > 0xFFFFFFFFUL) {
74717         chunkSize = 0xFFFFFFFFUL;
74718     }
74719     return chunkSize;
74720 }
74721 DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize)
74722 {
74723     return dataChunkSize;
74724 }
74725 DRWAV_PRIVATE drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_format* pFormat, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
74726 {
74727     if (pWav == NULL || onWrite == NULL) {
74728         return DRWAV_FALSE;
74729     }
74730     if (!isSequential && onSeek == NULL) {
74731         return DRWAV_FALSE;
74732     }
74733     if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) {
74734         return DRWAV_FALSE;
74735     }
74736     if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) {
74737         return DRWAV_FALSE;
74738     }
74739     DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
74740     pWav->onWrite   = onWrite;
74741     pWav->onSeek    = onSeek;
74742     pWav->pUserData = pUserData;
74743     pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
74744     if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
74745         return DRWAV_FALSE;
74746     }
74747     pWav->fmt.formatTag = (drwav_uint16)pFormat->format;
74748     pWav->fmt.channels = (drwav_uint16)pFormat->channels;
74749     pWav->fmt.sampleRate = pFormat->sampleRate;
74750     pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8);
74751     pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8);
74752     pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
74753     pWav->fmt.extendedSize = 0;
74754     pWav->isSequentialWrite = isSequential;
74755     return DRWAV_TRUE;
74756 }
74757 DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
74758 {
74759     size_t runningPos = 0;
74760     drwav_uint64 initialDataChunkSize = 0;
74761     drwav_uint64 chunkSizeFMT;
74762     if (pWav->isSequentialWrite) {
74763         initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8;
74764         if (pFormat->container == drwav_container_riff) {
74765             if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) {
74766                 return DRWAV_FALSE;
74767             }
74768         }
74769     }
74770     pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize;
74771     if (pFormat->container == drwav_container_riff) {
74772         drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize;
74773         runningPos += drwav__write(pWav, "RIFF", 4);
74774         runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
74775         runningPos += drwav__write(pWav, "WAVE", 4);
74776     } else if (pFormat->container == drwav_container_w64) {
74777         drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize;
74778         runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16);
74779         runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF);
74780         runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16);
74781     } else if (pFormat->container == drwav_container_rf64) {
74782         runningPos += drwav__write(pWav, "RF64", 4);
74783         runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF);
74784         runningPos += drwav__write(pWav, "WAVE", 4);
74785     }
74786     if (pFormat->container == drwav_container_rf64) {
74787         drwav_uint32 initialds64ChunkSize = 28;
74788         drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize;
74789         runningPos += drwav__write(pWav, "ds64", 4);
74790         runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize);
74791         runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize);
74792         runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize);
74793         runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount);
74794         runningPos += drwav__write_u32ne_to_le(pWav, 0);
74795     }
74796     if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) {
74797         chunkSizeFMT = 16;
74798         runningPos += drwav__write(pWav, "fmt ", 4);
74799         runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT);
74800     } else if (pFormat->container == drwav_container_w64) {
74801         chunkSizeFMT = 40;
74802         runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16);
74803         runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT);
74804     }
74805     runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.formatTag);
74806     runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.channels);
74807     runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.sampleRate);
74808     runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.avgBytesPerSec);
74809     runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign);
74810     runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample);
74811     if (!pWav->isSequentialWrite && pWav->pMetadata != NULL && pWav->metadataCount > 0 && (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64)) {
74812         runningPos += drwav__write_or_count_metadata(pWav, pWav->pMetadata, pWav->metadataCount);
74813     }
74814     pWav->dataChunkDataPos = runningPos;
74815     if (pFormat->container == drwav_container_riff) {
74816         drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize;
74817         runningPos += drwav__write(pWav, "data", 4);
74818         runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA);
74819     } else if (pFormat->container == drwav_container_w64) {
74820         drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize;
74821         runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16);
74822         runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA);
74823     } else if (pFormat->container == drwav_container_rf64) {
74824         runningPos += drwav__write(pWav, "data", 4);
74825         runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF);
74826     }
74827     pWav->container = pFormat->container;
74828     pWav->channels = (drwav_uint16)pFormat->channels;
74829     pWav->sampleRate = pFormat->sampleRate;
74830     pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
74831     pWav->translatedFormatTag = (drwav_uint16)pFormat->format;
74832     pWav->dataChunkDataPos = runningPos;
74833     return DRWAV_TRUE;
74834 }
74835 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)
74836 {
74837     if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
74838         return DRWAV_FALSE;
74839     }
74840     return drwav_init_write__internal(pWav, pFormat, 0);
74841 }
74842 DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
74843 {
74844     if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) {
74845         return DRWAV_FALSE;
74846     }
74847     return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
74848 }
74849 DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
74850 {
74851     if (pFormat == NULL) {
74852         return DRWAV_FALSE;
74853     }
74854     return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks);
74855 }
74856 DRWAV_API drwav_bool32 drwav_init_write_with_metadata(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks, drwav_metadata* pMetadata, drwav_uint32 metadataCount)
74857 {
74858     if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
74859         return DRWAV_FALSE;
74860     }
74861     pWav->pMetadata     = pMetadata;
74862     pWav->metadataCount = metadataCount;
74863     return drwav_init_write__internal(pWav, pFormat, 0);
74864 }
74865 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalFrameCount, drwav_metadata* pMetadata, drwav_uint32 metadataCount)
74866 {
74867     drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalFrameCount * pFormat->channels * pFormat->bitsPerSample/8.0);
74868     drwav_uint64 riffChunkSizeBytes;
74869     drwav_uint64 fileSizeBytes = 0;
74870     if (pFormat->container == drwav_container_riff) {
74871         riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes, pMetadata, metadataCount);
74872         fileSizeBytes = (8 + riffChunkSizeBytes);
74873     } else if (pFormat->container == drwav_container_w64) {
74874         riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes);
74875         fileSizeBytes = riffChunkSizeBytes;
74876     } else if (pFormat->container == drwav_container_rf64) {
74877         riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes, pMetadata, metadataCount);
74878         fileSizeBytes = (8 + riffChunkSizeBytes);
74879     }
74880     return fileSizeBytes;
74881 }
74882 #ifndef DR_WAV_NO_STDIO
74883 #include <errno.h>
74884 DRWAV_PRIVATE drwav_result drwav_result_from_errno(int e)
74885 {
74886     switch (e)
74887     {
74888         case 0: return DRWAV_SUCCESS;
74889     #ifdef EPERM
74890         case EPERM: return DRWAV_INVALID_OPERATION;
74891     #endif
74892     #ifdef ENOENT
74893         case ENOENT: return DRWAV_DOES_NOT_EXIST;
74894     #endif
74895     #ifdef ESRCH
74896         case ESRCH: return DRWAV_DOES_NOT_EXIST;
74897     #endif
74898     #ifdef EINTR
74899         case EINTR: return DRWAV_INTERRUPT;
74900     #endif
74901     #ifdef EIO
74902         case EIO: return DRWAV_IO_ERROR;
74903     #endif
74904     #ifdef ENXIO
74905         case ENXIO: return DRWAV_DOES_NOT_EXIST;
74906     #endif
74907     #ifdef E2BIG
74908         case E2BIG: return DRWAV_INVALID_ARGS;
74909     #endif
74910     #ifdef ENOEXEC
74911         case ENOEXEC: return DRWAV_INVALID_FILE;
74912     #endif
74913     #ifdef EBADF
74914         case EBADF: return DRWAV_INVALID_FILE;
74915     #endif
74916     #ifdef ECHILD
74917         case ECHILD: return DRWAV_ERROR;
74918     #endif
74919     #ifdef EAGAIN
74920         case EAGAIN: return DRWAV_UNAVAILABLE;
74921     #endif
74922     #ifdef ENOMEM
74923         case ENOMEM: return DRWAV_OUT_OF_MEMORY;
74924     #endif
74925     #ifdef EACCES
74926         case EACCES: return DRWAV_ACCESS_DENIED;
74927     #endif
74928     #ifdef EFAULT
74929         case EFAULT: return DRWAV_BAD_ADDRESS;
74930     #endif
74931     #ifdef ENOTBLK
74932         case ENOTBLK: return DRWAV_ERROR;
74933     #endif
74934     #ifdef EBUSY
74935         case EBUSY: return DRWAV_BUSY;
74936     #endif
74937     #ifdef EEXIST
74938         case EEXIST: return DRWAV_ALREADY_EXISTS;
74939     #endif
74940     #ifdef EXDEV
74941         case EXDEV: return DRWAV_ERROR;
74942     #endif
74943     #ifdef ENODEV
74944         case ENODEV: return DRWAV_DOES_NOT_EXIST;
74945     #endif
74946     #ifdef ENOTDIR
74947         case ENOTDIR: return DRWAV_NOT_DIRECTORY;
74948     #endif
74949     #ifdef EISDIR
74950         case EISDIR: return DRWAV_IS_DIRECTORY;
74951     #endif
74952     #ifdef EINVAL
74953         case EINVAL: return DRWAV_INVALID_ARGS;
74954     #endif
74955     #ifdef ENFILE
74956         case ENFILE: return DRWAV_TOO_MANY_OPEN_FILES;
74957     #endif
74958     #ifdef EMFILE
74959         case EMFILE: return DRWAV_TOO_MANY_OPEN_FILES;
74960     #endif
74961     #ifdef ENOTTY
74962         case ENOTTY: return DRWAV_INVALID_OPERATION;
74963     #endif
74964     #ifdef ETXTBSY
74965         case ETXTBSY: return DRWAV_BUSY;
74966     #endif
74967     #ifdef EFBIG
74968         case EFBIG: return DRWAV_TOO_BIG;
74969     #endif
74970     #ifdef ENOSPC
74971         case ENOSPC: return DRWAV_NO_SPACE;
74972     #endif
74973     #ifdef ESPIPE
74974         case ESPIPE: return DRWAV_BAD_SEEK;
74975     #endif
74976     #ifdef EROFS
74977         case EROFS: return DRWAV_ACCESS_DENIED;
74978     #endif
74979     #ifdef EMLINK
74980         case EMLINK: return DRWAV_TOO_MANY_LINKS;
74981     #endif
74982     #ifdef EPIPE
74983         case EPIPE: return DRWAV_BAD_PIPE;
74984     #endif
74985     #ifdef EDOM
74986         case EDOM: return DRWAV_OUT_OF_RANGE;
74987     #endif
74988     #ifdef ERANGE
74989         case ERANGE: return DRWAV_OUT_OF_RANGE;
74990     #endif
74991     #ifdef EDEADLK
74992         case EDEADLK: return DRWAV_DEADLOCK;
74993     #endif
74994     #ifdef ENAMETOOLONG
74995         case ENAMETOOLONG: return DRWAV_PATH_TOO_LONG;
74996     #endif
74997     #ifdef ENOLCK
74998         case ENOLCK: return DRWAV_ERROR;
74999     #endif
75000     #ifdef ENOSYS
75001         case ENOSYS: return DRWAV_NOT_IMPLEMENTED;
75002     #endif
75003     #ifdef ENOTEMPTY
75004         case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY;
75005     #endif
75006     #ifdef ELOOP
75007         case ELOOP: return DRWAV_TOO_MANY_LINKS;
75008     #endif
75009     #ifdef ENOMSG
75010         case ENOMSG: return DRWAV_NO_MESSAGE;
75011     #endif
75012     #ifdef EIDRM
75013         case EIDRM: return DRWAV_ERROR;
75014     #endif
75015     #ifdef ECHRNG
75016         case ECHRNG: return DRWAV_ERROR;
75017     #endif
75018     #ifdef EL2NSYNC
75019         case EL2NSYNC: return DRWAV_ERROR;
75020     #endif
75021     #ifdef EL3HLT
75022         case EL3HLT: return DRWAV_ERROR;
75023     #endif
75024     #ifdef EL3RST
75025         case EL3RST: return DRWAV_ERROR;
75026     #endif
75027     #ifdef ELNRNG
75028         case ELNRNG: return DRWAV_OUT_OF_RANGE;
75029     #endif
75030     #ifdef EUNATCH
75031         case EUNATCH: return DRWAV_ERROR;
75032     #endif
75033     #ifdef ENOCSI
75034         case ENOCSI: return DRWAV_ERROR;
75035     #endif
75036     #ifdef EL2HLT
75037         case EL2HLT: return DRWAV_ERROR;
75038     #endif
75039     #ifdef EBADE
75040         case EBADE: return DRWAV_ERROR;
75041     #endif
75042     #ifdef EBADR
75043         case EBADR: return DRWAV_ERROR;
75044     #endif
75045     #ifdef EXFULL
75046         case EXFULL: return DRWAV_ERROR;
75047     #endif
75048     #ifdef ENOANO
75049         case ENOANO: return DRWAV_ERROR;
75050     #endif
75051     #ifdef EBADRQC
75052         case EBADRQC: return DRWAV_ERROR;
75053     #endif
75054     #ifdef EBADSLT
75055         case EBADSLT: return DRWAV_ERROR;
75056     #endif
75057     #ifdef EBFONT
75058         case EBFONT: return DRWAV_INVALID_FILE;
75059     #endif
75060     #ifdef ENOSTR
75061         case ENOSTR: return DRWAV_ERROR;
75062     #endif
75063     #ifdef ENODATA
75064         case ENODATA: return DRWAV_NO_DATA_AVAILABLE;
75065     #endif
75066     #ifdef ETIME
75067         case ETIME: return DRWAV_TIMEOUT;
75068     #endif
75069     #ifdef ENOSR
75070         case ENOSR: return DRWAV_NO_DATA_AVAILABLE;
75071     #endif
75072     #ifdef ENONET
75073         case ENONET: return DRWAV_NO_NETWORK;
75074     #endif
75075     #ifdef ENOPKG
75076         case ENOPKG: return DRWAV_ERROR;
75077     #endif
75078     #ifdef EREMOTE
75079         case EREMOTE: return DRWAV_ERROR;
75080     #endif
75081     #ifdef ENOLINK
75082         case ENOLINK: return DRWAV_ERROR;
75083     #endif
75084     #ifdef EADV
75085         case EADV: return DRWAV_ERROR;
75086     #endif
75087     #ifdef ESRMNT
75088         case ESRMNT: return DRWAV_ERROR;
75089     #endif
75090     #ifdef ECOMM
75091         case ECOMM: return DRWAV_ERROR;
75092     #endif
75093     #ifdef EPROTO
75094         case EPROTO: return DRWAV_ERROR;
75095     #endif
75096     #ifdef EMULTIHOP
75097         case EMULTIHOP: return DRWAV_ERROR;
75098     #endif
75099     #ifdef EDOTDOT
75100         case EDOTDOT: return DRWAV_ERROR;
75101     #endif
75102     #ifdef EBADMSG
75103         case EBADMSG: return DRWAV_BAD_MESSAGE;
75104     #endif
75105     #ifdef EOVERFLOW
75106         case EOVERFLOW: return DRWAV_TOO_BIG;
75107     #endif
75108     #ifdef ENOTUNIQ
75109         case ENOTUNIQ: return DRWAV_NOT_UNIQUE;
75110     #endif
75111     #ifdef EBADFD
75112         case EBADFD: return DRWAV_ERROR;
75113     #endif
75114     #ifdef EREMCHG
75115         case EREMCHG: return DRWAV_ERROR;
75116     #endif
75117     #ifdef ELIBACC
75118         case ELIBACC: return DRWAV_ACCESS_DENIED;
75119     #endif
75120     #ifdef ELIBBAD
75121         case ELIBBAD: return DRWAV_INVALID_FILE;
75122     #endif
75123     #ifdef ELIBSCN
75124         case ELIBSCN: return DRWAV_INVALID_FILE;
75125     #endif
75126     #ifdef ELIBMAX
75127         case ELIBMAX: return DRWAV_ERROR;
75128     #endif
75129     #ifdef ELIBEXEC
75130         case ELIBEXEC: return DRWAV_ERROR;
75131     #endif
75132     #ifdef EILSEQ
75133         case EILSEQ: return DRWAV_INVALID_DATA;
75134     #endif
75135     #ifdef ERESTART
75136         case ERESTART: return DRWAV_ERROR;
75137     #endif
75138     #ifdef ESTRPIPE
75139         case ESTRPIPE: return DRWAV_ERROR;
75140     #endif
75141     #ifdef EUSERS
75142         case EUSERS: return DRWAV_ERROR;
75143     #endif
75144     #ifdef ENOTSOCK
75145         case ENOTSOCK: return DRWAV_NOT_SOCKET;
75146     #endif
75147     #ifdef EDESTADDRREQ
75148         case EDESTADDRREQ: return DRWAV_NO_ADDRESS;
75149     #endif
75150     #ifdef EMSGSIZE
75151         case EMSGSIZE: return DRWAV_TOO_BIG;
75152     #endif
75153     #ifdef EPROTOTYPE
75154         case EPROTOTYPE: return DRWAV_BAD_PROTOCOL;
75155     #endif
75156     #ifdef ENOPROTOOPT
75157         case ENOPROTOOPT: return DRWAV_PROTOCOL_UNAVAILABLE;
75158     #endif
75159     #ifdef EPROTONOSUPPORT
75160         case EPROTONOSUPPORT: return DRWAV_PROTOCOL_NOT_SUPPORTED;
75161     #endif
75162     #ifdef ESOCKTNOSUPPORT
75163         case ESOCKTNOSUPPORT: return DRWAV_SOCKET_NOT_SUPPORTED;
75164     #endif
75165     #ifdef EOPNOTSUPP
75166         case EOPNOTSUPP: return DRWAV_INVALID_OPERATION;
75167     #endif
75168     #ifdef EPFNOSUPPORT
75169         case EPFNOSUPPORT: return DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED;
75170     #endif
75171     #ifdef EAFNOSUPPORT
75172         case EAFNOSUPPORT: return DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED;
75173     #endif
75174     #ifdef EADDRINUSE
75175         case EADDRINUSE: return DRWAV_ALREADY_IN_USE;
75176     #endif
75177     #ifdef EADDRNOTAVAIL
75178         case EADDRNOTAVAIL: return DRWAV_ERROR;
75179     #endif
75180     #ifdef ENETDOWN
75181         case ENETDOWN: return DRWAV_NO_NETWORK;
75182     #endif
75183     #ifdef ENETUNREACH
75184         case ENETUNREACH: return DRWAV_NO_NETWORK;
75185     #endif
75186     #ifdef ENETRESET
75187         case ENETRESET: return DRWAV_NO_NETWORK;
75188     #endif
75189     #ifdef ECONNABORTED
75190         case ECONNABORTED: return DRWAV_NO_NETWORK;
75191     #endif
75192     #ifdef ECONNRESET
75193         case ECONNRESET: return DRWAV_CONNECTION_RESET;
75194     #endif
75195     #ifdef ENOBUFS
75196         case ENOBUFS: return DRWAV_NO_SPACE;
75197     #endif
75198     #ifdef EISCONN
75199         case EISCONN: return DRWAV_ALREADY_CONNECTED;
75200     #endif
75201     #ifdef ENOTCONN
75202         case ENOTCONN: return DRWAV_NOT_CONNECTED;
75203     #endif
75204     #ifdef ESHUTDOWN
75205         case ESHUTDOWN: return DRWAV_ERROR;
75206     #endif
75207     #ifdef ETOOMANYREFS
75208         case ETOOMANYREFS: return DRWAV_ERROR;
75209     #endif
75210     #ifdef ETIMEDOUT
75211         case ETIMEDOUT: return DRWAV_TIMEOUT;
75212     #endif
75213     #ifdef ECONNREFUSED
75214         case ECONNREFUSED: return DRWAV_CONNECTION_REFUSED;
75215     #endif
75216     #ifdef EHOSTDOWN
75217         case EHOSTDOWN: return DRWAV_NO_HOST;
75218     #endif
75219     #ifdef EHOSTUNREACH
75220         case EHOSTUNREACH: return DRWAV_NO_HOST;
75221     #endif
75222     #ifdef EALREADY
75223         case EALREADY: return DRWAV_IN_PROGRESS;
75224     #endif
75225     #ifdef EINPROGRESS
75226         case EINPROGRESS: return DRWAV_IN_PROGRESS;
75227     #endif
75228     #ifdef ESTALE
75229         case ESTALE: return DRWAV_INVALID_FILE;
75230     #endif
75231     #ifdef EUCLEAN
75232         case EUCLEAN: return DRWAV_ERROR;
75233     #endif
75234     #ifdef ENOTNAM
75235         case ENOTNAM: return DRWAV_ERROR;
75236     #endif
75237     #ifdef ENAVAIL
75238         case ENAVAIL: return DRWAV_ERROR;
75239     #endif
75240     #ifdef EISNAM
75241         case EISNAM: return DRWAV_ERROR;
75242     #endif
75243     #ifdef EREMOTEIO
75244         case EREMOTEIO: return DRWAV_IO_ERROR;
75245     #endif
75246     #ifdef EDQUOT
75247         case EDQUOT: return DRWAV_NO_SPACE;
75248     #endif
75249     #ifdef ENOMEDIUM
75250         case ENOMEDIUM: return DRWAV_DOES_NOT_EXIST;
75251     #endif
75252     #ifdef EMEDIUMTYPE
75253         case EMEDIUMTYPE: return DRWAV_ERROR;
75254     #endif
75255     #ifdef ECANCELED
75256         case ECANCELED: return DRWAV_CANCELLED;
75257     #endif
75258     #ifdef ENOKEY
75259         case ENOKEY: return DRWAV_ERROR;
75260     #endif
75261     #ifdef EKEYEXPIRED
75262         case EKEYEXPIRED: return DRWAV_ERROR;
75263     #endif
75264     #ifdef EKEYREVOKED
75265         case EKEYREVOKED: return DRWAV_ERROR;
75266     #endif
75267     #ifdef EKEYREJECTED
75268         case EKEYREJECTED: return DRWAV_ERROR;
75269     #endif
75270     #ifdef EOWNERDEAD
75271         case EOWNERDEAD: return DRWAV_ERROR;
75272     #endif
75273     #ifdef ENOTRECOVERABLE
75274         case ENOTRECOVERABLE: return DRWAV_ERROR;
75275     #endif
75276     #ifdef ERFKILL
75277         case ERFKILL: return DRWAV_ERROR;
75278     #endif
75279     #ifdef EHWPOISON
75280         case EHWPOISON: return DRWAV_ERROR;
75281     #endif
75282         default: return DRWAV_ERROR;
75283     }
75284 }
75285 DRWAV_PRIVATE drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
75286 {
75287 #if defined(_MSC_VER) && _MSC_VER >= 1400
75288     errno_t err;
75289 #endif
75290     if (ppFile != NULL) {
75291         *ppFile = NULL;
75292     }
75293     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
75294         return DRWAV_INVALID_ARGS;
75295     }
75296 #if defined(_MSC_VER) && _MSC_VER >= 1400
75297     err = fopen_s(ppFile, pFilePath, pOpenMode);
75298     if (err != 0) {
75299         return drwav_result_from_errno(err);
75300     }
75301 #else
75302 #if defined(_WIN32) || defined(__APPLE__)
75303     *ppFile = fopen(pFilePath, pOpenMode);
75304 #else
75305     #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
75306         *ppFile = fopen64(pFilePath, pOpenMode);
75307     #else
75308         *ppFile = fopen(pFilePath, pOpenMode);
75309     #endif
75310 #endif
75311     if (*ppFile == NULL) {
75312         drwav_result result = drwav_result_from_errno(errno);
75313         if (result == DRWAV_SUCCESS) {
75314             result = DRWAV_ERROR;
75315         }
75316         return result;
75317     }
75318 #endif
75319     return DRWAV_SUCCESS;
75320 }
75321 #if defined(_WIN32)
75322     #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
75323         #define DRWAV_HAS_WFOPEN
75324     #endif
75325 #endif
75326 DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks)
75327 {
75328     if (ppFile != NULL) {
75329         *ppFile = NULL;
75330     }
75331     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
75332         return DRWAV_INVALID_ARGS;
75333     }
75334 #if defined(DRWAV_HAS_WFOPEN)
75335     {
75336     #if defined(_MSC_VER) && _MSC_VER >= 1400
75337         errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
75338         if (err != 0) {
75339             return drwav_result_from_errno(err);
75340         }
75341     #else
75342         *ppFile = _wfopen(pFilePath, pOpenMode);
75343         if (*ppFile == NULL) {
75344             return drwav_result_from_errno(errno);
75345         }
75346     #endif
75347         (void)pAllocationCallbacks;
75348     }
75349 #else
75350     {
75351         mbstate_t mbs;
75352         size_t lenMB;
75353         const wchar_t* pFilePathTemp = pFilePath;
75354         char* pFilePathMB = NULL;
75355         char pOpenModeMB[32] = {0};
75356         DRWAV_ZERO_OBJECT(&mbs);
75357         lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
75358         if (lenMB == (size_t)-1) {
75359             return drwav_result_from_errno(errno);
75360         }
75361         pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
75362         if (pFilePathMB == NULL) {
75363             return DRWAV_OUT_OF_MEMORY;
75364         }
75365         pFilePathTemp = pFilePath;
75366         DRWAV_ZERO_OBJECT(&mbs);
75367         wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
75368         {
75369             size_t i = 0;
75370             for (;;) {
75371                 if (pOpenMode[i] == 0) {
75372                     pOpenModeMB[i] = '\0';
75373                     break;
75374                 }
75375                 pOpenModeMB[i] = (char)pOpenMode[i];
75376                 i += 1;
75377             }
75378         }
75379         *ppFile = fopen(pFilePathMB, pOpenModeMB);
75380         drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
75381     }
75382     if (*ppFile == NULL) {
75383         return DRWAV_ERROR;
75384     }
75385 #endif
75386     return DRWAV_SUCCESS;
75387 }
75388 DRWAV_PRIVATE size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
75389 {
75390     return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
75391 }
75392 DRWAV_PRIVATE size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite)
75393 {
75394     return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData);
75395 }
75396 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
75397 {
75398     return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
75399 }
75400 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
75401 {
75402     return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
75403 }
75404 DRWAV_PRIVATE drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFile, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, drwav_metadata_type allowedMetadataTypes, const drwav_allocation_callbacks* pAllocationCallbacks)
75405 {
75406     drwav_bool32 result;
75407     result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
75408     if (result != DRWAV_TRUE) {
75409         fclose(pFile);
75410         return result;
75411     }
75412     pWav->allowedMetadataTypes = allowedMetadataTypes;
75413     result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
75414     if (result != DRWAV_TRUE) {
75415         fclose(pFile);
75416         return result;
75417     }
75418     return DRWAV_TRUE;
75419 }
75420 DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
75421 {
75422     FILE* pFile;
75423     if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
75424         return DRWAV_FALSE;
75425     }
75426     return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, drwav_metadata_type_none, pAllocationCallbacks);
75427 }
75428 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
75429 {
75430     return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
75431 }
75432 DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
75433 {
75434     FILE* pFile;
75435     if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
75436         return DRWAV_FALSE;
75437     }
75438     return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, drwav_metadata_type_none, pAllocationCallbacks);
75439 }
75440 DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
75441 {
75442     FILE* pFile;
75443     if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
75444         return DRWAV_FALSE;
75445     }
75446     return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags, drwav_metadata_type_all_including_unknown, pAllocationCallbacks);
75447 }
75448 DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
75449 {
75450     FILE* pFile;
75451     if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
75452         return DRWAV_FALSE;
75453     }
75454     return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags, drwav_metadata_type_all_including_unknown, pAllocationCallbacks);
75455 }
75456 DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
75457 {
75458     drwav_bool32 result;
75459     result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
75460     if (result != DRWAV_TRUE) {
75461         fclose(pFile);
75462         return result;
75463     }
75464     result = drwav_init_write__internal(pWav, pFormat, totalSampleCount);
75465     if (result != DRWAV_TRUE) {
75466         fclose(pFile);
75467         return result;
75468     }
75469     return DRWAV_TRUE;
75470 }
75471 DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
75472 {
75473     FILE* pFile;
75474     if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) {
75475         return DRWAV_FALSE;
75476     }
75477     return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
75478 }
75479 DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
75480 {
75481     FILE* pFile;
75482     if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) {
75483         return DRWAV_FALSE;
75484     }
75485     return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
75486 }
75487 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
75488 {
75489     return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
75490 }
75491 DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
75492 {
75493     return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
75494 }
75495 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
75496 {
75497     if (pFormat == NULL) {
75498         return DRWAV_FALSE;
75499     }
75500     return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
75501 }
75502 DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
75503 {
75504     return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
75505 }
75506 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
75507 {
75508     return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
75509 }
75510 DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
75511 {
75512     if (pFormat == NULL) {
75513         return DRWAV_FALSE;
75514     }
75515     return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
75516 }
75517 #endif
75518 DRWAV_PRIVATE size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
75519 {
75520     drwav* pWav = (drwav*)pUserData;
75521     size_t bytesRemaining;
75522     DRWAV_ASSERT(pWav != NULL);
75523     DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos);
75524     bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos;
75525     if (bytesToRead > bytesRemaining) {
75526         bytesToRead = bytesRemaining;
75527     }
75528     if (bytesToRead > 0) {
75529         DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead);
75530         pWav->memoryStream.currentReadPos += bytesToRead;
75531     }
75532     return bytesToRead;
75533 }
75534 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
75535 {
75536     drwav* pWav = (drwav*)pUserData;
75537     DRWAV_ASSERT(pWav != NULL);
75538     if (origin == drwav_seek_origin_current) {
75539         if (offset > 0) {
75540             if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) {
75541                 return DRWAV_FALSE;
75542             }
75543         } else {
75544             if (pWav->memoryStream.currentReadPos < (size_t)-offset) {
75545                 return DRWAV_FALSE;
75546             }
75547         }
75548         pWav->memoryStream.currentReadPos += offset;
75549     } else {
75550         if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) {
75551             pWav->memoryStream.currentReadPos = offset;
75552         } else {
75553             return DRWAV_FALSE;
75554         }
75555     }
75556     return DRWAV_TRUE;
75557 }
75558 DRWAV_PRIVATE size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite)
75559 {
75560     drwav* pWav = (drwav*)pUserData;
75561     size_t bytesRemaining;
75562     DRWAV_ASSERT(pWav != NULL);
75563     DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos);
75564     bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos;
75565     if (bytesRemaining < bytesToWrite) {
75566         void* pNewData;
75567         size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2;
75568         if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) {
75569             newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite;
75570         }
75571         pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks);
75572         if (pNewData == NULL) {
75573             return 0;
75574         }
75575         *pWav->memoryStreamWrite.ppData = pNewData;
75576         pWav->memoryStreamWrite.dataCapacity = newDataCapacity;
75577     }
75578     DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite);
75579     pWav->memoryStreamWrite.currentWritePos += bytesToWrite;
75580     if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) {
75581         pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos;
75582     }
75583     *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize;
75584     return bytesToWrite;
75585 }
75586 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
75587 {
75588     drwav* pWav = (drwav*)pUserData;
75589     DRWAV_ASSERT(pWav != NULL);
75590     if (origin == drwav_seek_origin_current) {
75591         if (offset > 0) {
75592             if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) {
75593                 offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos);
75594             }
75595         } else {
75596             if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) {
75597                 offset = -(int)pWav->memoryStreamWrite.currentWritePos;
75598             }
75599         }
75600         pWav->memoryStreamWrite.currentWritePos += offset;
75601     } else {
75602         if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) {
75603             pWav->memoryStreamWrite.currentWritePos = offset;
75604         } else {
75605             pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize;
75606         }
75607     }
75608     return DRWAV_TRUE;
75609 }
75610 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks)
75611 {
75612     return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks);
75613 }
75614 DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
75615 {
75616     if (data == NULL || dataSize == 0) {
75617         return DRWAV_FALSE;
75618     }
75619     if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
75620         return DRWAV_FALSE;
75621     }
75622     pWav->memoryStream.data = (const drwav_uint8*)data;
75623     pWav->memoryStream.dataSize = dataSize;
75624     pWav->memoryStream.currentReadPos = 0;
75625     return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
75626 }
75627 DRWAV_API drwav_bool32 drwav_init_memory_with_metadata(drwav* pWav, const void* data, size_t dataSize, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
75628 {
75629     if (data == NULL || dataSize == 0) {
75630         return DRWAV_FALSE;
75631     }
75632     if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
75633         return DRWAV_FALSE;
75634     }
75635     pWav->memoryStream.data = (const drwav_uint8*)data;
75636     pWav->memoryStream.dataSize = dataSize;
75637     pWav->memoryStream.currentReadPos = 0;
75638     pWav->allowedMetadataTypes = drwav_metadata_type_all_including_unknown;
75639     return drwav_init__internal(pWav, NULL, NULL, flags);
75640 }
75641 DRWAV_PRIVATE drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
75642 {
75643     if (ppData == NULL || pDataSize == NULL) {
75644         return DRWAV_FALSE;
75645     }
75646     *ppData = NULL;
75647     *pDataSize = 0;
75648     if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) {
75649         return DRWAV_FALSE;
75650     }
75651     pWav->memoryStreamWrite.ppData = ppData;
75652     pWav->memoryStreamWrite.pDataSize = pDataSize;
75653     pWav->memoryStreamWrite.dataSize = 0;
75654     pWav->memoryStreamWrite.dataCapacity = 0;
75655     pWav->memoryStreamWrite.currentWritePos = 0;
75656     return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
75657 }
75658 DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
75659 {
75660     return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
75661 }
75662 DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
75663 {
75664     return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
75665 }
75666 DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
75667 {
75668     if (pFormat == NULL) {
75669         return DRWAV_FALSE;
75670     }
75671     return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
75672 }
75673 DRWAV_API drwav_result drwav_uninit(drwav* pWav)
75674 {
75675     drwav_result result = DRWAV_SUCCESS;
75676     if (pWav == NULL) {
75677         return DRWAV_INVALID_ARGS;
75678     }
75679     if (pWav->onWrite != NULL) {
75680         drwav_uint32 paddingSize = 0;
75681         if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
75682             paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize);
75683         } else {
75684             paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize);
75685         }
75686         if (paddingSize > 0) {
75687             drwav_uint64 paddingData = 0;
75688             drwav__write(pWav, &paddingData, paddingSize);
75689         }
75690         if (pWav->onSeek && !pWav->isSequentialWrite) {
75691             if (pWav->container == drwav_container_riff) {
75692                 if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) {
75693                     drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
75694                     drwav__write_u32ne_to_le(pWav, riffChunkSize);
75695                 }
75696                 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, drwav_seek_origin_start)) {
75697                     drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
75698                     drwav__write_u32ne_to_le(pWav, dataChunkSize);
75699                 }
75700             } else if (pWav->container == drwav_container_w64) {
75701                 if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
75702                     drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
75703                     drwav__write_u64ne_to_le(pWav, riffChunkSize);
75704                 }
75705                 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, drwav_seek_origin_start)) {
75706                     drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
75707                     drwav__write_u64ne_to_le(pWav, dataChunkSize);
75708                 }
75709             } else if (pWav->container == drwav_container_rf64) {
75710                 int ds64BodyPos = 12 + 8;
75711                 if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) {
75712                     drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
75713                     drwav__write_u64ne_to_le(pWav, riffChunkSize);
75714                 }
75715                 if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) {
75716                     drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
75717                     drwav__write_u64ne_to_le(pWav, dataChunkSize);
75718                 }
75719             }
75720         }
75721         if (pWav->isSequentialWrite) {
75722             if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) {
75723                 result = DRWAV_INVALID_FILE;
75724             }
75725         }
75726     } else {
75727         if (pWav->pMetadata != NULL) {
75728             pWav->allocationCallbacks.onFree(pWav->pMetadata, pWav->allocationCallbacks.pUserData);
75729         }
75730     }
75731 #ifndef DR_WAV_NO_STDIO
75732     if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) {
75733         fclose((FILE*)pWav->pUserData);
75734     }
75735 #endif
75736     return result;
75737 }
75738 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut)
75739 {
75740     size_t bytesRead;
75741     drwav_uint32 bytesPerFrame;
75742     if (pWav == NULL || bytesToRead == 0) {
75743         return 0;
75744     }
75745     if (bytesToRead > pWav->bytesRemaining) {
75746         bytesToRead = (size_t)pWav->bytesRemaining;
75747     }
75748     if (bytesToRead == 0) {
75749         return 0;
75750     }
75751     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
75752     if (bytesPerFrame == 0) {
75753         return 0;
75754     }
75755     if (pBufferOut != NULL) {
75756         bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead);
75757     } else {
75758         bytesRead = 0;
75759         while (bytesRead < bytesToRead) {
75760             size_t bytesToSeek = (bytesToRead - bytesRead);
75761             if (bytesToSeek > 0x7FFFFFFF) {
75762                 bytesToSeek = 0x7FFFFFFF;
75763             }
75764             if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) {
75765                 break;
75766             }
75767             bytesRead += bytesToSeek;
75768         }
75769         while (bytesRead < bytesToRead) {
75770             drwav_uint8 buffer[4096];
75771             size_t bytesSeeked;
75772             size_t bytesToSeek = (bytesToRead - bytesRead);
75773             if (bytesToSeek > sizeof(buffer)) {
75774                 bytesToSeek = sizeof(buffer);
75775             }
75776             bytesSeeked = pWav->onRead(pWav->pUserData, buffer, bytesToSeek);
75777             bytesRead += bytesSeeked;
75778             if (bytesSeeked < bytesToSeek) {
75779                 break;
75780             }
75781         }
75782     }
75783     pWav->readCursorInPCMFrames += bytesRead / bytesPerFrame;
75784     pWav->bytesRemaining -= bytesRead;
75785     return bytesRead;
75786 }
75787 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
75788 {
75789     drwav_uint32 bytesPerFrame;
75790     drwav_uint64 bytesToRead;
75791     if (pWav == NULL || framesToRead == 0) {
75792         return 0;
75793     }
75794     if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
75795         return 0;
75796     }
75797     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
75798     if (bytesPerFrame == 0) {
75799         return 0;
75800     }
75801     bytesToRead = framesToRead * bytesPerFrame;
75802     if (bytesToRead > DRWAV_SIZE_MAX) {
75803         bytesToRead = (DRWAV_SIZE_MAX / bytesPerFrame) * bytesPerFrame;
75804     }
75805     if (bytesToRead == 0) {
75806         return 0;
75807     }
75808     return drwav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame;
75809 }
75810 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
75811 {
75812     drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
75813     if (pBufferOut != NULL) {
75814         drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
75815         if (bytesPerFrame == 0) {
75816             return 0;
75817         }
75818         drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, bytesPerFrame/pWav->channels, pWav->translatedFormatTag);
75819     }
75820     return framesRead;
75821 }
75822 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
75823 {
75824     if (drwav__is_little_endian()) {
75825         return drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
75826     } else {
75827         return drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut);
75828     }
75829 }
75830 DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav)
75831 {
75832     if (pWav->onWrite != NULL) {
75833         return DRWAV_FALSE;
75834     }
75835     if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) {
75836         return DRWAV_FALSE;
75837     }
75838     if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
75839         if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
75840             DRWAV_ZERO_OBJECT(&pWav->msadpcm);
75841         } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
75842             DRWAV_ZERO_OBJECT(&pWav->ima);
75843         } else {
75844             DRWAV_ASSERT(DRWAV_FALSE);
75845         }
75846     }
75847     pWav->readCursorInPCMFrames = 0;
75848     pWav->bytesRemaining = pWav->dataChunkDataSize;
75849     return DRWAV_TRUE;
75850 }
75851 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex)
75852 {
75853     if (pWav == NULL || pWav->onSeek == NULL) {
75854         return DRWAV_FALSE;
75855     }
75856     if (pWav->onWrite != NULL) {
75857         return DRWAV_FALSE;
75858     }
75859     if (pWav->totalPCMFrameCount == 0) {
75860         return DRWAV_TRUE;
75861     }
75862     if (targetFrameIndex >= pWav->totalPCMFrameCount) {
75863         targetFrameIndex  = pWav->totalPCMFrameCount - 1;
75864     }
75865     if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
75866         if (targetFrameIndex < pWav->readCursorInPCMFrames) {
75867             if (!drwav_seek_to_first_pcm_frame(pWav)) {
75868                 return DRWAV_FALSE;
75869             }
75870         }
75871         if (targetFrameIndex > pWav->readCursorInPCMFrames) {
75872             drwav_uint64 offsetInFrames = targetFrameIndex - pWav->readCursorInPCMFrames;
75873             drwav_int16 devnull[2048];
75874             while (offsetInFrames > 0) {
75875                 drwav_uint64 framesRead = 0;
75876                 drwav_uint64 framesToRead = offsetInFrames;
75877                 if (framesToRead > drwav_countof(devnull)/pWav->channels) {
75878                     framesToRead = drwav_countof(devnull)/pWav->channels;
75879                 }
75880                 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
75881                     framesRead = drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull);
75882                 } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
75883                     framesRead = drwav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull);
75884                 } else {
75885                     DRWAV_ASSERT(DRWAV_FALSE);
75886                 }
75887                 if (framesRead != framesToRead) {
75888                     return DRWAV_FALSE;
75889                 }
75890                 offsetInFrames -= framesRead;
75891             }
75892         }
75893     } else {
75894         drwav_uint64 totalSizeInBytes;
75895         drwav_uint64 currentBytePos;
75896         drwav_uint64 targetBytePos;
75897         drwav_uint64 offset;
75898         drwav_uint32 bytesPerFrame;
75899         bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
75900         if (bytesPerFrame == 0) {
75901             return DRWAV_FALSE;
75902         }
75903         totalSizeInBytes = pWav->totalPCMFrameCount * bytesPerFrame;
75904         DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining);
75905         currentBytePos = totalSizeInBytes - pWav->bytesRemaining;
75906         targetBytePos  = targetFrameIndex * bytesPerFrame;
75907         if (currentBytePos < targetBytePos) {
75908             offset = (targetBytePos - currentBytePos);
75909         } else {
75910             if (!drwav_seek_to_first_pcm_frame(pWav)) {
75911                 return DRWAV_FALSE;
75912             }
75913             offset = targetBytePos;
75914         }
75915         while (offset > 0) {
75916             int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
75917             if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) {
75918                 return DRWAV_FALSE;
75919             }
75920             pWav->readCursorInPCMFrames += offset32 / bytesPerFrame;
75921             pWav->bytesRemaining        -= offset32;
75922             offset                      -= offset32;
75923         }
75924     }
75925     return DRWAV_TRUE;
75926 }
75927 DRWAV_API drwav_result drwav_get_cursor_in_pcm_frames(drwav* pWav, drwav_uint64* pCursor)
75928 {
75929     if (pCursor == NULL) {
75930         return DRWAV_INVALID_ARGS;
75931     }
75932     *pCursor = 0;
75933     if (pWav == NULL) {
75934         return DRWAV_INVALID_ARGS;
75935     }
75936     *pCursor = pWav->readCursorInPCMFrames;
75937     return DRWAV_SUCCESS;
75938 }
75939 DRWAV_API drwav_result drwav_get_length_in_pcm_frames(drwav* pWav, drwav_uint64* pLength)
75940 {
75941     if (pLength == NULL) {
75942         return DRWAV_INVALID_ARGS;
75943     }
75944     *pLength = 0;
75945     if (pWav == NULL) {
75946         return DRWAV_INVALID_ARGS;
75947     }
75948     *pLength = pWav->totalPCMFrameCount;
75949     return DRWAV_SUCCESS;
75950 }
75951 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData)
75952 {
75953     size_t bytesWritten;
75954     if (pWav == NULL || bytesToWrite == 0 || pData == NULL) {
75955         return 0;
75956     }
75957     bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite);
75958     pWav->dataChunkDataSize += bytesWritten;
75959     return bytesWritten;
75960 }
75961 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
75962 {
75963     drwav_uint64 bytesToWrite;
75964     drwav_uint64 bytesWritten;
75965     const drwav_uint8* pRunningData;
75966     if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
75967         return 0;
75968     }
75969     bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
75970     if (bytesToWrite > DRWAV_SIZE_MAX) {
75971         return 0;
75972     }
75973     bytesWritten = 0;
75974     pRunningData = (const drwav_uint8*)pData;
75975     while (bytesToWrite > 0) {
75976         size_t bytesJustWritten;
75977         drwav_uint64 bytesToWriteThisIteration;
75978         bytesToWriteThisIteration = bytesToWrite;
75979         DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX);
75980         bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData);
75981         if (bytesJustWritten == 0) {
75982             break;
75983         }
75984         bytesToWrite -= bytesJustWritten;
75985         bytesWritten += bytesJustWritten;
75986         pRunningData += bytesJustWritten;
75987     }
75988     return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
75989 }
75990 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
75991 {
75992     drwav_uint64 bytesToWrite;
75993     drwav_uint64 bytesWritten;
75994     drwav_uint32 bytesPerSample;
75995     const drwav_uint8* pRunningData;
75996     if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
75997         return 0;
75998     }
75999     bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
76000     if (bytesToWrite > DRWAV_SIZE_MAX) {
76001         return 0;
76002     }
76003     bytesWritten = 0;
76004     pRunningData = (const drwav_uint8*)pData;
76005     bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels;
76006     if (bytesPerSample == 0) {
76007         return 0;
76008     }
76009     while (bytesToWrite > 0) {
76010         drwav_uint8 temp[4096];
76011         drwav_uint32 sampleCount;
76012         size_t bytesJustWritten;
76013         drwav_uint64 bytesToWriteThisIteration;
76014         bytesToWriteThisIteration = bytesToWrite;
76015         DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX);
76016         sampleCount = sizeof(temp)/bytesPerSample;
76017         if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) {
76018             bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample;
76019         }
76020         DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration);
76021         drwav__bswap_samples(temp, sampleCount, bytesPerSample, pWav->translatedFormatTag);
76022         bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp);
76023         if (bytesJustWritten == 0) {
76024             break;
76025         }
76026         bytesToWrite -= bytesJustWritten;
76027         bytesWritten += bytesJustWritten;
76028         pRunningData += bytesJustWritten;
76029     }
76030     return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
76031 }
76032 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
76033 {
76034     if (drwav__is_little_endian()) {
76035         return drwav_write_pcm_frames_le(pWav, framesToWrite, pData);
76036     } else {
76037         return drwav_write_pcm_frames_be(pWav, framesToWrite, pData);
76038     }
76039 }
76040 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
76041 {
76042     drwav_uint64 totalFramesRead = 0;
76043     DRWAV_ASSERT(pWav != NULL);
76044     DRWAV_ASSERT(framesToRead > 0);
76045     while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
76046         DRWAV_ASSERT(framesToRead > 0);
76047         if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) {
76048             if (pWav->channels == 1) {
76049                 drwav_uint8 header[7];
76050                 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
76051                     return totalFramesRead;
76052                 }
76053                 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
76054                 pWav->msadpcm.predictor[0]     = header[0];
76055                 pWav->msadpcm.delta[0]         = drwav_bytes_to_s16(header + 1);
76056                 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 3);
76057                 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 5);
76058                 pWav->msadpcm.cachedFrames[2]  = pWav->msadpcm.prevFrames[0][0];
76059                 pWav->msadpcm.cachedFrames[3]  = pWav->msadpcm.prevFrames[0][1];
76060                 pWav->msadpcm.cachedFrameCount = 2;
76061             } else {
76062                 drwav_uint8 header[14];
76063                 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
76064                     return totalFramesRead;
76065                 }
76066                 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
76067                 pWav->msadpcm.predictor[0] = header[0];
76068                 pWav->msadpcm.predictor[1] = header[1];
76069                 pWav->msadpcm.delta[0] = drwav_bytes_to_s16(header + 2);
76070                 pWav->msadpcm.delta[1] = drwav_bytes_to_s16(header + 4);
76071                 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 6);
76072                 pWav->msadpcm.prevFrames[1][1] = (drwav_int32)drwav_bytes_to_s16(header + 8);
76073                 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 10);
76074                 pWav->msadpcm.prevFrames[1][0] = (drwav_int32)drwav_bytes_to_s16(header + 12);
76075                 pWav->msadpcm.cachedFrames[0] = pWav->msadpcm.prevFrames[0][0];
76076                 pWav->msadpcm.cachedFrames[1] = pWav->msadpcm.prevFrames[1][0];
76077                 pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1];
76078                 pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1];
76079                 pWav->msadpcm.cachedFrameCount = 2;
76080             }
76081         }
76082         while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
76083             if (pBufferOut != NULL) {
76084                 drwav_uint32 iSample = 0;
76085                 for (iSample = 0; iSample < pWav->channels; iSample += 1) {
76086                     pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample];
76087                 }
76088                 pBufferOut += pWav->channels;
76089             }
76090             framesToRead    -= 1;
76091             totalFramesRead += 1;
76092             pWav->readCursorInPCMFrames += 1;
76093             pWav->msadpcm.cachedFrameCount -= 1;
76094         }
76095         if (framesToRead == 0) {
76096             break;
76097         }
76098         if (pWav->msadpcm.cachedFrameCount == 0) {
76099             if (pWav->msadpcm.bytesRemainingInBlock == 0) {
76100                 continue;
76101             } else {
76102                 static drwav_int32 adaptationTable[] = {
76103                     230, 230, 230, 230, 307, 409, 512, 614,
76104                     768, 614, 512, 409, 307, 230, 230, 230
76105                 };
76106                 static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460,  392 };
76107                 static drwav_int32 coeff2Table[] = { 0,  -256, 0, 64,  0,  -208, -232 };
76108                 drwav_uint8 nibbles;
76109                 drwav_int32 nibble0;
76110                 drwav_int32 nibble1;
76111                 if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) {
76112                     return totalFramesRead;
76113                 }
76114                 pWav->msadpcm.bytesRemainingInBlock -= 1;
76115                 nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; }
76116                 nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; }
76117                 if (pWav->channels == 1) {
76118                     drwav_int32 newSample0;
76119                     drwav_int32 newSample1;
76120                     newSample0  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
76121                     newSample0 += nibble0 * pWav->msadpcm.delta[0];
76122                     newSample0  = drwav_clamp(newSample0, -32768, 32767);
76123                     pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
76124                     if (pWav->msadpcm.delta[0] < 16) {
76125                         pWav->msadpcm.delta[0] = 16;
76126                     }
76127                     pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
76128                     pWav->msadpcm.prevFrames[0][1] = newSample0;
76129                     newSample1  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
76130                     newSample1 += nibble1 * pWav->msadpcm.delta[0];
76131                     newSample1  = drwav_clamp(newSample1, -32768, 32767);
76132                     pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8;
76133                     if (pWav->msadpcm.delta[0] < 16) {
76134                         pWav->msadpcm.delta[0] = 16;
76135                     }
76136                     pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
76137                     pWav->msadpcm.prevFrames[0][1] = newSample1;
76138                     pWav->msadpcm.cachedFrames[2] = newSample0;
76139                     pWav->msadpcm.cachedFrames[3] = newSample1;
76140                     pWav->msadpcm.cachedFrameCount = 2;
76141                 } else {
76142                     drwav_int32 newSample0;
76143                     drwav_int32 newSample1;
76144                     newSample0  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
76145                     newSample0 += nibble0 * pWav->msadpcm.delta[0];
76146                     newSample0  = drwav_clamp(newSample0, -32768, 32767);
76147                     pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
76148                     if (pWav->msadpcm.delta[0] < 16) {
76149                         pWav->msadpcm.delta[0] = 16;
76150                     }
76151                     pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
76152                     pWav->msadpcm.prevFrames[0][1] = newSample0;
76153                     newSample1  = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8;
76154                     newSample1 += nibble1 * pWav->msadpcm.delta[1];
76155                     newSample1  = drwav_clamp(newSample1, -32768, 32767);
76156                     pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8;
76157                     if (pWav->msadpcm.delta[1] < 16) {
76158                         pWav->msadpcm.delta[1] = 16;
76159                     }
76160                     pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1];
76161                     pWav->msadpcm.prevFrames[1][1] = newSample1;
76162                     pWav->msadpcm.cachedFrames[2] = newSample0;
76163                     pWav->msadpcm.cachedFrames[3] = newSample1;
76164                     pWav->msadpcm.cachedFrameCount = 1;
76165                 }
76166             }
76167         }
76168     }
76169     return totalFramesRead;
76170 }
76171 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
76172 {
76173     drwav_uint64 totalFramesRead = 0;
76174     drwav_uint32 iChannel;
76175     static drwav_int32 indexTable[16] = {
76176         -1, -1, -1, -1, 2, 4, 6, 8,
76177         -1, -1, -1, -1, 2, 4, 6, 8
76178     };
76179     static drwav_int32 stepTable[89] = {
76180         7,     8,     9,     10,    11,    12,    13,    14,    16,    17,
76181         19,    21,    23,    25,    28,    31,    34,    37,    41,    45,
76182         50,    55,    60,    66,    73,    80,    88,    97,    107,   118,
76183         130,   143,   157,   173,   190,   209,   230,   253,   279,   307,
76184         337,   371,   408,   449,   494,   544,   598,   658,   724,   796,
76185         876,   963,   1060,  1166,  1282,  1411,  1552,  1707,  1878,  2066,
76186         2272,  2499,  2749,  3024,  3327,  3660,  4026,  4428,  4871,  5358,
76187         5894,  6484,  7132,  7845,  8630,  9493,  10442, 11487, 12635, 13899,
76188         15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
76189     };
76190     DRWAV_ASSERT(pWav != NULL);
76191     DRWAV_ASSERT(framesToRead > 0);
76192     while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
76193         DRWAV_ASSERT(framesToRead > 0);
76194         if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) {
76195             if (pWav->channels == 1) {
76196                 drwav_uint8 header[4];
76197                 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
76198                     return totalFramesRead;
76199                 }
76200                 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
76201                 if (header[2] >= drwav_countof(stepTable)) {
76202                     pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
76203                     pWav->ima.bytesRemainingInBlock = 0;
76204                     return totalFramesRead;
76205                 }
76206                 pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0);
76207                 pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1);
76208                 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0];
76209                 pWav->ima.cachedFrameCount = 1;
76210             } else {
76211                 drwav_uint8 header[8];
76212                 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
76213                     return totalFramesRead;
76214                 }
76215                 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
76216                 if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) {
76217                     pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
76218                     pWav->ima.bytesRemainingInBlock = 0;
76219                     return totalFramesRead;
76220                 }
76221                 pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0);
76222                 pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1);
76223                 pWav->ima.predictor[1] = drwav_bytes_to_s16(header + 4);
76224                 pWav->ima.stepIndex[1] = drwav_clamp(header[6], 0, (drwav_int32)drwav_countof(stepTable)-1);
76225                 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0];
76226                 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1];
76227                 pWav->ima.cachedFrameCount = 1;
76228             }
76229         }
76230         while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
76231             if (pBufferOut != NULL) {
76232                 drwav_uint32 iSample;
76233                 for (iSample = 0; iSample < pWav->channels; iSample += 1) {
76234                     pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample];
76235                 }
76236                 pBufferOut += pWav->channels;
76237             }
76238             framesToRead    -= 1;
76239             totalFramesRead += 1;
76240             pWav->readCursorInPCMFrames += 1;
76241             pWav->ima.cachedFrameCount -= 1;
76242         }
76243         if (framesToRead == 0) {
76244             break;
76245         }
76246         if (pWav->ima.cachedFrameCount == 0) {
76247             if (pWav->ima.bytesRemainingInBlock == 0) {
76248                 continue;
76249             } else {
76250                 pWav->ima.cachedFrameCount = 8;
76251                 for (iChannel = 0; iChannel < pWav->channels; ++iChannel) {
76252                     drwav_uint32 iByte;
76253                     drwav_uint8 nibbles[4];
76254                     if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) {
76255                         pWav->ima.cachedFrameCount = 0;
76256                         return totalFramesRead;
76257                     }
76258                     pWav->ima.bytesRemainingInBlock -= 4;
76259                     for (iByte = 0; iByte < 4; ++iByte) {
76260                         drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0);
76261                         drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4);
76262                         drwav_int32 step      = stepTable[pWav->ima.stepIndex[iChannel]];
76263                         drwav_int32 predictor = pWav->ima.predictor[iChannel];
76264                         drwav_int32      diff  = step >> 3;
76265                         if (nibble0 & 1) diff += step >> 2;
76266                         if (nibble0 & 2) diff += step >> 1;
76267                         if (nibble0 & 4) diff += step;
76268                         if (nibble0 & 8) diff  = -diff;
76269                         predictor = drwav_clamp(predictor + diff, -32768, 32767);
76270                         pWav->ima.predictor[iChannel] = predictor;
76271                         pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1);
76272                         pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor;
76273                         step      = stepTable[pWav->ima.stepIndex[iChannel]];
76274                         predictor = pWav->ima.predictor[iChannel];
76275                                          diff  = step >> 3;
76276                         if (nibble1 & 1) diff += step >> 2;
76277                         if (nibble1 & 2) diff += step >> 1;
76278                         if (nibble1 & 4) diff += step;
76279                         if (nibble1 & 8) diff  = -diff;
76280                         predictor = drwav_clamp(predictor + diff, -32768, 32767);
76281                         pWav->ima.predictor[iChannel] = predictor;
76282                         pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1);
76283                         pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor;
76284                     }
76285                 }
76286             }
76287         }
76288     }
76289     return totalFramesRead;
76290 }
76291 #ifndef DR_WAV_NO_CONVERSION_API
76292 static unsigned short g_drwavAlawTable[256] = {
76293     0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580,
76294     0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0,
76295     0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600,
76296     0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00,
76297     0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58,
76298     0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58,
76299     0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960,
76300     0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0,
76301     0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80,
76302     0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40,
76303     0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00,
76304     0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500,
76305     0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8,
76306     0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8,
76307     0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0,
76308     0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350
76309 };
76310 static unsigned short g_drwavMulawTable[256] = {
76311     0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84,
76312     0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84,
76313     0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004,
76314     0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844,
76315     0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64,
76316     0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74,
76317     0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C,
76318     0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000,
76319     0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C,
76320     0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C,
76321     0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC,
76322     0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC,
76323     0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C,
76324     0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C,
76325     0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084,
76326     0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
76327 };
76328 static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn)
76329 {
76330     return (short)g_drwavAlawTable[sampleIn];
76331 }
76332 static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn)
76333 {
76334     return (short)g_drwavMulawTable[sampleIn];
76335 }
76336 DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
76337 {
76338     size_t i;
76339     if (bytesPerSample == 1) {
76340         drwav_u8_to_s16(pOut, pIn, totalSampleCount);
76341         return;
76342     }
76343     if (bytesPerSample == 2) {
76344         for (i = 0; i < totalSampleCount; ++i) {
76345            *pOut++ = ((const drwav_int16*)pIn)[i];
76346         }
76347         return;
76348     }
76349     if (bytesPerSample == 3) {
76350         drwav_s24_to_s16(pOut, pIn, totalSampleCount);
76351         return;
76352     }
76353     if (bytesPerSample == 4) {
76354         drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount);
76355         return;
76356     }
76357     if (bytesPerSample > 8) {
76358         DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
76359         return;
76360     }
76361     for (i = 0; i < totalSampleCount; ++i) {
76362         drwav_uint64 sample = 0;
76363         unsigned int shift  = (8 - bytesPerSample) * 8;
76364         unsigned int j;
76365         for (j = 0; j < bytesPerSample; j += 1) {
76366             DRWAV_ASSERT(j < 8);
76367             sample |= (drwav_uint64)(pIn[j]) << shift;
76368             shift  += 8;
76369         }
76370         pIn += j;
76371         *pOut++ = (drwav_int16)((drwav_int64)sample >> 48);
76372     }
76373 }
76374 DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
76375 {
76376     if (bytesPerSample == 4) {
76377         drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount);
76378         return;
76379     } else if (bytesPerSample == 8) {
76380         drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount);
76381         return;
76382     } else {
76383         DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
76384         return;
76385     }
76386 }
76387 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
76388 {
76389     drwav_uint64 totalFramesRead;
76390     drwav_uint8 sampleData[4096] = {0};
76391     drwav_uint32 bytesPerFrame;
76392     drwav_uint32 bytesPerSample;
76393     drwav_uint64 samplesRead;
76394     if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) {
76395         return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
76396     }
76397     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
76398     if (bytesPerFrame == 0) {
76399         return 0;
76400     }
76401     bytesPerSample = bytesPerFrame / pWav->channels;
76402     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
76403         return 0;
76404     }
76405     totalFramesRead = 0;
76406     while (framesToRead > 0) {
76407         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
76408         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
76409         if (framesRead == 0) {
76410             break;
76411         }
76412         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
76413         samplesRead = framesRead * pWav->channels;
76414         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
76415             DRWAV_ASSERT(DRWAV_FALSE);
76416             break;
76417         }
76418         drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
76419         pBufferOut      += samplesRead;
76420         framesToRead    -= framesRead;
76421         totalFramesRead += framesRead;
76422     }
76423     return totalFramesRead;
76424 }
76425 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
76426 {
76427     drwav_uint64 totalFramesRead;
76428     drwav_uint8 sampleData[4096] = {0};
76429     drwav_uint32 bytesPerFrame;
76430     drwav_uint32 bytesPerSample;
76431     drwav_uint64 samplesRead;
76432     if (pBufferOut == NULL) {
76433         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
76434     }
76435     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
76436     if (bytesPerFrame == 0) {
76437         return 0;
76438     }
76439     bytesPerSample = bytesPerFrame / pWav->channels;
76440     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
76441         return 0;
76442     }
76443     totalFramesRead = 0;
76444     while (framesToRead > 0) {
76445         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
76446         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
76447         if (framesRead == 0) {
76448             break;
76449         }
76450         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
76451         samplesRead = framesRead * pWav->channels;
76452         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
76453             DRWAV_ASSERT(DRWAV_FALSE);
76454             break;
76455         }
76456         drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
76457         pBufferOut      += samplesRead;
76458         framesToRead    -= framesRead;
76459         totalFramesRead += framesRead;
76460     }
76461     return totalFramesRead;
76462 }
76463 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
76464 {
76465     drwav_uint64 totalFramesRead;
76466     drwav_uint8 sampleData[4096] = {0};
76467     drwav_uint32 bytesPerFrame;
76468     drwav_uint32 bytesPerSample;
76469     drwav_uint64 samplesRead;
76470     if (pBufferOut == NULL) {
76471         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
76472     }
76473     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
76474     if (bytesPerFrame == 0) {
76475         return 0;
76476     }
76477     bytesPerSample = bytesPerFrame / pWav->channels;
76478     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
76479         return 0;
76480     }
76481     totalFramesRead = 0;
76482     while (framesToRead > 0) {
76483         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
76484         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
76485         if (framesRead == 0) {
76486             break;
76487         }
76488         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
76489         samplesRead = framesRead * pWav->channels;
76490         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
76491             DRWAV_ASSERT(DRWAV_FALSE);
76492             break;
76493         }
76494         drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead);
76495         pBufferOut      += samplesRead;
76496         framesToRead    -= framesRead;
76497         totalFramesRead += framesRead;
76498     }
76499     return totalFramesRead;
76500 }
76501 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
76502 {
76503     drwav_uint64 totalFramesRead;
76504     drwav_uint8 sampleData[4096] = {0};
76505     drwav_uint32 bytesPerFrame;
76506     drwav_uint32 bytesPerSample;
76507     drwav_uint64 samplesRead;
76508     if (pBufferOut == NULL) {
76509         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
76510     }
76511     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
76512     if (bytesPerFrame == 0) {
76513         return 0;
76514     }
76515     bytesPerSample = bytesPerFrame / pWav->channels;
76516     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
76517         return 0;
76518     }
76519     totalFramesRead = 0;
76520     while (framesToRead > 0) {
76521         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
76522         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
76523         if (framesRead == 0) {
76524             break;
76525         }
76526         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
76527         samplesRead = framesRead * pWav->channels;
76528         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
76529             DRWAV_ASSERT(DRWAV_FALSE);
76530             break;
76531         }
76532         drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead);
76533         pBufferOut      += samplesRead;
76534         framesToRead    -= framesRead;
76535         totalFramesRead += framesRead;
76536     }
76537     return totalFramesRead;
76538 }
76539 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
76540 {
76541     if (pWav == NULL || framesToRead == 0) {
76542         return 0;
76543     }
76544     if (pBufferOut == NULL) {
76545         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
76546     }
76547     if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) {
76548         framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels;
76549     }
76550     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
76551         return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut);
76552     }
76553     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
76554         return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut);
76555     }
76556     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
76557         return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut);
76558     }
76559     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
76560         return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut);
76561     }
76562     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
76563         return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut);
76564     }
76565     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
76566         return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut);
76567     }
76568     return 0;
76569 }
76570 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
76571 {
76572     drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
76573     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
76574         drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
76575     }
76576     return framesRead;
76577 }
76578 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
76579 {
76580     drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
76581     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
76582         drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
76583     }
76584     return framesRead;
76585 }
76586 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
76587 {
76588     int r;
76589     size_t i;
76590     for (i = 0; i < sampleCount; ++i) {
76591         int x = pIn[i];
76592         r = x << 8;
76593         r = r - 32768;
76594         pOut[i] = (short)r;
76595     }
76596 }
76597 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
76598 {
76599     int r;
76600     size_t i;
76601     for (i = 0; i < sampleCount; ++i) {
76602         int x = ((int)(((unsigned int)(((const drwav_uint8*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+2])) << 24)) >> 8;
76603         r = x >> 8;
76604         pOut[i] = (short)r;
76605     }
76606 }
76607 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount)
76608 {
76609     int r;
76610     size_t i;
76611     for (i = 0; i < sampleCount; ++i) {
76612         int x = pIn[i];
76613         r = x >> 16;
76614         pOut[i] = (short)r;
76615     }
76616 }
76617 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount)
76618 {
76619     int r;
76620     size_t i;
76621     for (i = 0; i < sampleCount; ++i) {
76622         float x = pIn[i];
76623         float c;
76624         c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
76625         c = c + 1;
76626         r = (int)(c * 32767.5f);
76627         r = r - 32768;
76628         pOut[i] = (short)r;
76629     }
76630 }
76631 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount)
76632 {
76633     int r;
76634     size_t i;
76635     for (i = 0; i < sampleCount; ++i) {
76636         double x = pIn[i];
76637         double c;
76638         c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
76639         c = c + 1;
76640         r = (int)(c * 32767.5);
76641         r = r - 32768;
76642         pOut[i] = (short)r;
76643     }
76644 }
76645 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
76646 {
76647     size_t i;
76648     for (i = 0; i < sampleCount; ++i) {
76649         pOut[i] = drwav__alaw_to_s16(pIn[i]);
76650     }
76651 }
76652 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
76653 {
76654     size_t i;
76655     for (i = 0; i < sampleCount; ++i) {
76656         pOut[i] = drwav__mulaw_to_s16(pIn[i]);
76657     }
76658 }
76659 DRWAV_PRIVATE void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
76660 {
76661     unsigned int i;
76662     if (bytesPerSample == 1) {
76663         drwav_u8_to_f32(pOut, pIn, sampleCount);
76664         return;
76665     }
76666     if (bytesPerSample == 2) {
76667         drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount);
76668         return;
76669     }
76670     if (bytesPerSample == 3) {
76671         drwav_s24_to_f32(pOut, pIn, sampleCount);
76672         return;
76673     }
76674     if (bytesPerSample == 4) {
76675         drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount);
76676         return;
76677     }
76678     if (bytesPerSample > 8) {
76679         DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
76680         return;
76681     }
76682     for (i = 0; i < sampleCount; ++i) {
76683         drwav_uint64 sample = 0;
76684         unsigned int shift  = (8 - bytesPerSample) * 8;
76685         unsigned int j;
76686         for (j = 0; j < bytesPerSample; j += 1) {
76687             DRWAV_ASSERT(j < 8);
76688             sample |= (drwav_uint64)(pIn[j]) << shift;
76689             shift  += 8;
76690         }
76691         pIn += j;
76692         *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0);
76693     }
76694 }
76695 DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
76696 {
76697     if (bytesPerSample == 4) {
76698         unsigned int i;
76699         for (i = 0; i < sampleCount; ++i) {
76700             *pOut++ = ((const float*)pIn)[i];
76701         }
76702         return;
76703     } else if (bytesPerSample == 8) {
76704         drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount);
76705         return;
76706     } else {
76707         DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
76708         return;
76709     }
76710 }
76711 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
76712 {
76713     drwav_uint64 totalFramesRead;
76714     drwav_uint8 sampleData[4096] = {0};
76715     drwav_uint32 bytesPerFrame;
76716     drwav_uint32 bytesPerSample;
76717     drwav_uint64 samplesRead;
76718     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
76719     if (bytesPerFrame == 0) {
76720         return 0;
76721     }
76722     bytesPerSample = bytesPerFrame / pWav->channels;
76723     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
76724         return 0;
76725     }
76726     totalFramesRead = 0;
76727     while (framesToRead > 0) {
76728         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
76729         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
76730         if (framesRead == 0) {
76731             break;
76732         }
76733         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
76734         samplesRead = framesRead * pWav->channels;
76735         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
76736             DRWAV_ASSERT(DRWAV_FALSE);
76737             break;
76738         }
76739         drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
76740         pBufferOut      += samplesRead;
76741         framesToRead    -= framesRead;
76742         totalFramesRead += framesRead;
76743     }
76744     return totalFramesRead;
76745 }
76746 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
76747 {
76748     drwav_uint64 totalFramesRead;
76749     drwav_int16 samples16[2048];
76750     totalFramesRead = 0;
76751     while (framesToRead > 0) {
76752         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels);
76753         drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16);
76754         if (framesRead == 0) {
76755             break;
76756         }
76757         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
76758         drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));
76759         pBufferOut      += framesRead*pWav->channels;
76760         framesToRead    -= framesRead;
76761         totalFramesRead += framesRead;
76762     }
76763     return totalFramesRead;
76764 }
76765 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
76766 {
76767     drwav_uint64 totalFramesRead;
76768     drwav_uint8 sampleData[4096] = {0};
76769     drwav_uint32 bytesPerFrame;
76770     drwav_uint32 bytesPerSample;
76771     drwav_uint64 samplesRead;
76772     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) {
76773         return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
76774     }
76775     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
76776     if (bytesPerFrame == 0) {
76777         return 0;
76778     }
76779     bytesPerSample = bytesPerFrame / pWav->channels;
76780     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
76781         return 0;
76782     }
76783     totalFramesRead = 0;
76784     while (framesToRead > 0) {
76785         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
76786         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
76787         if (framesRead == 0) {
76788             break;
76789         }
76790         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
76791         samplesRead = framesRead * pWav->channels;
76792         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
76793             DRWAV_ASSERT(DRWAV_FALSE);
76794             break;
76795         }
76796         drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
76797         pBufferOut      += samplesRead;
76798         framesToRead    -= framesRead;
76799         totalFramesRead += framesRead;
76800     }
76801     return totalFramesRead;
76802 }
76803 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
76804 {
76805     drwav_uint64 totalFramesRead;
76806     drwav_uint8 sampleData[4096] = {0};
76807     drwav_uint32 bytesPerFrame;
76808     drwav_uint32 bytesPerSample;
76809     drwav_uint64 samplesRead;
76810     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
76811     if (bytesPerFrame == 0) {
76812         return 0;
76813     }
76814     bytesPerSample = bytesPerFrame / pWav->channels;
76815     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
76816         return 0;
76817     }
76818     totalFramesRead = 0;
76819     while (framesToRead > 0) {
76820         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
76821         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
76822         if (framesRead == 0) {
76823             break;
76824         }
76825         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
76826         samplesRead = framesRead * pWav->channels;
76827         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
76828             DRWAV_ASSERT(DRWAV_FALSE);
76829             break;
76830         }
76831         drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead);
76832         pBufferOut      += samplesRead;
76833         framesToRead    -= framesRead;
76834         totalFramesRead += framesRead;
76835     }
76836     return totalFramesRead;
76837 }
76838 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
76839 {
76840     drwav_uint64 totalFramesRead;
76841     drwav_uint8 sampleData[4096] = {0};
76842     drwav_uint32 bytesPerFrame;
76843     drwav_uint32 bytesPerSample;
76844     drwav_uint64 samplesRead;
76845     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
76846     if (bytesPerFrame == 0) {
76847         return 0;
76848     }
76849     bytesPerSample = bytesPerFrame / pWav->channels;
76850     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
76851         return 0;
76852     }
76853     totalFramesRead = 0;
76854     while (framesToRead > 0) {
76855         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
76856         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
76857         if (framesRead == 0) {
76858             break;
76859         }
76860         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
76861         samplesRead = framesRead * pWav->channels;
76862         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
76863             DRWAV_ASSERT(DRWAV_FALSE);
76864             break;
76865         }
76866         drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead);
76867         pBufferOut      += samplesRead;
76868         framesToRead    -= framesRead;
76869         totalFramesRead += framesRead;
76870     }
76871     return totalFramesRead;
76872 }
76873 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
76874 {
76875     if (pWav == NULL || framesToRead == 0) {
76876         return 0;
76877     }
76878     if (pBufferOut == NULL) {
76879         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
76880     }
76881     if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) {
76882         framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels;
76883     }
76884     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
76885         return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut);
76886     }
76887     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
76888         return drwav_read_pcm_frames_f32__msadpcm_ima(pWav, framesToRead, pBufferOut);
76889     }
76890     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
76891         return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut);
76892     }
76893     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
76894         return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut);
76895     }
76896     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
76897         return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut);
76898     }
76899     return 0;
76900 }
76901 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
76902 {
76903     drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
76904     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
76905         drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
76906     }
76907     return framesRead;
76908 }
76909 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
76910 {
76911     drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
76912     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
76913         drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
76914     }
76915     return framesRead;
76916 }
76917 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
76918 {
76919     size_t i;
76920     if (pOut == NULL || pIn == NULL) {
76921         return;
76922     }
76923 #ifdef DR_WAV_LIBSNDFILE_COMPAT
76924     for (i = 0; i < sampleCount; ++i) {
76925         *pOut++ = (pIn[i] / 256.0f) * 2 - 1;
76926     }
76927 #else
76928     for (i = 0; i < sampleCount; ++i) {
76929         float x = pIn[i];
76930         x = x * 0.00784313725490196078f;
76931         x = x - 1;
76932         *pOut++ = x;
76933     }
76934 #endif
76935 }
76936 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount)
76937 {
76938     size_t i;
76939     if (pOut == NULL || pIn == NULL) {
76940         return;
76941     }
76942     for (i = 0; i < sampleCount; ++i) {
76943         *pOut++ = pIn[i] * 0.000030517578125f;
76944     }
76945 }
76946 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
76947 {
76948     size_t i;
76949     if (pOut == NULL || pIn == NULL) {
76950         return;
76951     }
76952     for (i = 0; i < sampleCount; ++i) {
76953         double x;
76954         drwav_uint32 a = ((drwav_uint32)(pIn[i*3+0]) <<  8);
76955         drwav_uint32 b = ((drwav_uint32)(pIn[i*3+1]) << 16);
76956         drwav_uint32 c = ((drwav_uint32)(pIn[i*3+2]) << 24);
76957         x = (double)((drwav_int32)(a | b | c) >> 8);
76958         *pOut++ = (float)(x * 0.00000011920928955078125);
76959     }
76960 }
76961 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount)
76962 {
76963     size_t i;
76964     if (pOut == NULL || pIn == NULL) {
76965         return;
76966     }
76967     for (i = 0; i < sampleCount; ++i) {
76968         *pOut++ = (float)(pIn[i] / 2147483648.0);
76969     }
76970 }
76971 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount)
76972 {
76973     size_t i;
76974     if (pOut == NULL || pIn == NULL) {
76975         return;
76976     }
76977     for (i = 0; i < sampleCount; ++i) {
76978         *pOut++ = (float)pIn[i];
76979     }
76980 }
76981 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
76982 {
76983     size_t i;
76984     if (pOut == NULL || pIn == NULL) {
76985         return;
76986     }
76987     for (i = 0; i < sampleCount; ++i) {
76988         *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f;
76989     }
76990 }
76991 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
76992 {
76993     size_t i;
76994     if (pOut == NULL || pIn == NULL) {
76995         return;
76996     }
76997     for (i = 0; i < sampleCount; ++i) {
76998         *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f;
76999     }
77000 }
77001 DRWAV_PRIVATE void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
77002 {
77003     unsigned int i;
77004     if (bytesPerSample == 1) {
77005         drwav_u8_to_s32(pOut, pIn, totalSampleCount);
77006         return;
77007     }
77008     if (bytesPerSample == 2) {
77009         drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount);
77010         return;
77011     }
77012     if (bytesPerSample == 3) {
77013         drwav_s24_to_s32(pOut, pIn, totalSampleCount);
77014         return;
77015     }
77016     if (bytesPerSample == 4) {
77017         for (i = 0; i < totalSampleCount; ++i) {
77018            *pOut++ = ((const drwav_int32*)pIn)[i];
77019         }
77020         return;
77021     }
77022     if (bytesPerSample > 8) {
77023         DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
77024         return;
77025     }
77026     for (i = 0; i < totalSampleCount; ++i) {
77027         drwav_uint64 sample = 0;
77028         unsigned int shift  = (8 - bytesPerSample) * 8;
77029         unsigned int j;
77030         for (j = 0; j < bytesPerSample; j += 1) {
77031             DRWAV_ASSERT(j < 8);
77032             sample |= (drwav_uint64)(pIn[j]) << shift;
77033             shift  += 8;
77034         }
77035         pIn += j;
77036         *pOut++ = (drwav_int32)((drwav_int64)sample >> 32);
77037     }
77038 }
77039 DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
77040 {
77041     if (bytesPerSample == 4) {
77042         drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount);
77043         return;
77044     } else if (bytesPerSample == 8) {
77045         drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount);
77046         return;
77047     } else {
77048         DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
77049         return;
77050     }
77051 }
77052 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
77053 {
77054     drwav_uint64 totalFramesRead;
77055     drwav_uint8 sampleData[4096] = {0};
77056     drwav_uint32 bytesPerFrame;
77057     drwav_uint32 bytesPerSample;
77058     drwav_uint64 samplesRead;
77059     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) {
77060         return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
77061     }
77062     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
77063     if (bytesPerFrame == 0) {
77064         return 0;
77065     }
77066     bytesPerSample = bytesPerFrame / pWav->channels;
77067     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
77068         return 0;
77069     }
77070     totalFramesRead = 0;
77071     while (framesToRead > 0) {
77072         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
77073         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
77074         if (framesRead == 0) {
77075             break;
77076         }
77077         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
77078         samplesRead = framesRead * pWav->channels;
77079         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
77080             DRWAV_ASSERT(DRWAV_FALSE);
77081             break;
77082         }
77083         drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
77084         pBufferOut      += samplesRead;
77085         framesToRead    -= framesRead;
77086         totalFramesRead += framesRead;
77087     }
77088     return totalFramesRead;
77089 }
77090 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
77091 {
77092     drwav_uint64 totalFramesRead = 0;
77093     drwav_int16 samples16[2048];
77094     while (framesToRead > 0) {
77095         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels);
77096         drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16);
77097         if (framesRead == 0) {
77098             break;
77099         }
77100         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
77101         drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));
77102         pBufferOut      += framesRead*pWav->channels;
77103         framesToRead    -= framesRead;
77104         totalFramesRead += framesRead;
77105     }
77106     return totalFramesRead;
77107 }
77108 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
77109 {
77110     drwav_uint64 totalFramesRead;
77111     drwav_uint8 sampleData[4096] = {0};
77112     drwav_uint32 bytesPerFrame;
77113     drwav_uint32 bytesPerSample;
77114     drwav_uint64 samplesRead;
77115     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
77116     if (bytesPerFrame == 0) {
77117         return 0;
77118     }
77119     bytesPerSample = bytesPerFrame / pWav->channels;
77120     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
77121         return 0;
77122     }
77123     totalFramesRead = 0;
77124     while (framesToRead > 0) {
77125         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
77126         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
77127         if (framesRead == 0) {
77128             break;
77129         }
77130         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
77131         samplesRead = framesRead * pWav->channels;
77132         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
77133             DRWAV_ASSERT(DRWAV_FALSE);
77134             break;
77135         }
77136         drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
77137         pBufferOut      += samplesRead;
77138         framesToRead    -= framesRead;
77139         totalFramesRead += framesRead;
77140     }
77141     return totalFramesRead;
77142 }
77143 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
77144 {
77145     drwav_uint64 totalFramesRead;
77146     drwav_uint8 sampleData[4096] = {0};
77147     drwav_uint32 bytesPerFrame;
77148     drwav_uint32 bytesPerSample;
77149     drwav_uint64 samplesRead;
77150     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
77151     if (bytesPerFrame == 0) {
77152         return 0;
77153     }
77154     bytesPerSample = bytesPerFrame / pWav->channels;
77155     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
77156         return 0;
77157     }
77158     totalFramesRead = 0;
77159     while (framesToRead > 0) {
77160         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
77161         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
77162         if (framesRead == 0) {
77163             break;
77164         }
77165         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
77166         samplesRead = framesRead * pWav->channels;
77167         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
77168             DRWAV_ASSERT(DRWAV_FALSE);
77169             break;
77170         }
77171         drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead);
77172         pBufferOut      += samplesRead;
77173         framesToRead    -= framesRead;
77174         totalFramesRead += framesRead;
77175     }
77176     return totalFramesRead;
77177 }
77178 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
77179 {
77180     drwav_uint64 totalFramesRead;
77181     drwav_uint8 sampleData[4096] = {0};
77182     drwav_uint32 bytesPerFrame;
77183     drwav_uint32 bytesPerSample;
77184     drwav_uint64 samplesRead;
77185     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
77186     if (bytesPerFrame == 0) {
77187         return 0;
77188     }
77189     bytesPerSample = bytesPerFrame / pWav->channels;
77190     if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
77191         return 0;
77192     }
77193     totalFramesRead = 0;
77194     while (framesToRead > 0) {
77195         drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
77196         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
77197         if (framesRead == 0) {
77198             break;
77199         }
77200         DRWAV_ASSERT(framesRead <= framesToReadThisIteration);
77201         samplesRead = framesRead * pWav->channels;
77202         if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
77203             DRWAV_ASSERT(DRWAV_FALSE);
77204             break;
77205         }
77206         drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead);
77207         pBufferOut      += samplesRead;
77208         framesToRead    -= framesRead;
77209         totalFramesRead += framesRead;
77210     }
77211     return totalFramesRead;
77212 }
77213 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
77214 {
77215     if (pWav == NULL || framesToRead == 0) {
77216         return 0;
77217     }
77218     if (pBufferOut == NULL) {
77219         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
77220     }
77221     if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) {
77222         framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels;
77223     }
77224     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
77225         return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut);
77226     }
77227     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
77228         return drwav_read_pcm_frames_s32__msadpcm_ima(pWav, framesToRead, pBufferOut);
77229     }
77230     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
77231         return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut);
77232     }
77233     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
77234         return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut);
77235     }
77236     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
77237         return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut);
77238     }
77239     return 0;
77240 }
77241 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
77242 {
77243     drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
77244     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
77245         drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
77246     }
77247     return framesRead;
77248 }
77249 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
77250 {
77251     drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
77252     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
77253         drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
77254     }
77255     return framesRead;
77256 }
77257 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
77258 {
77259     size_t i;
77260     if (pOut == NULL || pIn == NULL) {
77261         return;
77262     }
77263     for (i = 0; i < sampleCount; ++i) {
77264         *pOut++ = ((int)pIn[i] - 128) << 24;
77265     }
77266 }
77267 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount)
77268 {
77269     size_t i;
77270     if (pOut == NULL || pIn == NULL) {
77271         return;
77272     }
77273     for (i = 0; i < sampleCount; ++i) {
77274         *pOut++ = pIn[i] << 16;
77275     }
77276 }
77277 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
77278 {
77279     size_t i;
77280     if (pOut == NULL || pIn == NULL) {
77281         return;
77282     }
77283     for (i = 0; i < sampleCount; ++i) {
77284         unsigned int s0 = pIn[i*3 + 0];
77285         unsigned int s1 = pIn[i*3 + 1];
77286         unsigned int s2 = pIn[i*3 + 2];
77287         drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24));
77288         *pOut++ = sample32;
77289     }
77290 }
77291 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount)
77292 {
77293     size_t i;
77294     if (pOut == NULL || pIn == NULL) {
77295         return;
77296     }
77297     for (i = 0; i < sampleCount; ++i) {
77298         *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
77299     }
77300 }
77301 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount)
77302 {
77303     size_t i;
77304     if (pOut == NULL || pIn == NULL) {
77305         return;
77306     }
77307     for (i = 0; i < sampleCount; ++i) {
77308         *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
77309     }
77310 }
77311 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
77312 {
77313     size_t i;
77314     if (pOut == NULL || pIn == NULL) {
77315         return;
77316     }
77317     for (i = 0; i < sampleCount; ++i) {
77318         *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16;
77319     }
77320 }
77321 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
77322 {
77323     size_t i;
77324     if (pOut == NULL || pIn == NULL) {
77325         return;
77326     }
77327     for (i= 0; i < sampleCount; ++i) {
77328         *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16;
77329     }
77330 }
77331 DRWAV_PRIVATE drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
77332 {
77333     drwav_uint64 sampleDataSize;
77334     drwav_int16* pSampleData;
77335     drwav_uint64 framesRead;
77336     DRWAV_ASSERT(pWav != NULL);
77337     sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16);
77338     if (sampleDataSize > DRWAV_SIZE_MAX) {
77339         drwav_uninit(pWav);
77340         return NULL;
77341     }
77342     pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks);
77343     if (pSampleData == NULL) {
77344         drwav_uninit(pWav);
77345         return NULL;
77346     }
77347     framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
77348     if (framesRead != pWav->totalPCMFrameCount) {
77349         drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
77350         drwav_uninit(pWav);
77351         return NULL;
77352     }
77353     drwav_uninit(pWav);
77354     if (sampleRate) {
77355         *sampleRate = pWav->sampleRate;
77356     }
77357     if (channels) {
77358         *channels = pWav->channels;
77359     }
77360     if (totalFrameCount) {
77361         *totalFrameCount = pWav->totalPCMFrameCount;
77362     }
77363     return pSampleData;
77364 }
77365 DRWAV_PRIVATE float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
77366 {
77367     drwav_uint64 sampleDataSize;
77368     float* pSampleData;
77369     drwav_uint64 framesRead;
77370     DRWAV_ASSERT(pWav != NULL);
77371     sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float);
77372     if (sampleDataSize > DRWAV_SIZE_MAX) {
77373         drwav_uninit(pWav);
77374         return NULL;
77375     }
77376     pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks);
77377     if (pSampleData == NULL) {
77378         drwav_uninit(pWav);
77379         return NULL;
77380     }
77381     framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
77382     if (framesRead != pWav->totalPCMFrameCount) {
77383         drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
77384         drwav_uninit(pWav);
77385         return NULL;
77386     }
77387     drwav_uninit(pWav);
77388     if (sampleRate) {
77389         *sampleRate = pWav->sampleRate;
77390     }
77391     if (channels) {
77392         *channels = pWav->channels;
77393     }
77394     if (totalFrameCount) {
77395         *totalFrameCount = pWav->totalPCMFrameCount;
77396     }
77397     return pSampleData;
77398 }
77399 DRWAV_PRIVATE drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
77400 {
77401     drwav_uint64 sampleDataSize;
77402     drwav_int32* pSampleData;
77403     drwav_uint64 framesRead;
77404     DRWAV_ASSERT(pWav != NULL);
77405     sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32);
77406     if (sampleDataSize > DRWAV_SIZE_MAX) {
77407         drwav_uninit(pWav);
77408         return NULL;
77409     }
77410     pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks);
77411     if (pSampleData == NULL) {
77412         drwav_uninit(pWav);
77413         return NULL;
77414     }
77415     framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
77416     if (framesRead != pWav->totalPCMFrameCount) {
77417         drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
77418         drwav_uninit(pWav);
77419         return NULL;
77420     }
77421     drwav_uninit(pWav);
77422     if (sampleRate) {
77423         *sampleRate = pWav->sampleRate;
77424     }
77425     if (channels) {
77426         *channels = pWav->channels;
77427     }
77428     if (totalFrameCount) {
77429         *totalFrameCount = pWav->totalPCMFrameCount;
77430     }
77431     return pSampleData;
77432 }
77433 DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77434 {
77435     drwav wav;
77436     if (channelsOut) {
77437         *channelsOut = 0;
77438     }
77439     if (sampleRateOut) {
77440         *sampleRateOut = 0;
77441     }
77442     if (totalFrameCountOut) {
77443         *totalFrameCountOut = 0;
77444     }
77445     if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
77446         return NULL;
77447     }
77448     return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77449 }
77450 DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77451 {
77452     drwav wav;
77453     if (channelsOut) {
77454         *channelsOut = 0;
77455     }
77456     if (sampleRateOut) {
77457         *sampleRateOut = 0;
77458     }
77459     if (totalFrameCountOut) {
77460         *totalFrameCountOut = 0;
77461     }
77462     if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
77463         return NULL;
77464     }
77465     return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77466 }
77467 DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77468 {
77469     drwav wav;
77470     if (channelsOut) {
77471         *channelsOut = 0;
77472     }
77473     if (sampleRateOut) {
77474         *sampleRateOut = 0;
77475     }
77476     if (totalFrameCountOut) {
77477         *totalFrameCountOut = 0;
77478     }
77479     if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
77480         return NULL;
77481     }
77482     return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77483 }
77484 #ifndef DR_WAV_NO_STDIO
77485 DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77486 {
77487     drwav wav;
77488     if (channelsOut) {
77489         *channelsOut = 0;
77490     }
77491     if (sampleRateOut) {
77492         *sampleRateOut = 0;
77493     }
77494     if (totalFrameCountOut) {
77495         *totalFrameCountOut = 0;
77496     }
77497     if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
77498         return NULL;
77499     }
77500     return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77501 }
77502 DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77503 {
77504     drwav wav;
77505     if (channelsOut) {
77506         *channelsOut = 0;
77507     }
77508     if (sampleRateOut) {
77509         *sampleRateOut = 0;
77510     }
77511     if (totalFrameCountOut) {
77512         *totalFrameCountOut = 0;
77513     }
77514     if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
77515         return NULL;
77516     }
77517     return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77518 }
77519 DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77520 {
77521     drwav wav;
77522     if (channelsOut) {
77523         *channelsOut = 0;
77524     }
77525     if (sampleRateOut) {
77526         *sampleRateOut = 0;
77527     }
77528     if (totalFrameCountOut) {
77529         *totalFrameCountOut = 0;
77530     }
77531     if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
77532         return NULL;
77533     }
77534     return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77535 }
77536 DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77537 {
77538     drwav wav;
77539     if (sampleRateOut) {
77540         *sampleRateOut = 0;
77541     }
77542     if (channelsOut) {
77543         *channelsOut = 0;
77544     }
77545     if (totalFrameCountOut) {
77546         *totalFrameCountOut = 0;
77547     }
77548     if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
77549         return NULL;
77550     }
77551     return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77552 }
77553 DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77554 {
77555     drwav wav;
77556     if (sampleRateOut) {
77557         *sampleRateOut = 0;
77558     }
77559     if (channelsOut) {
77560         *channelsOut = 0;
77561     }
77562     if (totalFrameCountOut) {
77563         *totalFrameCountOut = 0;
77564     }
77565     if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
77566         return NULL;
77567     }
77568     return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77569 }
77570 DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77571 {
77572     drwav wav;
77573     if (sampleRateOut) {
77574         *sampleRateOut = 0;
77575     }
77576     if (channelsOut) {
77577         *channelsOut = 0;
77578     }
77579     if (totalFrameCountOut) {
77580         *totalFrameCountOut = 0;
77581     }
77582     if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
77583         return NULL;
77584     }
77585     return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77586 }
77587 #endif
77588 DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77589 {
77590     drwav wav;
77591     if (channelsOut) {
77592         *channelsOut = 0;
77593     }
77594     if (sampleRateOut) {
77595         *sampleRateOut = 0;
77596     }
77597     if (totalFrameCountOut) {
77598         *totalFrameCountOut = 0;
77599     }
77600     if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
77601         return NULL;
77602     }
77603     return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77604 }
77605 DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77606 {
77607     drwav wav;
77608     if (channelsOut) {
77609         *channelsOut = 0;
77610     }
77611     if (sampleRateOut) {
77612         *sampleRateOut = 0;
77613     }
77614     if (totalFrameCountOut) {
77615         *totalFrameCountOut = 0;
77616     }
77617     if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
77618         return NULL;
77619     }
77620     return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77621 }
77622 DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
77623 {
77624     drwav wav;
77625     if (channelsOut) {
77626         *channelsOut = 0;
77627     }
77628     if (sampleRateOut) {
77629         *sampleRateOut = 0;
77630     }
77631     if (totalFrameCountOut) {
77632         *totalFrameCountOut = 0;
77633     }
77634     if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
77635         return NULL;
77636     }
77637     return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
77638 }
77639 #endif
77640 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
77641 {
77642     if (pAllocationCallbacks != NULL) {
77643         drwav__free_from_callbacks(p, pAllocationCallbacks);
77644     } else {
77645         drwav__free_default(p, NULL);
77646     }
77647 }
77648 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data)
77649 {
77650     return ((drwav_uint16)data[0] << 0) | ((drwav_uint16)data[1] << 8);
77651 }
77652 DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data)
77653 {
77654     return (drwav_int16)drwav_bytes_to_u16(data);
77655 }
77656 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data)
77657 {
77658     return ((drwav_uint32)data[0] << 0) | ((drwav_uint32)data[1] << 8) | ((drwav_uint32)data[2] << 16) | ((drwav_uint32)data[3] << 24);
77659 }
77660 DRWAV_API float drwav_bytes_to_f32(const drwav_uint8* data)
77661 {
77662     union {
77663         drwav_uint32 u32;
77664         float f32;
77665     } value;
77666     value.u32 = drwav_bytes_to_u32(data);
77667     return value.f32;
77668 }
77669 DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data)
77670 {
77671     return (drwav_int32)drwav_bytes_to_u32(data);
77672 }
77673 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data)
77674 {
77675     return
77676         ((drwav_uint64)data[0] <<  0) | ((drwav_uint64)data[1] <<  8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) |
77677         ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56);
77678 }
77679 DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data)
77680 {
77681     return (drwav_int64)drwav_bytes_to_u64(data);
77682 }
77683 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
77684 {
77685     int i;
77686     for (i = 0; i < 16; i += 1) {
77687         if (a[i] != b[i]) {
77688             return DRWAV_FALSE;
77689         }
77690     }
77691     return DRWAV_TRUE;
77692 }
77693 DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
77694 {
77695     return
77696         a[0] == b[0] &&
77697         a[1] == b[1] &&
77698         a[2] == b[2] &&
77699         a[3] == b[3];
77700 }
77701 #endif
77702 /* dr_wav_c end */
77703 #endif  /* DRWAV_IMPLEMENTATION */
77704 #endif  /* MA_NO_WAV */
77705
77706 #if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING)
77707 #if !defined(DR_FLAC_IMPLEMENTATION) && !defined(DRFLAC_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */
77708 /* dr_flac_c begin */
77709 #ifndef dr_flac_c
77710 #define dr_flac_c
77711 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
77712     #pragma GCC diagnostic push
77713     #if __GNUC__ >= 7
77714     #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
77715     #endif
77716 #endif
77717 #ifdef __linux__
77718     #ifndef _BSD_SOURCE
77719         #define _BSD_SOURCE
77720     #endif
77721     #ifndef _DEFAULT_SOURCE
77722         #define _DEFAULT_SOURCE
77723     #endif
77724     #ifndef __USE_BSD
77725         #define __USE_BSD
77726     #endif
77727     #include <endian.h>
77728 #endif
77729 #include <stdlib.h>
77730 #include <string.h>
77731 #ifdef _MSC_VER
77732     #define DRFLAC_INLINE __forceinline
77733 #elif defined(__GNUC__)
77734     #if defined(__STRICT_ANSI__)
77735         #define DRFLAC_INLINE __inline__ __attribute__((always_inline))
77736     #else
77737         #define DRFLAC_INLINE inline __attribute__((always_inline))
77738     #endif
77739 #elif defined(__WATCOMC__)
77740     #define DRFLAC_INLINE __inline
77741 #else
77742     #define DRFLAC_INLINE
77743 #endif
77744 #if defined(__x86_64__) || defined(_M_X64)
77745     #define DRFLAC_X64
77746 #elif defined(__i386) || defined(_M_IX86)
77747     #define DRFLAC_X86
77748 #elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARM64)
77749     #define DRFLAC_ARM
77750 #endif
77751 #if !defined(DR_FLAC_NO_SIMD)
77752     #if defined(DRFLAC_X64) || defined(DRFLAC_X86)
77753         #if defined(_MSC_VER) && !defined(__clang__)
77754             #if _MSC_VER >= 1400 && !defined(DRFLAC_NO_SSE2)
77755                 #define DRFLAC_SUPPORT_SSE2
77756             #endif
77757             #if _MSC_VER >= 1600 && !defined(DRFLAC_NO_SSE41)
77758                 #define DRFLAC_SUPPORT_SSE41
77759             #endif
77760         #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
77761             #if defined(__SSE2__) && !defined(DRFLAC_NO_SSE2)
77762                 #define DRFLAC_SUPPORT_SSE2
77763             #endif
77764             #if defined(__SSE4_1__) && !defined(DRFLAC_NO_SSE41)
77765                 #define DRFLAC_SUPPORT_SSE41
77766             #endif
77767         #endif
77768         #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
77769             #if !defined(DRFLAC_SUPPORT_SSE2) && !defined(DRFLAC_NO_SSE2) && __has_include(<emmintrin.h>)
77770                 #define DRFLAC_SUPPORT_SSE2
77771             #endif
77772             #if !defined(DRFLAC_SUPPORT_SSE41) && !defined(DRFLAC_NO_SSE41) && __has_include(<smmintrin.h>)
77773                 #define DRFLAC_SUPPORT_SSE41
77774             #endif
77775         #endif
77776         #if defined(DRFLAC_SUPPORT_SSE41)
77777             #include <smmintrin.h>
77778         #elif defined(DRFLAC_SUPPORT_SSE2)
77779             #include <emmintrin.h>
77780         #endif
77781     #endif
77782     #if defined(DRFLAC_ARM)
77783         #if !defined(DRFLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
77784             #define DRFLAC_SUPPORT_NEON
77785         #endif
77786         #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
77787             #if !defined(DRFLAC_SUPPORT_NEON) && !defined(DRFLAC_NO_NEON) && __has_include(<arm_neon.h>)
77788                 #define DRFLAC_SUPPORT_NEON
77789             #endif
77790         #endif
77791         #if defined(DRFLAC_SUPPORT_NEON)
77792             #include <arm_neon.h>
77793         #endif
77794     #endif
77795 #endif
77796 #if !defined(DR_FLAC_NO_SIMD) && (defined(DRFLAC_X86) || defined(DRFLAC_X64))
77797     #if defined(_MSC_VER) && !defined(__clang__)
77798         #if _MSC_VER >= 1400
77799             #include <intrin.h>
77800             static void drflac__cpuid(int info[4], int fid)
77801             {
77802                 __cpuid(info, fid);
77803             }
77804         #else
77805             #define DRFLAC_NO_CPUID
77806         #endif
77807     #else
77808         #if defined(__GNUC__) || defined(__clang__)
77809             static void drflac__cpuid(int info[4], int fid)
77810             {
77811                 #if defined(DRFLAC_X86) && defined(__PIC__)
77812                     __asm__ __volatile__ (
77813                         "xchg{l} {%%}ebx, %k1;"
77814                         "cpuid;"
77815                         "xchg{l} {%%}ebx, %k1;"
77816                         : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
77817                     );
77818                 #else
77819                     __asm__ __volatile__ (
77820                         "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
77821                     );
77822                 #endif
77823             }
77824         #else
77825             #define DRFLAC_NO_CPUID
77826         #endif
77827     #endif
77828 #else
77829     #define DRFLAC_NO_CPUID
77830 #endif
77831 static DRFLAC_INLINE drflac_bool32 drflac_has_sse2(void)
77832 {
77833 #if defined(DRFLAC_SUPPORT_SSE2)
77834     #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE2)
77835         #if defined(DRFLAC_X64)
77836             return DRFLAC_TRUE;
77837         #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)
77838             return DRFLAC_TRUE;
77839         #else
77840             #if defined(DRFLAC_NO_CPUID)
77841                 return DRFLAC_FALSE;
77842             #else
77843                 int info[4];
77844                 drflac__cpuid(info, 1);
77845                 return (info[3] & (1 << 26)) != 0;
77846             #endif
77847         #endif
77848     #else
77849         return DRFLAC_FALSE;
77850     #endif
77851 #else
77852     return DRFLAC_FALSE;
77853 #endif
77854 }
77855 static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void)
77856 {
77857 #if defined(DRFLAC_SUPPORT_SSE41)
77858     #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE41)
77859         #if defined(DRFLAC_X64)
77860             return DRFLAC_TRUE;
77861         #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE4_1__)
77862             return DRFLAC_TRUE;
77863         #else
77864             #if defined(DRFLAC_NO_CPUID)
77865                 return DRFLAC_FALSE;
77866             #else
77867                 int info[4];
77868                 drflac__cpuid(info, 1);
77869                 return (info[2] & (1 << 19)) != 0;
77870             #endif
77871         #endif
77872     #else
77873         return DRFLAC_FALSE;
77874     #endif
77875 #else
77876     return DRFLAC_FALSE;
77877 #endif
77878 }
77879 #if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) && !defined(__clang__)
77880     #define DRFLAC_HAS_LZCNT_INTRINSIC
77881 #elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))
77882     #define DRFLAC_HAS_LZCNT_INTRINSIC
77883 #elif defined(__clang__)
77884     #if defined(__has_builtin)
77885         #if __has_builtin(__builtin_clzll) || __has_builtin(__builtin_clzl)
77886             #define DRFLAC_HAS_LZCNT_INTRINSIC
77887         #endif
77888     #endif
77889 #endif
77890 #if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(__clang__)
77891     #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
77892     #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
77893     #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
77894 #elif defined(__clang__)
77895     #if defined(__has_builtin)
77896         #if __has_builtin(__builtin_bswap16)
77897             #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
77898         #endif
77899         #if __has_builtin(__builtin_bswap32)
77900             #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
77901         #endif
77902         #if __has_builtin(__builtin_bswap64)
77903             #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
77904         #endif
77905     #endif
77906 #elif defined(__GNUC__)
77907     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
77908         #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
77909         #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
77910     #endif
77911     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
77912         #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
77913     #endif
77914 #elif defined(__WATCOMC__) && defined(__386__)
77915     #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
77916     #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
77917     #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
77918     extern __inline drflac_uint16 _watcom_bswap16(drflac_uint16);
77919     extern __inline drflac_uint32 _watcom_bswap32(drflac_uint32);
77920     extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64);
77921 #pragma aux _watcom_bswap16 = \
77922     "xchg al, ah" \
77923     parm   [ax]   \
77924     modify [ax];
77925 #pragma aux _watcom_bswap32 = \
77926     "bswap eax"  \
77927     parm   [eax] \
77928     modify [eax];
77929 #pragma aux _watcom_bswap64 = \
77930     "bswap eax"     \
77931     "bswap edx"     \
77932     "xchg eax,edx"  \
77933     parm [eax edx]  \
77934     modify [eax edx];
77935 #endif
77936 #ifndef DRFLAC_ASSERT
77937 #include <assert.h>
77938 #define DRFLAC_ASSERT(expression)           assert(expression)
77939 #endif
77940 #ifndef DRFLAC_MALLOC
77941 #define DRFLAC_MALLOC(sz)                   malloc((sz))
77942 #endif
77943 #ifndef DRFLAC_REALLOC
77944 #define DRFLAC_REALLOC(p, sz)               realloc((p), (sz))
77945 #endif
77946 #ifndef DRFLAC_FREE
77947 #define DRFLAC_FREE(p)                      free((p))
77948 #endif
77949 #ifndef DRFLAC_COPY_MEMORY
77950 #define DRFLAC_COPY_MEMORY(dst, src, sz)    memcpy((dst), (src), (sz))
77951 #endif
77952 #ifndef DRFLAC_ZERO_MEMORY
77953 #define DRFLAC_ZERO_MEMORY(p, sz)           memset((p), 0, (sz))
77954 #endif
77955 #ifndef DRFLAC_ZERO_OBJECT
77956 #define DRFLAC_ZERO_OBJECT(p)               DRFLAC_ZERO_MEMORY((p), sizeof(*(p)))
77957 #endif
77958 #define DRFLAC_MAX_SIMD_VECTOR_SIZE                     64
77959 typedef drflac_int32 drflac_result;
77960 #define DRFLAC_SUCCESS                                   0
77961 #define DRFLAC_ERROR                                    -1
77962 #define DRFLAC_INVALID_ARGS                             -2
77963 #define DRFLAC_INVALID_OPERATION                        -3
77964 #define DRFLAC_OUT_OF_MEMORY                            -4
77965 #define DRFLAC_OUT_OF_RANGE                             -5
77966 #define DRFLAC_ACCESS_DENIED                            -6
77967 #define DRFLAC_DOES_NOT_EXIST                           -7
77968 #define DRFLAC_ALREADY_EXISTS                           -8
77969 #define DRFLAC_TOO_MANY_OPEN_FILES                      -9
77970 #define DRFLAC_INVALID_FILE                             -10
77971 #define DRFLAC_TOO_BIG                                  -11
77972 #define DRFLAC_PATH_TOO_LONG                            -12
77973 #define DRFLAC_NAME_TOO_LONG                            -13
77974 #define DRFLAC_NOT_DIRECTORY                            -14
77975 #define DRFLAC_IS_DIRECTORY                             -15
77976 #define DRFLAC_DIRECTORY_NOT_EMPTY                      -16
77977 #define DRFLAC_END_OF_FILE                              -17
77978 #define DRFLAC_NO_SPACE                                 -18
77979 #define DRFLAC_BUSY                                     -19
77980 #define DRFLAC_IO_ERROR                                 -20
77981 #define DRFLAC_INTERRUPT                                -21
77982 #define DRFLAC_UNAVAILABLE                              -22
77983 #define DRFLAC_ALREADY_IN_USE                           -23
77984 #define DRFLAC_BAD_ADDRESS                              -24
77985 #define DRFLAC_BAD_SEEK                                 -25
77986 #define DRFLAC_BAD_PIPE                                 -26
77987 #define DRFLAC_DEADLOCK                                 -27
77988 #define DRFLAC_TOO_MANY_LINKS                           -28
77989 #define DRFLAC_NOT_IMPLEMENTED                          -29
77990 #define DRFLAC_NO_MESSAGE                               -30
77991 #define DRFLAC_BAD_MESSAGE                              -31
77992 #define DRFLAC_NO_DATA_AVAILABLE                        -32
77993 #define DRFLAC_INVALID_DATA                             -33
77994 #define DRFLAC_TIMEOUT                                  -34
77995 #define DRFLAC_NO_NETWORK                               -35
77996 #define DRFLAC_NOT_UNIQUE                               -36
77997 #define DRFLAC_NOT_SOCKET                               -37
77998 #define DRFLAC_NO_ADDRESS                               -38
77999 #define DRFLAC_BAD_PROTOCOL                             -39
78000 #define DRFLAC_PROTOCOL_UNAVAILABLE                     -40
78001 #define DRFLAC_PROTOCOL_NOT_SUPPORTED                   -41
78002 #define DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED            -42
78003 #define DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED             -43
78004 #define DRFLAC_SOCKET_NOT_SUPPORTED                     -44
78005 #define DRFLAC_CONNECTION_RESET                         -45
78006 #define DRFLAC_ALREADY_CONNECTED                        -46
78007 #define DRFLAC_NOT_CONNECTED                            -47
78008 #define DRFLAC_CONNECTION_REFUSED                       -48
78009 #define DRFLAC_NO_HOST                                  -49
78010 #define DRFLAC_IN_PROGRESS                              -50
78011 #define DRFLAC_CANCELLED                                -51
78012 #define DRFLAC_MEMORY_ALREADY_MAPPED                    -52
78013 #define DRFLAC_AT_END                                   -53
78014 #define DRFLAC_CRC_MISMATCH                             -128
78015 #define DRFLAC_SUBFRAME_CONSTANT                        0
78016 #define DRFLAC_SUBFRAME_VERBATIM                        1
78017 #define DRFLAC_SUBFRAME_FIXED                           8
78018 #define DRFLAC_SUBFRAME_LPC                             32
78019 #define DRFLAC_SUBFRAME_RESERVED                        255
78020 #define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE  0
78021 #define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1
78022 #define DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT           0
78023 #define DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE             8
78024 #define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE            9
78025 #define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE              10
78026 #define drflac_align(x, a)                              ((((x) + (a) - 1) / (a)) * (a))
78027 DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision)
78028 {
78029     if (pMajor) {
78030         *pMajor = DRFLAC_VERSION_MAJOR;
78031     }
78032     if (pMinor) {
78033         *pMinor = DRFLAC_VERSION_MINOR;
78034     }
78035     if (pRevision) {
78036         *pRevision = DRFLAC_VERSION_REVISION;
78037     }
78038 }
78039 DRFLAC_API const char* drflac_version_string(void)
78040 {
78041     return DRFLAC_VERSION_STRING;
78042 }
78043 #if defined(__has_feature)
78044     #if __has_feature(thread_sanitizer)
78045         #define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread")))
78046     #else
78047         #define DRFLAC_NO_THREAD_SANITIZE
78048     #endif
78049 #else
78050     #define DRFLAC_NO_THREAD_SANITIZE
78051 #endif
78052 #if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
78053 static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE;
78054 #endif
78055 #ifndef DRFLAC_NO_CPUID
78056 static drflac_bool32 drflac__gIsSSE2Supported  = DRFLAC_FALSE;
78057 static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE;
78058 DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void)
78059 {
78060     static drflac_bool32 isCPUCapsInitialized = DRFLAC_FALSE;
78061     if (!isCPUCapsInitialized) {
78062 #if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
78063         int info[4] = {0};
78064         drflac__cpuid(info, 0x80000001);
78065         drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0;
78066 #endif
78067         drflac__gIsSSE2Supported = drflac_has_sse2();
78068         drflac__gIsSSE41Supported = drflac_has_sse41();
78069         isCPUCapsInitialized = DRFLAC_TRUE;
78070     }
78071 }
78072 #else
78073 static drflac_bool32 drflac__gIsNEONSupported  = DRFLAC_FALSE;
78074 static DRFLAC_INLINE drflac_bool32 drflac__has_neon(void)
78075 {
78076 #if defined(DRFLAC_SUPPORT_NEON)
78077     #if defined(DRFLAC_ARM) && !defined(DRFLAC_NO_NEON)
78078         #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
78079             return DRFLAC_TRUE;
78080         #else
78081             return DRFLAC_FALSE;
78082         #endif
78083     #else
78084         return DRFLAC_FALSE;
78085     #endif
78086 #else
78087     return DRFLAC_FALSE;
78088 #endif
78089 }
78090 DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void)
78091 {
78092     drflac__gIsNEONSupported = drflac__has_neon();
78093 #if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5)
78094     drflac__gIsLZCNTSupported = DRFLAC_TRUE;
78095 #endif
78096 }
78097 #endif
78098 static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian(void)
78099 {
78100 #if defined(DRFLAC_X86) || defined(DRFLAC_X64)
78101     return DRFLAC_TRUE;
78102 #elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
78103     return DRFLAC_TRUE;
78104 #else
78105     int n = 1;
78106     return (*(char*)&n) == 1;
78107 #endif
78108 }
78109 static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n)
78110 {
78111 #ifdef DRFLAC_HAS_BYTESWAP16_INTRINSIC
78112     #if defined(_MSC_VER) && !defined(__clang__)
78113         return _byteswap_ushort(n);
78114     #elif defined(__GNUC__) || defined(__clang__)
78115         return __builtin_bswap16(n);
78116     #elif defined(__WATCOMC__) && defined(__386__)
78117         return _watcom_bswap16(n);
78118     #else
78119         #error "This compiler does not support the byte swap intrinsic."
78120     #endif
78121 #else
78122     return ((n & 0xFF00) >> 8) |
78123            ((n & 0x00FF) << 8);
78124 #endif
78125 }
78126 static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n)
78127 {
78128 #ifdef DRFLAC_HAS_BYTESWAP32_INTRINSIC
78129     #if defined(_MSC_VER) && !defined(__clang__)
78130         return _byteswap_ulong(n);
78131     #elif defined(__GNUC__) || defined(__clang__)
78132         #if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRFLAC_64BIT)
78133             drflac_uint32 r;
78134             __asm__ __volatile__ (
78135             #if defined(DRFLAC_64BIT)
78136                 "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n)
78137             #else
78138                 "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
78139             #endif
78140             );
78141             return r;
78142         #else
78143             return __builtin_bswap32(n);
78144         #endif
78145     #elif defined(__WATCOMC__) && defined(__386__)
78146         return _watcom_bswap32(n);
78147     #else
78148         #error "This compiler does not support the byte swap intrinsic."
78149     #endif
78150 #else
78151     return ((n & 0xFF000000) >> 24) |
78152            ((n & 0x00FF0000) >>  8) |
78153            ((n & 0x0000FF00) <<  8) |
78154            ((n & 0x000000FF) << 24);
78155 #endif
78156 }
78157 static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n)
78158 {
78159 #ifdef DRFLAC_HAS_BYTESWAP64_INTRINSIC
78160     #if defined(_MSC_VER) && !defined(__clang__)
78161         return _byteswap_uint64(n);
78162     #elif defined(__GNUC__) || defined(__clang__)
78163         return __builtin_bswap64(n);
78164     #elif defined(__WATCOMC__) && defined(__386__)
78165         return _watcom_bswap64(n);
78166     #else
78167         #error "This compiler does not support the byte swap intrinsic."
78168     #endif
78169 #else
78170     return ((n & ((drflac_uint64)0xFF000000 << 32)) >> 56) |
78171            ((n & ((drflac_uint64)0x00FF0000 << 32)) >> 40) |
78172            ((n & ((drflac_uint64)0x0000FF00 << 32)) >> 24) |
78173            ((n & ((drflac_uint64)0x000000FF << 32)) >>  8) |
78174            ((n & ((drflac_uint64)0xFF000000      )) <<  8) |
78175            ((n & ((drflac_uint64)0x00FF0000      )) << 24) |
78176            ((n & ((drflac_uint64)0x0000FF00      )) << 40) |
78177            ((n & ((drflac_uint64)0x000000FF      )) << 56);
78178 #endif
78179 }
78180 static DRFLAC_INLINE drflac_uint16 drflac__be2host_16(drflac_uint16 n)
78181 {
78182     if (drflac__is_little_endian()) {
78183         return drflac__swap_endian_uint16(n);
78184     }
78185     return n;
78186 }
78187 static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n)
78188 {
78189     if (drflac__is_little_endian()) {
78190         return drflac__swap_endian_uint32(n);
78191     }
78192     return n;
78193 }
78194 static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n)
78195 {
78196     if (drflac__is_little_endian()) {
78197         return drflac__swap_endian_uint64(n);
78198     }
78199     return n;
78200 }
78201 static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n)
78202 {
78203     if (!drflac__is_little_endian()) {
78204         return drflac__swap_endian_uint32(n);
78205     }
78206     return n;
78207 }
78208 static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n)
78209 {
78210     drflac_uint32 result = 0;
78211     result |= (n & 0x7F000000) >> 3;
78212     result |= (n & 0x007F0000) >> 2;
78213     result |= (n & 0x00007F00) >> 1;
78214     result |= (n & 0x0000007F) >> 0;
78215     return result;
78216 }
78217 static drflac_uint8 drflac__crc8_table[] = {
78218     0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
78219     0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
78220     0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
78221     0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
78222     0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
78223     0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
78224     0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
78225     0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
78226     0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
78227     0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
78228     0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
78229     0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
78230     0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
78231     0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
78232     0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
78233     0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
78234 };
78235 static drflac_uint16 drflac__crc16_table[] = {
78236     0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
78237     0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
78238     0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
78239     0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
78240     0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
78241     0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
78242     0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
78243     0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
78244     0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
78245     0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
78246     0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
78247     0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
78248     0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
78249     0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
78250     0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
78251     0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
78252     0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
78253     0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
78254     0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
78255     0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
78256     0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
78257     0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
78258     0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
78259     0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
78260     0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
78261     0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
78262     0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
78263     0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
78264     0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
78265     0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
78266     0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
78267     0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
78268 };
78269 static DRFLAC_INLINE drflac_uint8 drflac_crc8_byte(drflac_uint8 crc, drflac_uint8 data)
78270 {
78271     return drflac__crc8_table[crc ^ data];
78272 }
78273 static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 data, drflac_uint32 count)
78274 {
78275 #ifdef DR_FLAC_NO_CRC
78276     (void)crc;
78277     (void)data;
78278     (void)count;
78279     return 0;
78280 #else
78281 #if 0
78282     drflac_uint8 p = 0x07;
78283     for (int i = count-1; i >= 0; --i) {
78284         drflac_uint8 bit = (data & (1 << i)) >> i;
78285         if (crc & 0x80) {
78286             crc = ((crc << 1) | bit) ^ p;
78287         } else {
78288             crc = ((crc << 1) | bit);
78289         }
78290     }
78291     return crc;
78292 #else
78293     drflac_uint32 wholeBytes;
78294     drflac_uint32 leftoverBits;
78295     drflac_uint64 leftoverDataMask;
78296     static drflac_uint64 leftoverDataMaskTable[8] = {
78297         0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
78298     };
78299     DRFLAC_ASSERT(count <= 32);
78300     wholeBytes = count >> 3;
78301     leftoverBits = count - (wholeBytes*8);
78302     leftoverDataMask = leftoverDataMaskTable[leftoverBits];
78303     switch (wholeBytes) {
78304         case 4: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits)));
78305         case 3: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits)));
78306         case 2: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits)));
78307         case 1: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits)));
78308         case 0: if (leftoverBits > 0) crc = (drflac_uint8)((crc << leftoverBits) ^ drflac__crc8_table[(crc >> (8 - leftoverBits)) ^ (data & leftoverDataMask)]);
78309     }
78310     return crc;
78311 #endif
78312 #endif
78313 }
78314 static DRFLAC_INLINE drflac_uint16 drflac_crc16_byte(drflac_uint16 crc, drflac_uint8 data)
78315 {
78316     return (crc << 8) ^ drflac__crc16_table[(drflac_uint8)(crc >> 8) ^ data];
78317 }
78318 static DRFLAC_INLINE drflac_uint16 drflac_crc16_cache(drflac_uint16 crc, drflac_cache_t data)
78319 {
78320 #ifdef DRFLAC_64BIT
78321     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF));
78322     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF));
78323     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF));
78324     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF));
78325 #endif
78326     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF));
78327     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF));
78328     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  8) & 0xFF));
78329     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  0) & 0xFF));
78330     return crc;
78331 }
78332 static DRFLAC_INLINE drflac_uint16 drflac_crc16_bytes(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 byteCount)
78333 {
78334     switch (byteCount)
78335     {
78336 #ifdef DRFLAC_64BIT
78337     case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF));
78338     case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF));
78339     case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF));
78340     case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF));
78341 #endif
78342     case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF));
78343     case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF));
78344     case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  8) & 0xFF));
78345     case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  0) & 0xFF));
78346     }
78347     return crc;
78348 }
78349 #if 0
78350 static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac_uint32 data, drflac_uint32 count)
78351 {
78352 #ifdef DR_FLAC_NO_CRC
78353     (void)crc;
78354     (void)data;
78355     (void)count;
78356     return 0;
78357 #else
78358 #if 0
78359     drflac_uint16 p = 0x8005;
78360     for (int i = count-1; i >= 0; --i) {
78361         drflac_uint16 bit = (data & (1ULL << i)) >> i;
78362         if (r & 0x8000) {
78363             r = ((r << 1) | bit) ^ p;
78364         } else {
78365             r = ((r << 1) | bit);
78366         }
78367     }
78368     return crc;
78369 #else
78370     drflac_uint32 wholeBytes;
78371     drflac_uint32 leftoverBits;
78372     drflac_uint64 leftoverDataMask;
78373     static drflac_uint64 leftoverDataMaskTable[8] = {
78374         0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
78375     };
78376     DRFLAC_ASSERT(count <= 64);
78377     wholeBytes = count >> 3;
78378     leftoverBits = count & 7;
78379     leftoverDataMask = leftoverDataMaskTable[leftoverBits];
78380     switch (wholeBytes) {
78381         default:
78382         case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits)));
78383         case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits)));
78384         case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits)));
78385         case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits)));
78386         case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)];
78387     }
78388     return crc;
78389 #endif
78390 #endif
78391 }
78392 static DRFLAC_INLINE drflac_uint16 drflac_crc16__64bit(drflac_uint16 crc, drflac_uint64 data, drflac_uint32 count)
78393 {
78394 #ifdef DR_FLAC_NO_CRC
78395     (void)crc;
78396     (void)data;
78397     (void)count;
78398     return 0;
78399 #else
78400     drflac_uint32 wholeBytes;
78401     drflac_uint32 leftoverBits;
78402     drflac_uint64 leftoverDataMask;
78403     static drflac_uint64 leftoverDataMaskTable[8] = {
78404         0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
78405     };
78406     DRFLAC_ASSERT(count <= 64);
78407     wholeBytes = count >> 3;
78408     leftoverBits = count & 7;
78409     leftoverDataMask = leftoverDataMaskTable[leftoverBits];
78410     switch (wholeBytes) {
78411         default:
78412         case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 << 32) << leftoverBits)) >> (56 + leftoverBits)));
78413         case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 << 32) << leftoverBits)) >> (48 + leftoverBits)));
78414         case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 << 32) << leftoverBits)) >> (40 + leftoverBits)));
78415         case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF << 32) << leftoverBits)) >> (32 + leftoverBits)));
78416         case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000      ) << leftoverBits)) >> (24 + leftoverBits)));
78417         case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000      ) << leftoverBits)) >> (16 + leftoverBits)));
78418         case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00      ) << leftoverBits)) >> ( 8 + leftoverBits)));
78419         case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF      ) << leftoverBits)) >> ( 0 + leftoverBits)));
78420         case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)];
78421     }
78422     return crc;
78423 #endif
78424 }
78425 static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 count)
78426 {
78427 #ifdef DRFLAC_64BIT
78428     return drflac_crc16__64bit(crc, data, count);
78429 #else
78430     return drflac_crc16__32bit(crc, data, count);
78431 #endif
78432 }
78433 #endif
78434 #ifdef DRFLAC_64BIT
78435 #define drflac__be2host__cache_line drflac__be2host_64
78436 #else
78437 #define drflac__be2host__cache_line drflac__be2host_32
78438 #endif
78439 #define DRFLAC_CACHE_L1_SIZE_BYTES(bs)                      (sizeof((bs)->cache))
78440 #define DRFLAC_CACHE_L1_SIZE_BITS(bs)                       (sizeof((bs)->cache)*8)
78441 #define DRFLAC_CACHE_L1_BITS_REMAINING(bs)                  (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (bs)->consumedBits)
78442 #define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount)           (~((~(drflac_cache_t)0) >> (_bitCount)))
78443 #define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount)      (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount))
78444 #define DRFLAC_CACHE_L1_SELECT(bs, _bitCount)               (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount))
78445 #define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount)     (DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >>  DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)))
78446 #define DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, _bitCount)(DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> (DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)) & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1)))
78447 #define DRFLAC_CACHE_L2_SIZE_BYTES(bs)                      (sizeof((bs)->cacheL2))
78448 #define DRFLAC_CACHE_L2_LINE_COUNT(bs)                      (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0]))
78449 #define DRFLAC_CACHE_L2_LINES_REMAINING(bs)                 (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line)
78450 #ifndef DR_FLAC_NO_CRC
78451 static DRFLAC_INLINE void drflac__reset_crc16(drflac_bs* bs)
78452 {
78453     bs->crc16 = 0;
78454     bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
78455 }
78456 static DRFLAC_INLINE void drflac__update_crc16(drflac_bs* bs)
78457 {
78458     if (bs->crc16CacheIgnoredBytes == 0) {
78459         bs->crc16 = drflac_crc16_cache(bs->crc16, bs->crc16Cache);
78460     } else {
78461         bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache, DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bs->crc16CacheIgnoredBytes);
78462         bs->crc16CacheIgnoredBytes = 0;
78463     }
78464 }
78465 static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs)
78466 {
78467     DRFLAC_ASSERT((DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0);
78468     if (DRFLAC_CACHE_L1_BITS_REMAINING(bs) == 0) {
78469         drflac__update_crc16(bs);
78470     } else {
78471         bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache >> DRFLAC_CACHE_L1_BITS_REMAINING(bs), (bs->consumedBits >> 3) - bs->crc16CacheIgnoredBytes);
78472         bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
78473     }
78474     return bs->crc16;
78475 }
78476 #endif
78477 static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
78478 {
78479     size_t bytesRead;
78480     size_t alignedL1LineCount;
78481     if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
78482         bs->cache = bs->cacheL2[bs->nextL2Line++];
78483         return DRFLAC_TRUE;
78484     }
78485     if (bs->unalignedByteCount > 0) {
78486         return DRFLAC_FALSE;
78487     }
78488     bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs));
78489     bs->nextL2Line = 0;
78490     if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) {
78491         bs->cache = bs->cacheL2[bs->nextL2Line++];
78492         return DRFLAC_TRUE;
78493     }
78494     alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs);
78495     bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs));
78496     if (bs->unalignedByteCount > 0) {
78497         bs->unalignedCache = bs->cacheL2[alignedL1LineCount];
78498     }
78499     if (alignedL1LineCount > 0) {
78500         size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount;
78501         size_t i;
78502         for (i = alignedL1LineCount; i > 0; --i) {
78503             bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1];
78504         }
78505         bs->nextL2Line = (drflac_uint32)offset;
78506         bs->cache = bs->cacheL2[bs->nextL2Line++];
78507         return DRFLAC_TRUE;
78508     } else {
78509         bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs);
78510         return DRFLAC_FALSE;
78511     }
78512 }
78513 static drflac_bool32 drflac__reload_cache(drflac_bs* bs)
78514 {
78515     size_t bytesRead;
78516 #ifndef DR_FLAC_NO_CRC
78517     drflac__update_crc16(bs);
78518 #endif
78519     if (drflac__reload_l1_cache_from_l2(bs)) {
78520         bs->cache = drflac__be2host__cache_line(bs->cache);
78521         bs->consumedBits = 0;
78522 #ifndef DR_FLAC_NO_CRC
78523         bs->crc16Cache = bs->cache;
78524 #endif
78525         return DRFLAC_TRUE;
78526     }
78527     bytesRead = bs->unalignedByteCount;
78528     if (bytesRead == 0) {
78529         bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);
78530         return DRFLAC_FALSE;
78531     }
78532     DRFLAC_ASSERT(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs));
78533     bs->consumedBits = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8;
78534     bs->cache = drflac__be2host__cache_line(bs->unalignedCache);
78535     bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_BITS_REMAINING(bs));
78536     bs->unalignedByteCount = 0;
78537 #ifndef DR_FLAC_NO_CRC
78538     bs->crc16Cache = bs->cache >> bs->consumedBits;
78539     bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
78540 #endif
78541     return DRFLAC_TRUE;
78542 }
78543 static void drflac__reset_cache(drflac_bs* bs)
78544 {
78545     bs->nextL2Line   = DRFLAC_CACHE_L2_LINE_COUNT(bs);
78546     bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);
78547     bs->cache = 0;
78548     bs->unalignedByteCount = 0;
78549     bs->unalignedCache = 0;
78550 #ifndef DR_FLAC_NO_CRC
78551     bs->crc16Cache = 0;
78552     bs->crc16CacheIgnoredBytes = 0;
78553 #endif
78554 }
78555 static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, drflac_uint32* pResultOut)
78556 {
78557     DRFLAC_ASSERT(bs != NULL);
78558     DRFLAC_ASSERT(pResultOut != NULL);
78559     DRFLAC_ASSERT(bitCount > 0);
78560     DRFLAC_ASSERT(bitCount <= 32);
78561     if (bs->consumedBits == DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
78562         if (!drflac__reload_cache(bs)) {
78563             return DRFLAC_FALSE;
78564         }
78565     }
78566     if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
78567 #ifdef DRFLAC_64BIT
78568         *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount);
78569         bs->consumedBits += bitCount;
78570         bs->cache <<= bitCount;
78571 #else
78572         if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
78573             *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount);
78574             bs->consumedBits += bitCount;
78575             bs->cache <<= bitCount;
78576         } else {
78577             *pResultOut = (drflac_uint32)bs->cache;
78578             bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);
78579             bs->cache = 0;
78580         }
78581 #endif
78582         return DRFLAC_TRUE;
78583     } else {
78584         drflac_uint32 bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs);
78585         drflac_uint32 bitCountLo = bitCount - bitCountHi;
78586         drflac_uint32 resultHi;
78587         DRFLAC_ASSERT(bitCountHi > 0);
78588         DRFLAC_ASSERT(bitCountHi < 32);
78589         resultHi = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi);
78590         if (!drflac__reload_cache(bs)) {
78591             return DRFLAC_FALSE;
78592         }
78593         *pResultOut = (resultHi << bitCountLo) | (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo);
78594         bs->consumedBits += bitCountLo;
78595         bs->cache <<= bitCountLo;
78596         return DRFLAC_TRUE;
78597     }
78598 }
78599 static drflac_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, drflac_int32* pResult)
78600 {
78601     drflac_uint32 result;
78602     DRFLAC_ASSERT(bs != NULL);
78603     DRFLAC_ASSERT(pResult != NULL);
78604     DRFLAC_ASSERT(bitCount > 0);
78605     DRFLAC_ASSERT(bitCount <= 32);
78606     if (!drflac__read_uint32(bs, bitCount, &result)) {
78607         return DRFLAC_FALSE;
78608     }
78609     if (bitCount < 32) {
78610         drflac_uint32 signbit;
78611         signbit = ((result >> (bitCount-1)) & 0x01);
78612         result |= (~signbit + 1) << bitCount;
78613     }
78614     *pResult = (drflac_int32)result;
78615     return DRFLAC_TRUE;
78616 }
78617 #ifdef DRFLAC_64BIT
78618 static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, drflac_uint64* pResultOut)
78619 {
78620     drflac_uint32 resultHi;
78621     drflac_uint32 resultLo;
78622     DRFLAC_ASSERT(bitCount <= 64);
78623     DRFLAC_ASSERT(bitCount >  32);
78624     if (!drflac__read_uint32(bs, bitCount - 32, &resultHi)) {
78625         return DRFLAC_FALSE;
78626     }
78627     if (!drflac__read_uint32(bs, 32, &resultLo)) {
78628         return DRFLAC_FALSE;
78629     }
78630     *pResultOut = (((drflac_uint64)resultHi) << 32) | ((drflac_uint64)resultLo);
78631     return DRFLAC_TRUE;
78632 }
78633 #endif
78634 #if 0
78635 static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, drflac_int64* pResultOut)
78636 {
78637     drflac_uint64 result;
78638     drflac_uint64 signbit;
78639     DRFLAC_ASSERT(bitCount <= 64);
78640     if (!drflac__read_uint64(bs, bitCount, &result)) {
78641         return DRFLAC_FALSE;
78642     }
78643     signbit = ((result >> (bitCount-1)) & 0x01);
78644     result |= (~signbit + 1) << bitCount;
78645     *pResultOut = (drflac_int64)result;
78646     return DRFLAC_TRUE;
78647 }
78648 #endif
78649 static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, drflac_uint16* pResult)
78650 {
78651     drflac_uint32 result;
78652     DRFLAC_ASSERT(bs != NULL);
78653     DRFLAC_ASSERT(pResult != NULL);
78654     DRFLAC_ASSERT(bitCount > 0);
78655     DRFLAC_ASSERT(bitCount <= 16);
78656     if (!drflac__read_uint32(bs, bitCount, &result)) {
78657         return DRFLAC_FALSE;
78658     }
78659     *pResult = (drflac_uint16)result;
78660     return DRFLAC_TRUE;
78661 }
78662 #if 0
78663 static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, drflac_int16* pResult)
78664 {
78665     drflac_int32 result;
78666     DRFLAC_ASSERT(bs != NULL);
78667     DRFLAC_ASSERT(pResult != NULL);
78668     DRFLAC_ASSERT(bitCount > 0);
78669     DRFLAC_ASSERT(bitCount <= 16);
78670     if (!drflac__read_int32(bs, bitCount, &result)) {
78671         return DRFLAC_FALSE;
78672     }
78673     *pResult = (drflac_int16)result;
78674     return DRFLAC_TRUE;
78675 }
78676 #endif
78677 static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, drflac_uint8* pResult)
78678 {
78679     drflac_uint32 result;
78680     DRFLAC_ASSERT(bs != NULL);
78681     DRFLAC_ASSERT(pResult != NULL);
78682     DRFLAC_ASSERT(bitCount > 0);
78683     DRFLAC_ASSERT(bitCount <= 8);
78684     if (!drflac__read_uint32(bs, bitCount, &result)) {
78685         return DRFLAC_FALSE;
78686     }
78687     *pResult = (drflac_uint8)result;
78688     return DRFLAC_TRUE;
78689 }
78690 static drflac_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, drflac_int8* pResult)
78691 {
78692     drflac_int32 result;
78693     DRFLAC_ASSERT(bs != NULL);
78694     DRFLAC_ASSERT(pResult != NULL);
78695     DRFLAC_ASSERT(bitCount > 0);
78696     DRFLAC_ASSERT(bitCount <= 8);
78697     if (!drflac__read_int32(bs, bitCount, &result)) {
78698         return DRFLAC_FALSE;
78699     }
78700     *pResult = (drflac_int8)result;
78701     return DRFLAC_TRUE;
78702 }
78703 static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
78704 {
78705     if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
78706         bs->consumedBits += (drflac_uint32)bitsToSeek;
78707         bs->cache <<= bitsToSeek;
78708         return DRFLAC_TRUE;
78709     } else {
78710         bitsToSeek       -= DRFLAC_CACHE_L1_BITS_REMAINING(bs);
78711         bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs);
78712         bs->cache         = 0;
78713 #ifdef DRFLAC_64BIT
78714         while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
78715             drflac_uint64 bin;
78716             if (!drflac__read_uint64(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) {
78717                 return DRFLAC_FALSE;
78718             }
78719             bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs);
78720         }
78721 #else
78722         while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
78723             drflac_uint32 bin;
78724             if (!drflac__read_uint32(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) {
78725                 return DRFLAC_FALSE;
78726             }
78727             bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs);
78728         }
78729 #endif
78730         while (bitsToSeek >= 8) {
78731             drflac_uint8 bin;
78732             if (!drflac__read_uint8(bs, 8, &bin)) {
78733                 return DRFLAC_FALSE;
78734             }
78735             bitsToSeek -= 8;
78736         }
78737         if (bitsToSeek > 0) {
78738             drflac_uint8 bin;
78739             if (!drflac__read_uint8(bs, (drflac_uint32)bitsToSeek, &bin)) {
78740                 return DRFLAC_FALSE;
78741             }
78742             bitsToSeek = 0;
78743         }
78744         DRFLAC_ASSERT(bitsToSeek == 0);
78745         return DRFLAC_TRUE;
78746     }
78747 }
78748 static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs)
78749 {
78750     DRFLAC_ASSERT(bs != NULL);
78751     if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) {
78752         return DRFLAC_FALSE;
78753     }
78754     for (;;) {
78755         drflac_uint8 hi;
78756 #ifndef DR_FLAC_NO_CRC
78757         drflac__reset_crc16(bs);
78758 #endif
78759         if (!drflac__read_uint8(bs, 8, &hi)) {
78760             return DRFLAC_FALSE;
78761         }
78762         if (hi == 0xFF) {
78763             drflac_uint8 lo;
78764             if (!drflac__read_uint8(bs, 6, &lo)) {
78765                 return DRFLAC_FALSE;
78766             }
78767             if (lo == 0x3E) {
78768                 return DRFLAC_TRUE;
78769             } else {
78770                 if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) {
78771                     return DRFLAC_FALSE;
78772                 }
78773             }
78774         }
78775     }
78776 }
78777 #if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
78778 #define DRFLAC_IMPLEMENT_CLZ_LZCNT
78779 #endif
78780 #if  defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(__clang__)
78781 #define DRFLAC_IMPLEMENT_CLZ_MSVC
78782 #endif
78783 #if  defined(__WATCOMC__) && defined(__386__)
78784 #define DRFLAC_IMPLEMENT_CLZ_WATCOM
78785 #endif
78786 static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x)
78787 {
78788     drflac_uint32 n;
78789     static drflac_uint32 clz_table_4[] = {
78790         0,
78791         4,
78792         3, 3,
78793         2, 2, 2, 2,
78794         1, 1, 1, 1, 1, 1, 1, 1
78795     };
78796     if (x == 0) {
78797         return sizeof(x)*8;
78798     }
78799     n = clz_table_4[x >> (sizeof(x)*8 - 4)];
78800     if (n == 0) {
78801 #ifdef DRFLAC_64BIT
78802         if ((x & ((drflac_uint64)0xFFFFFFFF << 32)) == 0) { n  = 32; x <<= 32; }
78803         if ((x & ((drflac_uint64)0xFFFF0000 << 32)) == 0) { n += 16; x <<= 16; }
78804         if ((x & ((drflac_uint64)0xFF000000 << 32)) == 0) { n += 8;  x <<= 8;  }
78805         if ((x & ((drflac_uint64)0xF0000000 << 32)) == 0) { n += 4;  x <<= 4;  }
78806 #else
78807         if ((x & 0xFFFF0000) == 0) { n  = 16; x <<= 16; }
78808         if ((x & 0xFF000000) == 0) { n += 8;  x <<= 8;  }
78809         if ((x & 0xF0000000) == 0) { n += 4;  x <<= 4;  }
78810 #endif
78811         n += clz_table_4[x >> (sizeof(x)*8 - 4)];
78812     }
78813     return n - 1;
78814 }
78815 #ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT
78816 static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported(void)
78817 {
78818 #if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5)
78819     return DRFLAC_TRUE;
78820 #else
78821     #ifdef DRFLAC_HAS_LZCNT_INTRINSIC
78822         return drflac__gIsLZCNTSupported;
78823     #else
78824         return DRFLAC_FALSE;
78825     #endif
78826 #endif
78827 }
78828 static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x)
78829 {
78830 #if defined(_MSC_VER)
78831     #ifdef DRFLAC_64BIT
78832         return (drflac_uint32)__lzcnt64(x);
78833     #else
78834         return (drflac_uint32)__lzcnt(x);
78835     #endif
78836 #else
78837     #if defined(__GNUC__) || defined(__clang__)
78838         #if defined(DRFLAC_X64)
78839             {
78840                 drflac_uint64 r;
78841                 __asm__ __volatile__ (
78842                     "lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
78843                 );
78844                 return (drflac_uint32)r;
78845             }
78846         #elif defined(DRFLAC_X86)
78847             {
78848                 drflac_uint32 r;
78849                 __asm__ __volatile__ (
78850                     "lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
78851                 );
78852                 return r;
78853             }
78854         #elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(DRFLAC_64BIT)
78855             {
78856                 unsigned int r;
78857                 __asm__ __volatile__ (
78858                 #if defined(DRFLAC_64BIT)
78859                     "clz %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(x)
78860                 #else
78861                     "clz %[out], %[in]" : [out]"=r"(r) : [in]"r"(x)
78862                 #endif
78863                 );
78864                 return r;
78865             }
78866         #else
78867             if (x == 0) {
78868                 return sizeof(x)*8;
78869             }
78870             #ifdef DRFLAC_64BIT
78871                 return (drflac_uint32)__builtin_clzll((drflac_uint64)x);
78872             #else
78873                 return (drflac_uint32)__builtin_clzl((drflac_uint32)x);
78874             #endif
78875         #endif
78876     #else
78877         #error "This compiler does not support the lzcnt intrinsic."
78878     #endif
78879 #endif
78880 }
78881 #endif
78882 #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC
78883 #include <intrin.h>
78884 static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x)
78885 {
78886     drflac_uint32 n;
78887     if (x == 0) {
78888         return sizeof(x)*8;
78889     }
78890 #ifdef DRFLAC_64BIT
78891     _BitScanReverse64((unsigned long*)&n, x);
78892 #else
78893     _BitScanReverse((unsigned long*)&n, x);
78894 #endif
78895     return sizeof(x)*8 - n - 1;
78896 }
78897 #endif
78898 #ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM
78899 static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32);
78900 #pragma aux drflac__clz_watcom = \
78901     "bsr eax, eax" \
78902     "xor eax, 31" \
78903     parm [eax] nomemory \
78904     value [eax] \
78905     modify exact [eax] nomemory;
78906 #endif
78907 static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x)
78908 {
78909 #ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT
78910     if (drflac__is_lzcnt_supported()) {
78911         return drflac__clz_lzcnt(x);
78912     } else
78913 #endif
78914     {
78915 #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC
78916         return drflac__clz_msvc(x);
78917 #elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM)
78918         return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x);
78919 #else
78920         return drflac__clz_software(x);
78921 #endif
78922     }
78923 }
78924 static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut)
78925 {
78926     drflac_uint32 zeroCounter = 0;
78927     drflac_uint32 setBitOffsetPlus1;
78928     while (bs->cache == 0) {
78929         zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs);
78930         if (!drflac__reload_cache(bs)) {
78931             return DRFLAC_FALSE;
78932         }
78933     }
78934     setBitOffsetPlus1 = drflac__clz(bs->cache);
78935     setBitOffsetPlus1 += 1;
78936     bs->consumedBits += setBitOffsetPlus1;
78937     bs->cache <<= setBitOffsetPlus1;
78938     *pOffsetOut = zeroCounter + setBitOffsetPlus1 - 1;
78939     return DRFLAC_TRUE;
78940 }
78941 static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFromStart)
78942 {
78943     DRFLAC_ASSERT(bs != NULL);
78944     DRFLAC_ASSERT(offsetFromStart > 0);
78945     if (offsetFromStart > 0x7FFFFFFF) {
78946         drflac_uint64 bytesRemaining = offsetFromStart;
78947         if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
78948             return DRFLAC_FALSE;
78949         }
78950         bytesRemaining -= 0x7FFFFFFF;
78951         while (bytesRemaining > 0x7FFFFFFF) {
78952             if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
78953                 return DRFLAC_FALSE;
78954             }
78955             bytesRemaining -= 0x7FFFFFFF;
78956         }
78957         if (bytesRemaining > 0) {
78958             if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) {
78959                 return DRFLAC_FALSE;
78960             }
78961         }
78962     } else {
78963         if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) {
78964             return DRFLAC_FALSE;
78965         }
78966     }
78967     drflac__reset_cache(bs);
78968     return DRFLAC_TRUE;
78969 }
78970 static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64* pNumberOut, drflac_uint8* pCRCOut)
78971 {
78972     drflac_uint8 crc;
78973     drflac_uint64 result;
78974     drflac_uint8 utf8[7] = {0};
78975     int byteCount;
78976     int i;
78977     DRFLAC_ASSERT(bs != NULL);
78978     DRFLAC_ASSERT(pNumberOut != NULL);
78979     DRFLAC_ASSERT(pCRCOut != NULL);
78980     crc = *pCRCOut;
78981     if (!drflac__read_uint8(bs, 8, utf8)) {
78982         *pNumberOut = 0;
78983         return DRFLAC_AT_END;
78984     }
78985     crc = drflac_crc8(crc, utf8[0], 8);
78986     if ((utf8[0] & 0x80) == 0) {
78987         *pNumberOut = utf8[0];
78988         *pCRCOut = crc;
78989         return DRFLAC_SUCCESS;
78990     }
78991     if ((utf8[0] & 0xE0) == 0xC0) {
78992         byteCount = 2;
78993     } else if ((utf8[0] & 0xF0) == 0xE0) {
78994         byteCount = 3;
78995     } else if ((utf8[0] & 0xF8) == 0xF0) {
78996         byteCount = 4;
78997     } else if ((utf8[0] & 0xFC) == 0xF8) {
78998         byteCount = 5;
78999     } else if ((utf8[0] & 0xFE) == 0xFC) {
79000         byteCount = 6;
79001     } else if ((utf8[0] & 0xFF) == 0xFE) {
79002         byteCount = 7;
79003     } else {
79004         *pNumberOut = 0;
79005         return DRFLAC_CRC_MISMATCH;
79006     }
79007     DRFLAC_ASSERT(byteCount > 1);
79008     result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1)));
79009     for (i = 1; i < byteCount; ++i) {
79010         if (!drflac__read_uint8(bs, 8, utf8 + i)) {
79011             *pNumberOut = 0;
79012             return DRFLAC_AT_END;
79013         }
79014         crc = drflac_crc8(crc, utf8[i], 8);
79015         result = (result << 6) | (utf8[i] & 0x3F);
79016     }
79017     *pNumberOut = result;
79018     *pCRCOut = crc;
79019     return DRFLAC_SUCCESS;
79020 }
79021 static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
79022 {
79023     drflac_int32 prediction = 0;
79024     DRFLAC_ASSERT(order <= 32);
79025     switch (order)
79026     {
79027     case 32: prediction += coefficients[31] * pDecodedSamples[-32];
79028     case 31: prediction += coefficients[30] * pDecodedSamples[-31];
79029     case 30: prediction += coefficients[29] * pDecodedSamples[-30];
79030     case 29: prediction += coefficients[28] * pDecodedSamples[-29];
79031     case 28: prediction += coefficients[27] * pDecodedSamples[-28];
79032     case 27: prediction += coefficients[26] * pDecodedSamples[-27];
79033     case 26: prediction += coefficients[25] * pDecodedSamples[-26];
79034     case 25: prediction += coefficients[24] * pDecodedSamples[-25];
79035     case 24: prediction += coefficients[23] * pDecodedSamples[-24];
79036     case 23: prediction += coefficients[22] * pDecodedSamples[-23];
79037     case 22: prediction += coefficients[21] * pDecodedSamples[-22];
79038     case 21: prediction += coefficients[20] * pDecodedSamples[-21];
79039     case 20: prediction += coefficients[19] * pDecodedSamples[-20];
79040     case 19: prediction += coefficients[18] * pDecodedSamples[-19];
79041     case 18: prediction += coefficients[17] * pDecodedSamples[-18];
79042     case 17: prediction += coefficients[16] * pDecodedSamples[-17];
79043     case 16: prediction += coefficients[15] * pDecodedSamples[-16];
79044     case 15: prediction += coefficients[14] * pDecodedSamples[-15];
79045     case 14: prediction += coefficients[13] * pDecodedSamples[-14];
79046     case 13: prediction += coefficients[12] * pDecodedSamples[-13];
79047     case 12: prediction += coefficients[11] * pDecodedSamples[-12];
79048     case 11: prediction += coefficients[10] * pDecodedSamples[-11];
79049     case 10: prediction += coefficients[ 9] * pDecodedSamples[-10];
79050     case  9: prediction += coefficients[ 8] * pDecodedSamples[- 9];
79051     case  8: prediction += coefficients[ 7] * pDecodedSamples[- 8];
79052     case  7: prediction += coefficients[ 6] * pDecodedSamples[- 7];
79053     case  6: prediction += coefficients[ 5] * pDecodedSamples[- 6];
79054     case  5: prediction += coefficients[ 4] * pDecodedSamples[- 5];
79055     case  4: prediction += coefficients[ 3] * pDecodedSamples[- 4];
79056     case  3: prediction += coefficients[ 2] * pDecodedSamples[- 3];
79057     case  2: prediction += coefficients[ 1] * pDecodedSamples[- 2];
79058     case  1: prediction += coefficients[ 0] * pDecodedSamples[- 1];
79059     }
79060     return (drflac_int32)(prediction >> shift);
79061 }
79062 static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
79063 {
79064     drflac_int64 prediction;
79065     DRFLAC_ASSERT(order <= 32);
79066 #ifndef DRFLAC_64BIT
79067     if (order == 8)
79068     {
79069         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
79070         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
79071         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
79072         prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
79073         prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
79074         prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
79075         prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
79076         prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8];
79077     }
79078     else if (order == 7)
79079     {
79080         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
79081         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
79082         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
79083         prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
79084         prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
79085         prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
79086         prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
79087     }
79088     else if (order == 3)
79089     {
79090         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
79091         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
79092         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
79093     }
79094     else if (order == 6)
79095     {
79096         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
79097         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
79098         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
79099         prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
79100         prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
79101         prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
79102     }
79103     else if (order == 5)
79104     {
79105         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
79106         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
79107         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
79108         prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
79109         prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
79110     }
79111     else if (order == 4)
79112     {
79113         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
79114         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
79115         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
79116         prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
79117     }
79118     else if (order == 12)
79119     {
79120         prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
79121         prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
79122         prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
79123         prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
79124         prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
79125         prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
79126         prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
79127         prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
79128         prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
79129         prediction += coefficients[9]  * (drflac_int64)pDecodedSamples[-10];
79130         prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
79131         prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12];
79132     }
79133     else if (order == 2)
79134     {
79135         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
79136         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
79137     }
79138     else if (order == 1)
79139     {
79140         prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
79141     }
79142     else if (order == 10)
79143     {
79144         prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
79145         prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
79146         prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
79147         prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
79148         prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
79149         prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
79150         prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
79151         prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
79152         prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
79153         prediction += coefficients[9]  * (drflac_int64)pDecodedSamples[-10];
79154     }
79155     else if (order == 9)
79156     {
79157         prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
79158         prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
79159         prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
79160         prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
79161         prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
79162         prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
79163         prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
79164         prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
79165         prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
79166     }
79167     else if (order == 11)
79168     {
79169         prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
79170         prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
79171         prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
79172         prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
79173         prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
79174         prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
79175         prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
79176         prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
79177         prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
79178         prediction += coefficients[9]  * (drflac_int64)pDecodedSamples[-10];
79179         prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
79180     }
79181     else
79182     {
79183         int j;
79184         prediction = 0;
79185         for (j = 0; j < (int)order; ++j) {
79186             prediction += coefficients[j] * (drflac_int64)pDecodedSamples[-j-1];
79187         }
79188     }
79189 #endif
79190 #ifdef DRFLAC_64BIT
79191     prediction = 0;
79192     switch (order)
79193     {
79194     case 32: prediction += coefficients[31] * (drflac_int64)pDecodedSamples[-32];
79195     case 31: prediction += coefficients[30] * (drflac_int64)pDecodedSamples[-31];
79196     case 30: prediction += coefficients[29] * (drflac_int64)pDecodedSamples[-30];
79197     case 29: prediction += coefficients[28] * (drflac_int64)pDecodedSamples[-29];
79198     case 28: prediction += coefficients[27] * (drflac_int64)pDecodedSamples[-28];
79199     case 27: prediction += coefficients[26] * (drflac_int64)pDecodedSamples[-27];
79200     case 26: prediction += coefficients[25] * (drflac_int64)pDecodedSamples[-26];
79201     case 25: prediction += coefficients[24] * (drflac_int64)pDecodedSamples[-25];
79202     case 24: prediction += coefficients[23] * (drflac_int64)pDecodedSamples[-24];
79203     case 23: prediction += coefficients[22] * (drflac_int64)pDecodedSamples[-23];
79204     case 22: prediction += coefficients[21] * (drflac_int64)pDecodedSamples[-22];
79205     case 21: prediction += coefficients[20] * (drflac_int64)pDecodedSamples[-21];
79206     case 20: prediction += coefficients[19] * (drflac_int64)pDecodedSamples[-20];
79207     case 19: prediction += coefficients[18] * (drflac_int64)pDecodedSamples[-19];
79208     case 18: prediction += coefficients[17] * (drflac_int64)pDecodedSamples[-18];
79209     case 17: prediction += coefficients[16] * (drflac_int64)pDecodedSamples[-17];
79210     case 16: prediction += coefficients[15] * (drflac_int64)pDecodedSamples[-16];
79211     case 15: prediction += coefficients[14] * (drflac_int64)pDecodedSamples[-15];
79212     case 14: prediction += coefficients[13] * (drflac_int64)pDecodedSamples[-14];
79213     case 13: prediction += coefficients[12] * (drflac_int64)pDecodedSamples[-13];
79214     case 12: prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12];
79215     case 11: prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
79216     case 10: prediction += coefficients[ 9] * (drflac_int64)pDecodedSamples[-10];
79217     case  9: prediction += coefficients[ 8] * (drflac_int64)pDecodedSamples[- 9];
79218     case  8: prediction += coefficients[ 7] * (drflac_int64)pDecodedSamples[- 8];
79219     case  7: prediction += coefficients[ 6] * (drflac_int64)pDecodedSamples[- 7];
79220     case  6: prediction += coefficients[ 5] * (drflac_int64)pDecodedSamples[- 6];
79221     case  5: prediction += coefficients[ 4] * (drflac_int64)pDecodedSamples[- 5];
79222     case  4: prediction += coefficients[ 3] * (drflac_int64)pDecodedSamples[- 4];
79223     case  3: prediction += coefficients[ 2] * (drflac_int64)pDecodedSamples[- 3];
79224     case  2: prediction += coefficients[ 1] * (drflac_int64)pDecodedSamples[- 2];
79225     case  1: prediction += coefficients[ 0] * (drflac_int64)pDecodedSamples[- 1];
79226     }
79227 #endif
79228     return (drflac_int32)(prediction >> shift);
79229 }
79230 #if 0
79231 static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
79232 {
79233     drflac_uint32 i;
79234     DRFLAC_ASSERT(bs != NULL);
79235     DRFLAC_ASSERT(pSamplesOut != NULL);
79236     for (i = 0; i < count; ++i) {
79237         drflac_uint32 zeroCounter = 0;
79238         for (;;) {
79239             drflac_uint8 bit;
79240             if (!drflac__read_uint8(bs, 1, &bit)) {
79241                 return DRFLAC_FALSE;
79242             }
79243             if (bit == 0) {
79244                 zeroCounter += 1;
79245             } else {
79246                 break;
79247             }
79248         }
79249         drflac_uint32 decodedRice;
79250         if (riceParam > 0) {
79251             if (!drflac__read_uint32(bs, riceParam, &decodedRice)) {
79252                 return DRFLAC_FALSE;
79253             }
79254         } else {
79255             decodedRice = 0;
79256         }
79257         decodedRice |= (zeroCounter << riceParam);
79258         if ((decodedRice & 0x01)) {
79259             decodedRice = ~(decodedRice >> 1);
79260         } else {
79261             decodedRice =  (decodedRice >> 1);
79262         }
79263         if (bitsPerSample+shift >= 32) {
79264             pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i);
79265         } else {
79266             pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i);
79267         }
79268     }
79269     return DRFLAC_TRUE;
79270 }
79271 #endif
79272 #if 0
79273 static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
79274 {
79275     drflac_uint32 zeroCounter = 0;
79276     drflac_uint32 decodedRice;
79277     for (;;) {
79278         drflac_uint8 bit;
79279         if (!drflac__read_uint8(bs, 1, &bit)) {
79280             return DRFLAC_FALSE;
79281         }
79282         if (bit == 0) {
79283             zeroCounter += 1;
79284         } else {
79285             break;
79286         }
79287     }
79288     if (riceParam > 0) {
79289         if (!drflac__read_uint32(bs, riceParam, &decodedRice)) {
79290             return DRFLAC_FALSE;
79291         }
79292     } else {
79293         decodedRice = 0;
79294     }
79295     *pZeroCounterOut = zeroCounter;
79296     *pRiceParamPartOut = decodedRice;
79297     return DRFLAC_TRUE;
79298 }
79299 #endif
79300 #if 0
79301 static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
79302 {
79303     drflac_cache_t riceParamMask;
79304     drflac_uint32 zeroCounter;
79305     drflac_uint32 setBitOffsetPlus1;
79306     drflac_uint32 riceParamPart;
79307     drflac_uint32 riceLength;
79308     DRFLAC_ASSERT(riceParam > 0);
79309     riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam);
79310     zeroCounter = 0;
79311     while (bs->cache == 0) {
79312         zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs);
79313         if (!drflac__reload_cache(bs)) {
79314             return DRFLAC_FALSE;
79315         }
79316     }
79317     setBitOffsetPlus1 = drflac__clz(bs->cache);
79318     zeroCounter += setBitOffsetPlus1;
79319     setBitOffsetPlus1 += 1;
79320     riceLength = setBitOffsetPlus1 + riceParam;
79321     if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
79322         riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength));
79323         bs->consumedBits += riceLength;
79324         bs->cache <<= riceLength;
79325     } else {
79326         drflac_uint32 bitCountLo;
79327         drflac_cache_t resultHi;
79328         bs->consumedBits += riceLength;
79329         bs->cache <<= setBitOffsetPlus1 & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1);
79330         bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs);
79331         resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam);
79332         if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
79333 #ifndef DR_FLAC_NO_CRC
79334             drflac__update_crc16(bs);
79335 #endif
79336             bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
79337             bs->consumedBits = 0;
79338 #ifndef DR_FLAC_NO_CRC
79339             bs->crc16Cache = bs->cache;
79340 #endif
79341         } else {
79342             if (!drflac__reload_cache(bs)) {
79343                 return DRFLAC_FALSE;
79344             }
79345         }
79346         riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo));
79347         bs->consumedBits += bitCountLo;
79348         bs->cache <<= bitCountLo;
79349     }
79350     pZeroCounterOut[0] = zeroCounter;
79351     pRiceParamPartOut[0] = riceParamPart;
79352     return DRFLAC_TRUE;
79353 }
79354 #endif
79355 static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
79356 {
79357     drflac_uint32  riceParamPlus1 = riceParam + 1;
79358     drflac_uint32  riceParamPlus1Shift = DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPlus1);
79359     drflac_uint32  riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1;
79360     drflac_cache_t bs_cache = bs->cache;
79361     drflac_uint32  bs_consumedBits = bs->consumedBits;
79362     drflac_uint32  lzcount = drflac__clz(bs_cache);
79363     if (lzcount < sizeof(bs_cache)*8) {
79364         pZeroCounterOut[0] = lzcount;
79365     extract_rice_param_part:
79366         bs_cache       <<= lzcount;
79367         bs_consumedBits += lzcount;
79368         if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) {
79369             pRiceParamPartOut[0] = (drflac_uint32)(bs_cache >> riceParamPlus1Shift);
79370             bs_cache       <<= riceParamPlus1;
79371             bs_consumedBits += riceParamPlus1;
79372         } else {
79373             drflac_uint32 riceParamPartHi;
79374             drflac_uint32 riceParamPartLo;
79375             drflac_uint32 riceParamPartLoBitCount;
79376             riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift);
79377             riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits;
79378             DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32);
79379             if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
79380             #ifndef DR_FLAC_NO_CRC
79381                 drflac__update_crc16(bs);
79382             #endif
79383                 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
79384                 bs_consumedBits = riceParamPartLoBitCount;
79385             #ifndef DR_FLAC_NO_CRC
79386                 bs->crc16Cache = bs_cache;
79387             #endif
79388             } else {
79389                 if (!drflac__reload_cache(bs)) {
79390                     return DRFLAC_FALSE;
79391                 }
79392                 bs_cache = bs->cache;
79393                 bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount;
79394             }
79395             riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount)));
79396             pRiceParamPartOut[0] = riceParamPartHi | riceParamPartLo;
79397             bs_cache <<= riceParamPartLoBitCount;
79398         }
79399     } else {
79400         drflac_uint32 zeroCounter = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs_consumedBits);
79401         for (;;) {
79402             if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
79403             #ifndef DR_FLAC_NO_CRC
79404                 drflac__update_crc16(bs);
79405             #endif
79406                 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
79407                 bs_consumedBits = 0;
79408             #ifndef DR_FLAC_NO_CRC
79409                 bs->crc16Cache = bs_cache;
79410             #endif
79411             } else {
79412                 if (!drflac__reload_cache(bs)) {
79413                     return DRFLAC_FALSE;
79414                 }
79415                 bs_cache = bs->cache;
79416                 bs_consumedBits = bs->consumedBits;
79417             }
79418             lzcount = drflac__clz(bs_cache);
79419             zeroCounter += lzcount;
79420             if (lzcount < sizeof(bs_cache)*8) {
79421                 break;
79422             }
79423         }
79424         pZeroCounterOut[0] = zeroCounter;
79425         goto extract_rice_param_part;
79426     }
79427     bs->cache = bs_cache;
79428     bs->consumedBits = bs_consumedBits;
79429     return DRFLAC_TRUE;
79430 }
79431 static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac_uint8 riceParam)
79432 {
79433     drflac_uint32  riceParamPlus1 = riceParam + 1;
79434     drflac_uint32  riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1;
79435     drflac_cache_t bs_cache = bs->cache;
79436     drflac_uint32  bs_consumedBits = bs->consumedBits;
79437     drflac_uint32  lzcount = drflac__clz(bs_cache);
79438     if (lzcount < sizeof(bs_cache)*8) {
79439     extract_rice_param_part:
79440         bs_cache       <<= lzcount;
79441         bs_consumedBits += lzcount;
79442         if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) {
79443             bs_cache       <<= riceParamPlus1;
79444             bs_consumedBits += riceParamPlus1;
79445         } else {
79446             drflac_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits;
79447             DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32);
79448             if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
79449             #ifndef DR_FLAC_NO_CRC
79450                 drflac__update_crc16(bs);
79451             #endif
79452                 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
79453                 bs_consumedBits = riceParamPartLoBitCount;
79454             #ifndef DR_FLAC_NO_CRC
79455                 bs->crc16Cache = bs_cache;
79456             #endif
79457             } else {
79458                 if (!drflac__reload_cache(bs)) {
79459                     return DRFLAC_FALSE;
79460                 }
79461                 bs_cache = bs->cache;
79462                 bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount;
79463             }
79464             bs_cache <<= riceParamPartLoBitCount;
79465         }
79466     } else {
79467         for (;;) {
79468             if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
79469             #ifndef DR_FLAC_NO_CRC
79470                 drflac__update_crc16(bs);
79471             #endif
79472                 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
79473                 bs_consumedBits = 0;
79474             #ifndef DR_FLAC_NO_CRC
79475                 bs->crc16Cache = bs_cache;
79476             #endif
79477             } else {
79478                 if (!drflac__reload_cache(bs)) {
79479                     return DRFLAC_FALSE;
79480                 }
79481                 bs_cache = bs->cache;
79482                 bs_consumedBits = bs->consumedBits;
79483             }
79484             lzcount = drflac__clz(bs_cache);
79485             if (lzcount < sizeof(bs_cache)*8) {
79486                 break;
79487             }
79488         }
79489         goto extract_rice_param_part;
79490     }
79491     bs->cache = bs_cache;
79492     bs->consumedBits = bs_consumedBits;
79493     return DRFLAC_TRUE;
79494 }
79495 static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorder(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
79496 {
79497     drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
79498     drflac_uint32 zeroCountPart0;
79499     drflac_uint32 riceParamPart0;
79500     drflac_uint32 riceParamMask;
79501     drflac_uint32 i;
79502     DRFLAC_ASSERT(bs != NULL);
79503     DRFLAC_ASSERT(pSamplesOut != NULL);
79504     (void)bitsPerSample;
79505     (void)order;
79506     (void)shift;
79507     (void)coefficients;
79508     riceParamMask  = (drflac_uint32)~((~0UL) << riceParam);
79509     i = 0;
79510     while (i < count) {
79511         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) {
79512             return DRFLAC_FALSE;
79513         }
79514         riceParamPart0 &= riceParamMask;
79515         riceParamPart0 |= (zeroCountPart0 << riceParam);
79516         riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
79517         pSamplesOut[i] = riceParamPart0;
79518         i += 1;
79519     }
79520     return DRFLAC_TRUE;
79521 }
79522 static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
79523 {
79524     drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
79525     drflac_uint32 zeroCountPart0 = 0;
79526     drflac_uint32 zeroCountPart1 = 0;
79527     drflac_uint32 zeroCountPart2 = 0;
79528     drflac_uint32 zeroCountPart3 = 0;
79529     drflac_uint32 riceParamPart0 = 0;
79530     drflac_uint32 riceParamPart1 = 0;
79531     drflac_uint32 riceParamPart2 = 0;
79532     drflac_uint32 riceParamPart3 = 0;
79533     drflac_uint32 riceParamMask;
79534     const drflac_int32* pSamplesOutEnd;
79535     drflac_uint32 i;
79536     DRFLAC_ASSERT(bs != NULL);
79537     DRFLAC_ASSERT(pSamplesOut != NULL);
79538     if (order == 0) {
79539         return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
79540     }
79541     riceParamMask  = (drflac_uint32)~((~0UL) << riceParam);
79542     pSamplesOutEnd = pSamplesOut + (count & ~3);
79543     if (bitsPerSample+shift > 32) {
79544         while (pSamplesOut < pSamplesOutEnd) {
79545             if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) ||
79546                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) ||
79547                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) ||
79548                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) {
79549                 return DRFLAC_FALSE;
79550             }
79551             riceParamPart0 &= riceParamMask;
79552             riceParamPart1 &= riceParamMask;
79553             riceParamPart2 &= riceParamMask;
79554             riceParamPart3 &= riceParamMask;
79555             riceParamPart0 |= (zeroCountPart0 << riceParam);
79556             riceParamPart1 |= (zeroCountPart1 << riceParam);
79557             riceParamPart2 |= (zeroCountPart2 << riceParam);
79558             riceParamPart3 |= (zeroCountPart3 << riceParam);
79559             riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
79560             riceParamPart1  = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01];
79561             riceParamPart2  = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01];
79562             riceParamPart3  = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01];
79563             pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0);
79564             pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 1);
79565             pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 2);
79566             pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 3);
79567             pSamplesOut += 4;
79568         }
79569     } else {
79570         while (pSamplesOut < pSamplesOutEnd) {
79571             if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) ||
79572                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) ||
79573                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) ||
79574                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) {
79575                 return DRFLAC_FALSE;
79576             }
79577             riceParamPart0 &= riceParamMask;
79578             riceParamPart1 &= riceParamMask;
79579             riceParamPart2 &= riceParamMask;
79580             riceParamPart3 &= riceParamMask;
79581             riceParamPart0 |= (zeroCountPart0 << riceParam);
79582             riceParamPart1 |= (zeroCountPart1 << riceParam);
79583             riceParamPart2 |= (zeroCountPart2 << riceParam);
79584             riceParamPart3 |= (zeroCountPart3 << riceParam);
79585             riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
79586             riceParamPart1  = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01];
79587             riceParamPart2  = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01];
79588             riceParamPart3  = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01];
79589             pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0);
79590             pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 1);
79591             pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 2);
79592             pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 3);
79593             pSamplesOut += 4;
79594         }
79595     }
79596     i = (count & ~3);
79597     while (i < count) {
79598         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) {
79599             return DRFLAC_FALSE;
79600         }
79601         riceParamPart0 &= riceParamMask;
79602         riceParamPart0 |= (zeroCountPart0 << riceParam);
79603         riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
79604         if (bitsPerSample+shift > 32) {
79605             pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0);
79606         } else {
79607             pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0);
79608         }
79609         i += 1;
79610         pSamplesOut += 1;
79611     }
79612     return DRFLAC_TRUE;
79613 }
79614 #if defined(DRFLAC_SUPPORT_SSE2)
79615 static DRFLAC_INLINE __m128i drflac__mm_packs_interleaved_epi32(__m128i a, __m128i b)
79616 {
79617     __m128i r;
79618     r = _mm_packs_epi32(a, b);
79619     r = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 1, 2, 0));
79620     r = _mm_shufflehi_epi16(r, _MM_SHUFFLE(3, 1, 2, 0));
79621     r = _mm_shufflelo_epi16(r, _MM_SHUFFLE(3, 1, 2, 0));
79622     return r;
79623 }
79624 #endif
79625 #if defined(DRFLAC_SUPPORT_SSE41)
79626 static DRFLAC_INLINE __m128i drflac__mm_not_si128(__m128i a)
79627 {
79628     return _mm_xor_si128(a, _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()));
79629 }
79630 static DRFLAC_INLINE __m128i drflac__mm_hadd_epi32(__m128i x)
79631 {
79632     __m128i x64 = _mm_add_epi32(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2)));
79633     __m128i x32 = _mm_shufflelo_epi16(x64, _MM_SHUFFLE(1, 0, 3, 2));
79634     return _mm_add_epi32(x64, x32);
79635 }
79636 static DRFLAC_INLINE __m128i drflac__mm_hadd_epi64(__m128i x)
79637 {
79638     return _mm_add_epi64(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2)));
79639 }
79640 static DRFLAC_INLINE __m128i drflac__mm_srai_epi64(__m128i x, int count)
79641 {
79642     __m128i lo = _mm_srli_epi64(x, count);
79643     __m128i hi = _mm_srai_epi32(x, count);
79644     hi = _mm_and_si128(hi, _mm_set_epi32(0xFFFFFFFF, 0, 0xFFFFFFFF, 0));
79645     return _mm_or_si128(lo, hi);
79646 }
79647 static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
79648 {
79649     int i;
79650     drflac_uint32 riceParamMask;
79651     drflac_int32* pDecodedSamples    = pSamplesOut;
79652     drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
79653     drflac_uint32 zeroCountParts0 = 0;
79654     drflac_uint32 zeroCountParts1 = 0;
79655     drflac_uint32 zeroCountParts2 = 0;
79656     drflac_uint32 zeroCountParts3 = 0;
79657     drflac_uint32 riceParamParts0 = 0;
79658     drflac_uint32 riceParamParts1 = 0;
79659     drflac_uint32 riceParamParts2 = 0;
79660     drflac_uint32 riceParamParts3 = 0;
79661     __m128i coefficients128_0;
79662     __m128i coefficients128_4;
79663     __m128i coefficients128_8;
79664     __m128i samples128_0;
79665     __m128i samples128_4;
79666     __m128i samples128_8;
79667     __m128i riceParamMask128;
79668     const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
79669     riceParamMask    = (drflac_uint32)~((~0UL) << riceParam);
79670     riceParamMask128 = _mm_set1_epi32(riceParamMask);
79671     coefficients128_0 = _mm_setzero_si128();
79672     coefficients128_4 = _mm_setzero_si128();
79673     coefficients128_8 = _mm_setzero_si128();
79674     samples128_0 = _mm_setzero_si128();
79675     samples128_4 = _mm_setzero_si128();
79676     samples128_8 = _mm_setzero_si128();
79677 #if 1
79678     {
79679         int runningOrder = order;
79680         if (runningOrder >= 4) {
79681             coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0));
79682             samples128_0      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 4));
79683             runningOrder -= 4;
79684         } else {
79685             switch (runningOrder) {
79686                 case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break;
79687                 case 2: coefficients128_0 = _mm_set_epi32(0, 0,               coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0,               0); break;
79688                 case 1: coefficients128_0 = _mm_set_epi32(0, 0,               0,               coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0,               0,               0); break;
79689             }
79690             runningOrder = 0;
79691         }
79692         if (runningOrder >= 4) {
79693             coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4));
79694             samples128_4      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 8));
79695             runningOrder -= 4;
79696         } else {
79697             switch (runningOrder) {
79698                 case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break;
79699                 case 2: coefficients128_4 = _mm_set_epi32(0, 0,               coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0,               0); break;
79700                 case 1: coefficients128_4 = _mm_set_epi32(0, 0,               0,               coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0,               0,               0); break;
79701             }
79702             runningOrder = 0;
79703         }
79704         if (runningOrder == 4) {
79705             coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8));
79706             samples128_8      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 12));
79707             runningOrder -= 4;
79708         } else {
79709             switch (runningOrder) {
79710                 case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break;
79711                 case 2: coefficients128_8 = _mm_set_epi32(0, 0,                coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0,                0); break;
79712                 case 1: coefficients128_8 = _mm_set_epi32(0, 0,                0,               coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0,                0,                0); break;
79713             }
79714             runningOrder = 0;
79715         }
79716         coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3));
79717         coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3));
79718         coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3));
79719     }
79720 #else
79721     switch (order)
79722     {
79723     case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12];
79724     case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11];
79725     case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10];
79726     case 9:  ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9];
79727     case 8:  ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8];
79728     case 7:  ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7];
79729     case 6:  ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6];
79730     case 5:  ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5];
79731     case 4:  ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4];
79732     case 3:  ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3];
79733     case 2:  ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2];
79734     case 1:  ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1];
79735     }
79736 #endif
79737     while (pDecodedSamples < pDecodedSamplesEnd) {
79738         __m128i prediction128;
79739         __m128i zeroCountPart128;
79740         __m128i riceParamPart128;
79741         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) ||
79742             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) ||
79743             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) ||
79744             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) {
79745             return DRFLAC_FALSE;
79746         }
79747         zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0);
79748         riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0);
79749         riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128);
79750         riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam));
79751         riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01))), _mm_set1_epi32(0x01)));
79752         if (order <= 4) {
79753             for (i = 0; i < 4; i += 1) {
79754                 prediction128 = _mm_mullo_epi32(coefficients128_0, samples128_0);
79755                 prediction128 = drflac__mm_hadd_epi32(prediction128);
79756                 prediction128 = _mm_srai_epi32(prediction128, shift);
79757                 prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
79758                 samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
79759                 riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
79760             }
79761         } else if (order <= 8) {
79762             for (i = 0; i < 4; i += 1) {
79763                 prediction128 =                              _mm_mullo_epi32(coefficients128_4, samples128_4);
79764                 prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0));
79765                 prediction128 = drflac__mm_hadd_epi32(prediction128);
79766                 prediction128 = _mm_srai_epi32(prediction128, shift);
79767                 prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
79768                 samples128_4 = _mm_alignr_epi8(samples128_0,  samples128_4, 4);
79769                 samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
79770                 riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
79771             }
79772         } else {
79773             for (i = 0; i < 4; i += 1) {
79774                 prediction128 =                              _mm_mullo_epi32(coefficients128_8, samples128_8);
79775                 prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_4, samples128_4));
79776                 prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0));
79777                 prediction128 = drflac__mm_hadd_epi32(prediction128);
79778                 prediction128 = _mm_srai_epi32(prediction128, shift);
79779                 prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
79780                 samples128_8 = _mm_alignr_epi8(samples128_4,  samples128_8, 4);
79781                 samples128_4 = _mm_alignr_epi8(samples128_0,  samples128_4, 4);
79782                 samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
79783                 riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
79784             }
79785         }
79786         _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0);
79787         pDecodedSamples += 4;
79788     }
79789     i = (count & ~3);
79790     while (i < (int)count) {
79791         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) {
79792             return DRFLAC_FALSE;
79793         }
79794         riceParamParts0 &= riceParamMask;
79795         riceParamParts0 |= (zeroCountParts0 << riceParam);
79796         riceParamParts0  = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01];
79797         pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples);
79798         i += 1;
79799         pDecodedSamples += 1;
79800     }
79801     return DRFLAC_TRUE;
79802 }
79803 static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
79804 {
79805     int i;
79806     drflac_uint32 riceParamMask;
79807     drflac_int32* pDecodedSamples    = pSamplesOut;
79808     drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
79809     drflac_uint32 zeroCountParts0 = 0;
79810     drflac_uint32 zeroCountParts1 = 0;
79811     drflac_uint32 zeroCountParts2 = 0;
79812     drflac_uint32 zeroCountParts3 = 0;
79813     drflac_uint32 riceParamParts0 = 0;
79814     drflac_uint32 riceParamParts1 = 0;
79815     drflac_uint32 riceParamParts2 = 0;
79816     drflac_uint32 riceParamParts3 = 0;
79817     __m128i coefficients128_0;
79818     __m128i coefficients128_4;
79819     __m128i coefficients128_8;
79820     __m128i samples128_0;
79821     __m128i samples128_4;
79822     __m128i samples128_8;
79823     __m128i prediction128;
79824     __m128i riceParamMask128;
79825     const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
79826     DRFLAC_ASSERT(order <= 12);
79827     riceParamMask    = (drflac_uint32)~((~0UL) << riceParam);
79828     riceParamMask128 = _mm_set1_epi32(riceParamMask);
79829     prediction128 = _mm_setzero_si128();
79830     coefficients128_0  = _mm_setzero_si128();
79831     coefficients128_4  = _mm_setzero_si128();
79832     coefficients128_8  = _mm_setzero_si128();
79833     samples128_0  = _mm_setzero_si128();
79834     samples128_4  = _mm_setzero_si128();
79835     samples128_8  = _mm_setzero_si128();
79836 #if 1
79837     {
79838         int runningOrder = order;
79839         if (runningOrder >= 4) {
79840             coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0));
79841             samples128_0      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 4));
79842             runningOrder -= 4;
79843         } else {
79844             switch (runningOrder) {
79845                 case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break;
79846                 case 2: coefficients128_0 = _mm_set_epi32(0, 0,               coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0,               0); break;
79847                 case 1: coefficients128_0 = _mm_set_epi32(0, 0,               0,               coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0,               0,               0); break;
79848             }
79849             runningOrder = 0;
79850         }
79851         if (runningOrder >= 4) {
79852             coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4));
79853             samples128_4      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 8));
79854             runningOrder -= 4;
79855         } else {
79856             switch (runningOrder) {
79857                 case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break;
79858                 case 2: coefficients128_4 = _mm_set_epi32(0, 0,               coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0,               0); break;
79859                 case 1: coefficients128_4 = _mm_set_epi32(0, 0,               0,               coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0,               0,               0); break;
79860             }
79861             runningOrder = 0;
79862         }
79863         if (runningOrder == 4) {
79864             coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8));
79865             samples128_8      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 12));
79866             runningOrder -= 4;
79867         } else {
79868             switch (runningOrder) {
79869                 case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break;
79870                 case 2: coefficients128_8 = _mm_set_epi32(0, 0,                coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0,                0); break;
79871                 case 1: coefficients128_8 = _mm_set_epi32(0, 0,                0,               coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0,                0,                0); break;
79872             }
79873             runningOrder = 0;
79874         }
79875         coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3));
79876         coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3));
79877         coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3));
79878     }
79879 #else
79880     switch (order)
79881     {
79882     case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12];
79883     case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11];
79884     case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10];
79885     case 9:  ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9];
79886     case 8:  ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8];
79887     case 7:  ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7];
79888     case 6:  ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6];
79889     case 5:  ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5];
79890     case 4:  ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4];
79891     case 3:  ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3];
79892     case 2:  ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2];
79893     case 1:  ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1];
79894     }
79895 #endif
79896     while (pDecodedSamples < pDecodedSamplesEnd) {
79897         __m128i zeroCountPart128;
79898         __m128i riceParamPart128;
79899         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) ||
79900             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) ||
79901             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) ||
79902             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) {
79903             return DRFLAC_FALSE;
79904         }
79905         zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0);
79906         riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0);
79907         riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128);
79908         riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam));
79909         riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(1))), _mm_set1_epi32(1)));
79910         for (i = 0; i < 4; i += 1) {
79911             prediction128 = _mm_xor_si128(prediction128, prediction128);
79912             switch (order)
79913             {
79914             case 12:
79915             case 11: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(1, 1, 0, 0))));
79916             case 10:
79917             case  9: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(3, 3, 2, 2))));
79918             case  8:
79919             case  7: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(1, 1, 0, 0))));
79920             case  6:
79921             case  5: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(3, 3, 2, 2))));
79922             case  4:
79923             case  3: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(1, 1, 0, 0))));
79924             case  2:
79925             case  1: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(3, 3, 2, 2))));
79926             }
79927             prediction128 = drflac__mm_hadd_epi64(prediction128);
79928             prediction128 = drflac__mm_srai_epi64(prediction128, shift);
79929             prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
79930             samples128_8 = _mm_alignr_epi8(samples128_4,  samples128_8, 4);
79931             samples128_4 = _mm_alignr_epi8(samples128_0,  samples128_4, 4);
79932             samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
79933             riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
79934         }
79935         _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0);
79936         pDecodedSamples += 4;
79937     }
79938     i = (count & ~3);
79939     while (i < (int)count) {
79940         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) {
79941             return DRFLAC_FALSE;
79942         }
79943         riceParamParts0 &= riceParamMask;
79944         riceParamParts0 |= (zeroCountParts0 << riceParam);
79945         riceParamParts0  = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01];
79946         pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples);
79947         i += 1;
79948         pDecodedSamples += 1;
79949     }
79950     return DRFLAC_TRUE;
79951 }
79952 static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
79953 {
79954     DRFLAC_ASSERT(bs != NULL);
79955     DRFLAC_ASSERT(pSamplesOut != NULL);
79956     if (order > 0 && order <= 12) {
79957         if (bitsPerSample+shift > 32) {
79958             return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
79959         } else {
79960             return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
79961         }
79962     } else {
79963         return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
79964     }
79965 }
79966 #endif
79967 #if defined(DRFLAC_SUPPORT_NEON)
79968 static DRFLAC_INLINE void drflac__vst2q_s32(drflac_int32* p, int32x4x2_t x)
79969 {
79970     vst1q_s32(p+0, x.val[0]);
79971     vst1q_s32(p+4, x.val[1]);
79972 }
79973 static DRFLAC_INLINE void drflac__vst2q_u32(drflac_uint32* p, uint32x4x2_t x)
79974 {
79975     vst1q_u32(p+0, x.val[0]);
79976     vst1q_u32(p+4, x.val[1]);
79977 }
79978 static DRFLAC_INLINE void drflac__vst2q_f32(float* p, float32x4x2_t x)
79979 {
79980     vst1q_f32(p+0, x.val[0]);
79981     vst1q_f32(p+4, x.val[1]);
79982 }
79983 static DRFLAC_INLINE void drflac__vst2q_s16(drflac_int16* p, int16x4x2_t x)
79984 {
79985     vst1q_s16(p, vcombine_s16(x.val[0], x.val[1]));
79986 }
79987 static DRFLAC_INLINE void drflac__vst2q_u16(drflac_uint16* p, uint16x4x2_t x)
79988 {
79989     vst1q_u16(p, vcombine_u16(x.val[0], x.val[1]));
79990 }
79991 static DRFLAC_INLINE int32x4_t drflac__vdupq_n_s32x4(drflac_int32 x3, drflac_int32 x2, drflac_int32 x1, drflac_int32 x0)
79992 {
79993     drflac_int32 x[4];
79994     x[3] = x3;
79995     x[2] = x2;
79996     x[1] = x1;
79997     x[0] = x0;
79998     return vld1q_s32(x);
79999 }
80000 static DRFLAC_INLINE int32x4_t drflac__valignrq_s32_1(int32x4_t a, int32x4_t b)
80001 {
80002     return vextq_s32(b, a, 1);
80003 }
80004 static DRFLAC_INLINE uint32x4_t drflac__valignrq_u32_1(uint32x4_t a, uint32x4_t b)
80005 {
80006     return vextq_u32(b, a, 1);
80007 }
80008 static DRFLAC_INLINE int32x2_t drflac__vhaddq_s32(int32x4_t x)
80009 {
80010     int32x2_t r = vadd_s32(vget_high_s32(x), vget_low_s32(x));
80011     return vpadd_s32(r, r);
80012 }
80013 static DRFLAC_INLINE int64x1_t drflac__vhaddq_s64(int64x2_t x)
80014 {
80015     return vadd_s64(vget_high_s64(x), vget_low_s64(x));
80016 }
80017 static DRFLAC_INLINE int32x4_t drflac__vrevq_s32(int32x4_t x)
80018 {
80019     return vrev64q_s32(vcombine_s32(vget_high_s32(x), vget_low_s32(x)));
80020 }
80021 static DRFLAC_INLINE int32x4_t drflac__vnotq_s32(int32x4_t x)
80022 {
80023     return veorq_s32(x, vdupq_n_s32(0xFFFFFFFF));
80024 }
80025 static DRFLAC_INLINE uint32x4_t drflac__vnotq_u32(uint32x4_t x)
80026 {
80027     return veorq_u32(x, vdupq_n_u32(0xFFFFFFFF));
80028 }
80029 static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
80030 {
80031     int i;
80032     drflac_uint32 riceParamMask;
80033     drflac_int32* pDecodedSamples    = pSamplesOut;
80034     drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
80035     drflac_uint32 zeroCountParts[4];
80036     drflac_uint32 riceParamParts[4];
80037     int32x4_t coefficients128_0;
80038     int32x4_t coefficients128_4;
80039     int32x4_t coefficients128_8;
80040     int32x4_t samples128_0;
80041     int32x4_t samples128_4;
80042     int32x4_t samples128_8;
80043     uint32x4_t riceParamMask128;
80044     int32x4_t riceParam128;
80045     int32x2_t shift64;
80046     uint32x4_t one128;
80047     const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
80048     riceParamMask    = ~((~0UL) << riceParam);
80049     riceParamMask128 = vdupq_n_u32(riceParamMask);
80050     riceParam128 = vdupq_n_s32(riceParam);
80051     shift64 = vdup_n_s32(-shift);
80052     one128 = vdupq_n_u32(1);
80053     {
80054         int runningOrder = order;
80055         drflac_int32 tempC[4] = {0, 0, 0, 0};
80056         drflac_int32 tempS[4] = {0, 0, 0, 0};
80057         if (runningOrder >= 4) {
80058             coefficients128_0 = vld1q_s32(coefficients + 0);
80059             samples128_0      = vld1q_s32(pSamplesOut  - 4);
80060             runningOrder -= 4;
80061         } else {
80062             switch (runningOrder) {
80063                 case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3];
80064                 case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2];
80065                 case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1];
80066             }
80067             coefficients128_0 = vld1q_s32(tempC);
80068             samples128_0      = vld1q_s32(tempS);
80069             runningOrder = 0;
80070         }
80071         if (runningOrder >= 4) {
80072             coefficients128_4 = vld1q_s32(coefficients + 4);
80073             samples128_4      = vld1q_s32(pSamplesOut  - 8);
80074             runningOrder -= 4;
80075         } else {
80076             switch (runningOrder) {
80077                 case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7];
80078                 case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6];
80079                 case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5];
80080             }
80081             coefficients128_4 = vld1q_s32(tempC);
80082             samples128_4      = vld1q_s32(tempS);
80083             runningOrder = 0;
80084         }
80085         if (runningOrder == 4) {
80086             coefficients128_8 = vld1q_s32(coefficients + 8);
80087             samples128_8      = vld1q_s32(pSamplesOut  - 12);
80088             runningOrder -= 4;
80089         } else {
80090             switch (runningOrder) {
80091                 case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11];
80092                 case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10];
80093                 case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9];
80094             }
80095             coefficients128_8 = vld1q_s32(tempC);
80096             samples128_8      = vld1q_s32(tempS);
80097             runningOrder = 0;
80098         }
80099         coefficients128_0 = drflac__vrevq_s32(coefficients128_0);
80100         coefficients128_4 = drflac__vrevq_s32(coefficients128_4);
80101         coefficients128_8 = drflac__vrevq_s32(coefficients128_8);
80102     }
80103     while (pDecodedSamples < pDecodedSamplesEnd) {
80104         int32x4_t prediction128;
80105         int32x2_t prediction64;
80106         uint32x4_t zeroCountPart128;
80107         uint32x4_t riceParamPart128;
80108         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) ||
80109             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) ||
80110             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) ||
80111             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) {
80112             return DRFLAC_FALSE;
80113         }
80114         zeroCountPart128 = vld1q_u32(zeroCountParts);
80115         riceParamPart128 = vld1q_u32(riceParamParts);
80116         riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128);
80117         riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128));
80118         riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128));
80119         if (order <= 4) {
80120             for (i = 0; i < 4; i += 1) {
80121                 prediction128 = vmulq_s32(coefficients128_0, samples128_0);
80122                 prediction64 = drflac__vhaddq_s32(prediction128);
80123                 prediction64 = vshl_s32(prediction64, shift64);
80124                 prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
80125                 samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
80126                 riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
80127             }
80128         } else if (order <= 8) {
80129             for (i = 0; i < 4; i += 1) {
80130                 prediction128 =                vmulq_s32(coefficients128_4, samples128_4);
80131                 prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0);
80132                 prediction64 = drflac__vhaddq_s32(prediction128);
80133                 prediction64 = vshl_s32(prediction64, shift64);
80134                 prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
80135                 samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
80136                 samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
80137                 riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
80138             }
80139         } else {
80140             for (i = 0; i < 4; i += 1) {
80141                 prediction128 =                vmulq_s32(coefficients128_8, samples128_8);
80142                 prediction128 = vmlaq_s32(prediction128, coefficients128_4, samples128_4);
80143                 prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0);
80144                 prediction64 = drflac__vhaddq_s32(prediction128);
80145                 prediction64 = vshl_s32(prediction64, shift64);
80146                 prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
80147                 samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8);
80148                 samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
80149                 samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
80150                 riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
80151             }
80152         }
80153         vst1q_s32(pDecodedSamples, samples128_0);
80154         pDecodedSamples += 4;
80155     }
80156     i = (count & ~3);
80157     while (i < (int)count) {
80158         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) {
80159             return DRFLAC_FALSE;
80160         }
80161         riceParamParts[0] &= riceParamMask;
80162         riceParamParts[0] |= (zeroCountParts[0] << riceParam);
80163         riceParamParts[0]  = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01];
80164         pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples);
80165         i += 1;
80166         pDecodedSamples += 1;
80167     }
80168     return DRFLAC_TRUE;
80169 }
80170 static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
80171 {
80172     int i;
80173     drflac_uint32 riceParamMask;
80174     drflac_int32* pDecodedSamples    = pSamplesOut;
80175     drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
80176     drflac_uint32 zeroCountParts[4];
80177     drflac_uint32 riceParamParts[4];
80178     int32x4_t coefficients128_0;
80179     int32x4_t coefficients128_4;
80180     int32x4_t coefficients128_8;
80181     int32x4_t samples128_0;
80182     int32x4_t samples128_4;
80183     int32x4_t samples128_8;
80184     uint32x4_t riceParamMask128;
80185     int32x4_t riceParam128;
80186     int64x1_t shift64;
80187     uint32x4_t one128;
80188     const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
80189     riceParamMask    = ~((~0UL) << riceParam);
80190     riceParamMask128 = vdupq_n_u32(riceParamMask);
80191     riceParam128 = vdupq_n_s32(riceParam);
80192     shift64 = vdup_n_s64(-shift);
80193     one128 = vdupq_n_u32(1);
80194     {
80195         int runningOrder = order;
80196         drflac_int32 tempC[4] = {0, 0, 0, 0};
80197         drflac_int32 tempS[4] = {0, 0, 0, 0};
80198         if (runningOrder >= 4) {
80199             coefficients128_0 = vld1q_s32(coefficients + 0);
80200             samples128_0      = vld1q_s32(pSamplesOut  - 4);
80201             runningOrder -= 4;
80202         } else {
80203             switch (runningOrder) {
80204                 case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3];
80205                 case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2];
80206                 case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1];
80207             }
80208             coefficients128_0 = vld1q_s32(tempC);
80209             samples128_0      = vld1q_s32(tempS);
80210             runningOrder = 0;
80211         }
80212         if (runningOrder >= 4) {
80213             coefficients128_4 = vld1q_s32(coefficients + 4);
80214             samples128_4      = vld1q_s32(pSamplesOut  - 8);
80215             runningOrder -= 4;
80216         } else {
80217             switch (runningOrder) {
80218                 case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7];
80219                 case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6];
80220                 case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5];
80221             }
80222             coefficients128_4 = vld1q_s32(tempC);
80223             samples128_4      = vld1q_s32(tempS);
80224             runningOrder = 0;
80225         }
80226         if (runningOrder == 4) {
80227             coefficients128_8 = vld1q_s32(coefficients + 8);
80228             samples128_8      = vld1q_s32(pSamplesOut  - 12);
80229             runningOrder -= 4;
80230         } else {
80231             switch (runningOrder) {
80232                 case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11];
80233                 case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10];
80234                 case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9];
80235             }
80236             coefficients128_8 = vld1q_s32(tempC);
80237             samples128_8      = vld1q_s32(tempS);
80238             runningOrder = 0;
80239         }
80240         coefficients128_0 = drflac__vrevq_s32(coefficients128_0);
80241         coefficients128_4 = drflac__vrevq_s32(coefficients128_4);
80242         coefficients128_8 = drflac__vrevq_s32(coefficients128_8);
80243     }
80244     while (pDecodedSamples < pDecodedSamplesEnd) {
80245         int64x2_t prediction128;
80246         uint32x4_t zeroCountPart128;
80247         uint32x4_t riceParamPart128;
80248         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) ||
80249             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) ||
80250             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) ||
80251             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) {
80252             return DRFLAC_FALSE;
80253         }
80254         zeroCountPart128 = vld1q_u32(zeroCountParts);
80255         riceParamPart128 = vld1q_u32(riceParamParts);
80256         riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128);
80257         riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128));
80258         riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128));
80259         for (i = 0; i < 4; i += 1) {
80260             int64x1_t prediction64;
80261             prediction128 = veorq_s64(prediction128, prediction128);
80262             switch (order)
80263             {
80264             case 12:
80265             case 11: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_8), vget_low_s32(samples128_8)));
80266             case 10:
80267             case  9: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_8), vget_high_s32(samples128_8)));
80268             case  8:
80269             case  7: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_4), vget_low_s32(samples128_4)));
80270             case  6:
80271             case  5: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_4), vget_high_s32(samples128_4)));
80272             case  4:
80273             case  3: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_0), vget_low_s32(samples128_0)));
80274             case  2:
80275             case  1: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_0), vget_high_s32(samples128_0)));
80276             }
80277             prediction64 = drflac__vhaddq_s64(prediction128);
80278             prediction64 = vshl_s64(prediction64, shift64);
80279             prediction64 = vadd_s64(prediction64, vdup_n_s64(vgetq_lane_u32(riceParamPart128, 0)));
80280             samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8);
80281             samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
80282             samples128_0 = drflac__valignrq_s32_1(vcombine_s32(vreinterpret_s32_s64(prediction64), vdup_n_s32(0)), samples128_0);
80283             riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
80284         }
80285         vst1q_s32(pDecodedSamples, samples128_0);
80286         pDecodedSamples += 4;
80287     }
80288     i = (count & ~3);
80289     while (i < (int)count) {
80290         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) {
80291             return DRFLAC_FALSE;
80292         }
80293         riceParamParts[0] &= riceParamMask;
80294         riceParamParts[0] |= (zeroCountParts[0] << riceParam);
80295         riceParamParts[0]  = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01];
80296         pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples);
80297         i += 1;
80298         pDecodedSamples += 1;
80299     }
80300     return DRFLAC_TRUE;
80301 }
80302 static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
80303 {
80304     DRFLAC_ASSERT(bs != NULL);
80305     DRFLAC_ASSERT(pSamplesOut != NULL);
80306     if (order > 0 && order <= 12) {
80307         if (bitsPerSample+shift > 32) {
80308             return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
80309         } else {
80310             return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
80311         }
80312     } else {
80313         return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
80314     }
80315 }
80316 #endif
80317 static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
80318 {
80319 #if defined(DRFLAC_SUPPORT_SSE41)
80320     if (drflac__gIsSSE41Supported) {
80321         return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
80322     } else
80323 #elif defined(DRFLAC_SUPPORT_NEON)
80324     if (drflac__gIsNEONSupported) {
80325         return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
80326     } else
80327 #endif
80328     {
80329     #if 0
80330         return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
80331     #else
80332         return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
80333     #endif
80334     }
80335 }
80336 static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam)
80337 {
80338     drflac_uint32 i;
80339     DRFLAC_ASSERT(bs != NULL);
80340     for (i = 0; i < count; ++i) {
80341         if (!drflac__seek_rice_parts(bs, riceParam)) {
80342             return DRFLAC_FALSE;
80343         }
80344     }
80345     return DRFLAC_TRUE;
80346 }
80347 static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
80348 {
80349     drflac_uint32 i;
80350     DRFLAC_ASSERT(bs != NULL);
80351     DRFLAC_ASSERT(unencodedBitsPerSample <= 31);
80352     DRFLAC_ASSERT(pSamplesOut != NULL);
80353     for (i = 0; i < count; ++i) {
80354         if (unencodedBitsPerSample > 0) {
80355             if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) {
80356                 return DRFLAC_FALSE;
80357             }
80358         } else {
80359             pSamplesOut[i] = 0;
80360         }
80361         if (bitsPerSample >= 24) {
80362             pSamplesOut[i] += drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i);
80363         } else {
80364             pSamplesOut[i] += drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i);
80365         }
80366     }
80367     return DRFLAC_TRUE;
80368 }
80369 static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
80370 {
80371     drflac_uint8 residualMethod;
80372     drflac_uint8 partitionOrder;
80373     drflac_uint32 samplesInPartition;
80374     drflac_uint32 partitionsRemaining;
80375     DRFLAC_ASSERT(bs != NULL);
80376     DRFLAC_ASSERT(blockSize != 0);
80377     DRFLAC_ASSERT(pDecodedSamples != NULL);
80378     if (!drflac__read_uint8(bs, 2, &residualMethod)) {
80379         return DRFLAC_FALSE;
80380     }
80381     if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
80382         return DRFLAC_FALSE;
80383     }
80384     pDecodedSamples += order;
80385     if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
80386         return DRFLAC_FALSE;
80387     }
80388     if (partitionOrder > 8) {
80389         return DRFLAC_FALSE;
80390     }
80391     if ((blockSize / (1 << partitionOrder)) < order) {
80392         return DRFLAC_FALSE;
80393     }
80394     samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
80395     partitionsRemaining = (1 << partitionOrder);
80396     for (;;) {
80397         drflac_uint8 riceParam = 0;
80398         if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
80399             if (!drflac__read_uint8(bs, 4, &riceParam)) {
80400                 return DRFLAC_FALSE;
80401             }
80402             if (riceParam == 15) {
80403                 riceParam = 0xFF;
80404             }
80405         } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
80406             if (!drflac__read_uint8(bs, 5, &riceParam)) {
80407                 return DRFLAC_FALSE;
80408             }
80409             if (riceParam == 31) {
80410                 riceParam = 0xFF;
80411             }
80412         }
80413         if (riceParam != 0xFF) {
80414             if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) {
80415                 return DRFLAC_FALSE;
80416             }
80417         } else {
80418             drflac_uint8 unencodedBitsPerSample = 0;
80419             if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
80420                 return DRFLAC_FALSE;
80421             }
80422             if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) {
80423                 return DRFLAC_FALSE;
80424             }
80425         }
80426         pDecodedSamples += samplesInPartition;
80427         if (partitionsRemaining == 1) {
80428             break;
80429         }
80430         partitionsRemaining -= 1;
80431         if (partitionOrder != 0) {
80432             samplesInPartition = blockSize / (1 << partitionOrder);
80433         }
80434     }
80435     return DRFLAC_TRUE;
80436 }
80437 static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 order)
80438 {
80439     drflac_uint8 residualMethod;
80440     drflac_uint8 partitionOrder;
80441     drflac_uint32 samplesInPartition;
80442     drflac_uint32 partitionsRemaining;
80443     DRFLAC_ASSERT(bs != NULL);
80444     DRFLAC_ASSERT(blockSize != 0);
80445     if (!drflac__read_uint8(bs, 2, &residualMethod)) {
80446         return DRFLAC_FALSE;
80447     }
80448     if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
80449         return DRFLAC_FALSE;
80450     }
80451     if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
80452         return DRFLAC_FALSE;
80453     }
80454     if (partitionOrder > 8) {
80455         return DRFLAC_FALSE;
80456     }
80457     if ((blockSize / (1 << partitionOrder)) <= order) {
80458         return DRFLAC_FALSE;
80459     }
80460     samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
80461     partitionsRemaining = (1 << partitionOrder);
80462     for (;;)
80463     {
80464         drflac_uint8 riceParam = 0;
80465         if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
80466             if (!drflac__read_uint8(bs, 4, &riceParam)) {
80467                 return DRFLAC_FALSE;
80468             }
80469             if (riceParam == 15) {
80470                 riceParam = 0xFF;
80471             }
80472         } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
80473             if (!drflac__read_uint8(bs, 5, &riceParam)) {
80474                 return DRFLAC_FALSE;
80475             }
80476             if (riceParam == 31) {
80477                 riceParam = 0xFF;
80478             }
80479         }
80480         if (riceParam != 0xFF) {
80481             if (!drflac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) {
80482                 return DRFLAC_FALSE;
80483             }
80484         } else {
80485             drflac_uint8 unencodedBitsPerSample = 0;
80486             if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
80487                 return DRFLAC_FALSE;
80488             }
80489             if (!drflac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) {
80490                 return DRFLAC_FALSE;
80491             }
80492         }
80493         if (partitionsRemaining == 1) {
80494             break;
80495         }
80496         partitionsRemaining -= 1;
80497         samplesInPartition = blockSize / (1 << partitionOrder);
80498     }
80499     return DRFLAC_TRUE;
80500 }
80501 static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples)
80502 {
80503     drflac_uint32 i;
80504     drflac_int32 sample;
80505     if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
80506         return DRFLAC_FALSE;
80507     }
80508     for (i = 0; i < blockSize; ++i) {
80509         pDecodedSamples[i] = sample;
80510     }
80511     return DRFLAC_TRUE;
80512 }
80513 static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples)
80514 {
80515     drflac_uint32 i;
80516     for (i = 0; i < blockSize; ++i) {
80517         drflac_int32 sample;
80518         if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
80519             return DRFLAC_FALSE;
80520         }
80521         pDecodedSamples[i] = sample;
80522     }
80523     return DRFLAC_TRUE;
80524 }
80525 static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples)
80526 {
80527     drflac_uint32 i;
80528     static drflac_int32 lpcCoefficientsTable[5][4] = {
80529         {0,  0, 0,  0},
80530         {1,  0, 0,  0},
80531         {2, -1, 0,  0},
80532         {3, -3, 1,  0},
80533         {4, -6, 4, -1}
80534     };
80535     for (i = 0; i < lpcOrder; ++i) {
80536         drflac_int32 sample;
80537         if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
80538             return DRFLAC_FALSE;
80539         }
80540         pDecodedSamples[i] = sample;
80541     }
80542     if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) {
80543         return DRFLAC_FALSE;
80544     }
80545     return DRFLAC_TRUE;
80546 }
80547 static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples)
80548 {
80549     drflac_uint8 i;
80550     drflac_uint8 lpcPrecision;
80551     drflac_int8 lpcShift;
80552     drflac_int32 coefficients[32];
80553     for (i = 0; i < lpcOrder; ++i) {
80554         drflac_int32 sample;
80555         if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
80556             return DRFLAC_FALSE;
80557         }
80558         pDecodedSamples[i] = sample;
80559     }
80560     if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
80561         return DRFLAC_FALSE;
80562     }
80563     if (lpcPrecision == 15) {
80564         return DRFLAC_FALSE;
80565     }
80566     lpcPrecision += 1;
80567     if (!drflac__read_int8(bs, 5, &lpcShift)) {
80568         return DRFLAC_FALSE;
80569     }
80570     if (lpcShift < 0) {
80571         return DRFLAC_FALSE;
80572     }
80573     DRFLAC_ZERO_MEMORY(coefficients, sizeof(coefficients));
80574     for (i = 0; i < lpcOrder; ++i) {
80575         if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) {
80576             return DRFLAC_FALSE;
80577         }
80578     }
80579     if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) {
80580         return DRFLAC_FALSE;
80581     }
80582     return DRFLAC_TRUE;
80583 }
80584 static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_uint8 streaminfoBitsPerSample, drflac_frame_header* header)
80585 {
80586     const drflac_uint32 sampleRateTable[12]  = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000};
80587     const drflac_uint8 bitsPerSampleTable[8] = {0, 8, 12, (drflac_uint8)-1, 16, 20, 24, (drflac_uint8)-1};
80588     DRFLAC_ASSERT(bs != NULL);
80589     DRFLAC_ASSERT(header != NULL);
80590     for (;;) {
80591         drflac_uint8 crc8 = 0xCE;
80592         drflac_uint8 reserved = 0;
80593         drflac_uint8 blockingStrategy = 0;
80594         drflac_uint8 blockSize = 0;
80595         drflac_uint8 sampleRate = 0;
80596         drflac_uint8 channelAssignment = 0;
80597         drflac_uint8 bitsPerSample = 0;
80598         drflac_bool32 isVariableBlockSize;
80599         if (!drflac__find_and_seek_to_next_sync_code(bs)) {
80600             return DRFLAC_FALSE;
80601         }
80602         if (!drflac__read_uint8(bs, 1, &reserved)) {
80603             return DRFLAC_FALSE;
80604         }
80605         if (reserved == 1) {
80606             continue;
80607         }
80608         crc8 = drflac_crc8(crc8, reserved, 1);
80609         if (!drflac__read_uint8(bs, 1, &blockingStrategy)) {
80610             return DRFLAC_FALSE;
80611         }
80612         crc8 = drflac_crc8(crc8, blockingStrategy, 1);
80613         if (!drflac__read_uint8(bs, 4, &blockSize)) {
80614             return DRFLAC_FALSE;
80615         }
80616         if (blockSize == 0) {
80617             continue;
80618         }
80619         crc8 = drflac_crc8(crc8, blockSize, 4);
80620         if (!drflac__read_uint8(bs, 4, &sampleRate)) {
80621             return DRFLAC_FALSE;
80622         }
80623         crc8 = drflac_crc8(crc8, sampleRate, 4);
80624         if (!drflac__read_uint8(bs, 4, &channelAssignment)) {
80625             return DRFLAC_FALSE;
80626         }
80627         if (channelAssignment > 10) {
80628             continue;
80629         }
80630         crc8 = drflac_crc8(crc8, channelAssignment, 4);
80631         if (!drflac__read_uint8(bs, 3, &bitsPerSample)) {
80632             return DRFLAC_FALSE;
80633         }
80634         if (bitsPerSample == 3 || bitsPerSample == 7) {
80635             continue;
80636         }
80637         crc8 = drflac_crc8(crc8, bitsPerSample, 3);
80638         if (!drflac__read_uint8(bs, 1, &reserved)) {
80639             return DRFLAC_FALSE;
80640         }
80641         if (reserved == 1) {
80642             continue;
80643         }
80644         crc8 = drflac_crc8(crc8, reserved, 1);
80645         isVariableBlockSize = blockingStrategy == 1;
80646         if (isVariableBlockSize) {
80647             drflac_uint64 pcmFrameNumber;
80648             drflac_result result = drflac__read_utf8_coded_number(bs, &pcmFrameNumber, &crc8);
80649             if (result != DRFLAC_SUCCESS) {
80650                 if (result == DRFLAC_AT_END) {
80651                     return DRFLAC_FALSE;
80652                 } else {
80653                     continue;
80654                 }
80655             }
80656             header->flacFrameNumber  = 0;
80657             header->pcmFrameNumber = pcmFrameNumber;
80658         } else {
80659             drflac_uint64 flacFrameNumber = 0;
80660             drflac_result result = drflac__read_utf8_coded_number(bs, &flacFrameNumber, &crc8);
80661             if (result != DRFLAC_SUCCESS) {
80662                 if (result == DRFLAC_AT_END) {
80663                     return DRFLAC_FALSE;
80664                 } else {
80665                     continue;
80666                 }
80667             }
80668             header->flacFrameNumber  = (drflac_uint32)flacFrameNumber;
80669             header->pcmFrameNumber = 0;
80670         }
80671         DRFLAC_ASSERT(blockSize > 0);
80672         if (blockSize == 1) {
80673             header->blockSizeInPCMFrames = 192;
80674         } else if (blockSize <= 5) {
80675             DRFLAC_ASSERT(blockSize >= 2);
80676             header->blockSizeInPCMFrames = 576 * (1 << (blockSize - 2));
80677         } else if (blockSize == 6) {
80678             if (!drflac__read_uint16(bs, 8, &header->blockSizeInPCMFrames)) {
80679                 return DRFLAC_FALSE;
80680             }
80681             crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 8);
80682             header->blockSizeInPCMFrames += 1;
80683         } else if (blockSize == 7) {
80684             if (!drflac__read_uint16(bs, 16, &header->blockSizeInPCMFrames)) {
80685                 return DRFLAC_FALSE;
80686             }
80687             crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 16);
80688             header->blockSizeInPCMFrames += 1;
80689         } else {
80690             DRFLAC_ASSERT(blockSize >= 8);
80691             header->blockSizeInPCMFrames = 256 * (1 << (blockSize - 8));
80692         }
80693         if (sampleRate <= 11) {
80694             header->sampleRate = sampleRateTable[sampleRate];
80695         } else if (sampleRate == 12) {
80696             if (!drflac__read_uint32(bs, 8, &header->sampleRate)) {
80697                 return DRFLAC_FALSE;
80698             }
80699             crc8 = drflac_crc8(crc8, header->sampleRate, 8);
80700             header->sampleRate *= 1000;
80701         } else if (sampleRate == 13) {
80702             if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
80703                 return DRFLAC_FALSE;
80704             }
80705             crc8 = drflac_crc8(crc8, header->sampleRate, 16);
80706         } else if (sampleRate == 14) {
80707             if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
80708                 return DRFLAC_FALSE;
80709             }
80710             crc8 = drflac_crc8(crc8, header->sampleRate, 16);
80711             header->sampleRate *= 10;
80712         } else {
80713             continue;
80714         }
80715         header->channelAssignment = channelAssignment;
80716         header->bitsPerSample = bitsPerSampleTable[bitsPerSample];
80717         if (header->bitsPerSample == 0) {
80718             header->bitsPerSample = streaminfoBitsPerSample;
80719         }
80720         if (!drflac__read_uint8(bs, 8, &header->crc8)) {
80721             return DRFLAC_FALSE;
80722         }
80723 #ifndef DR_FLAC_NO_CRC
80724         if (header->crc8 != crc8) {
80725             continue;
80726         }
80727 #endif
80728         return DRFLAC_TRUE;
80729     }
80730 }
80731 static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe)
80732 {
80733     drflac_uint8 header;
80734     int type;
80735     if (!drflac__read_uint8(bs, 8, &header)) {
80736         return DRFLAC_FALSE;
80737     }
80738     if ((header & 0x80) != 0) {
80739         return DRFLAC_FALSE;
80740     }
80741     type = (header & 0x7E) >> 1;
80742     if (type == 0) {
80743         pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT;
80744     } else if (type == 1) {
80745         pSubframe->subframeType = DRFLAC_SUBFRAME_VERBATIM;
80746     } else {
80747         if ((type & 0x20) != 0) {
80748             pSubframe->subframeType = DRFLAC_SUBFRAME_LPC;
80749             pSubframe->lpcOrder = (drflac_uint8)(type & 0x1F) + 1;
80750         } else if ((type & 0x08) != 0) {
80751             pSubframe->subframeType = DRFLAC_SUBFRAME_FIXED;
80752             pSubframe->lpcOrder = (drflac_uint8)(type & 0x07);
80753             if (pSubframe->lpcOrder > 4) {
80754                 pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
80755                 pSubframe->lpcOrder = 0;
80756             }
80757         } else {
80758             pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
80759         }
80760     }
80761     if (pSubframe->subframeType == DRFLAC_SUBFRAME_RESERVED) {
80762         return DRFLAC_FALSE;
80763     }
80764     pSubframe->wastedBitsPerSample = 0;
80765     if ((header & 0x01) == 1) {
80766         unsigned int wastedBitsPerSample;
80767         if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) {
80768             return DRFLAC_FALSE;
80769         }
80770         pSubframe->wastedBitsPerSample = (drflac_uint8)wastedBitsPerSample + 1;
80771     }
80772     return DRFLAC_TRUE;
80773 }
80774 static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, drflac_int32* pDecodedSamplesOut)
80775 {
80776     drflac_subframe* pSubframe;
80777     drflac_uint32 subframeBitsPerSample;
80778     DRFLAC_ASSERT(bs != NULL);
80779     DRFLAC_ASSERT(frame != NULL);
80780     pSubframe = frame->subframes + subframeIndex;
80781     if (!drflac__read_subframe_header(bs, pSubframe)) {
80782         return DRFLAC_FALSE;
80783     }
80784     subframeBitsPerSample = frame->header.bitsPerSample;
80785     if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
80786         subframeBitsPerSample += 1;
80787     } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
80788         subframeBitsPerSample += 1;
80789     }
80790     if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) {
80791         return DRFLAC_FALSE;
80792     }
80793     subframeBitsPerSample -= pSubframe->wastedBitsPerSample;
80794     pSubframe->pSamplesS32 = pDecodedSamplesOut;
80795     switch (pSubframe->subframeType)
80796     {
80797         case DRFLAC_SUBFRAME_CONSTANT:
80798         {
80799             drflac__decode_samples__constant(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32);
80800         } break;
80801         case DRFLAC_SUBFRAME_VERBATIM:
80802         {
80803             drflac__decode_samples__verbatim(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32);
80804         } break;
80805         case DRFLAC_SUBFRAME_FIXED:
80806         {
80807             drflac__decode_samples__fixed(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32);
80808         } break;
80809         case DRFLAC_SUBFRAME_LPC:
80810         {
80811             drflac__decode_samples__lpc(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32);
80812         } break;
80813         default: return DRFLAC_FALSE;
80814     }
80815     return DRFLAC_TRUE;
80816 }
80817 static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex)
80818 {
80819     drflac_subframe* pSubframe;
80820     drflac_uint32 subframeBitsPerSample;
80821     DRFLAC_ASSERT(bs != NULL);
80822     DRFLAC_ASSERT(frame != NULL);
80823     pSubframe = frame->subframes + subframeIndex;
80824     if (!drflac__read_subframe_header(bs, pSubframe)) {
80825         return DRFLAC_FALSE;
80826     }
80827     subframeBitsPerSample = frame->header.bitsPerSample;
80828     if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
80829         subframeBitsPerSample += 1;
80830     } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
80831         subframeBitsPerSample += 1;
80832     }
80833     if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) {
80834         return DRFLAC_FALSE;
80835     }
80836     subframeBitsPerSample -= pSubframe->wastedBitsPerSample;
80837     pSubframe->pSamplesS32 = NULL;
80838     switch (pSubframe->subframeType)
80839     {
80840         case DRFLAC_SUBFRAME_CONSTANT:
80841         {
80842             if (!drflac__seek_bits(bs, subframeBitsPerSample)) {
80843                 return DRFLAC_FALSE;
80844             }
80845         } break;
80846         case DRFLAC_SUBFRAME_VERBATIM:
80847         {
80848             unsigned int bitsToSeek = frame->header.blockSizeInPCMFrames * subframeBitsPerSample;
80849             if (!drflac__seek_bits(bs, bitsToSeek)) {
80850                 return DRFLAC_FALSE;
80851             }
80852         } break;
80853         case DRFLAC_SUBFRAME_FIXED:
80854         {
80855             unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample;
80856             if (!drflac__seek_bits(bs, bitsToSeek)) {
80857                 return DRFLAC_FALSE;
80858             }
80859             if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) {
80860                 return DRFLAC_FALSE;
80861             }
80862         } break;
80863         case DRFLAC_SUBFRAME_LPC:
80864         {
80865             drflac_uint8 lpcPrecision;
80866             unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample;
80867             if (!drflac__seek_bits(bs, bitsToSeek)) {
80868                 return DRFLAC_FALSE;
80869             }
80870             if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
80871                 return DRFLAC_FALSE;
80872             }
80873             if (lpcPrecision == 15) {
80874                 return DRFLAC_FALSE;
80875             }
80876             lpcPrecision += 1;
80877             bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5;
80878             if (!drflac__seek_bits(bs, bitsToSeek)) {
80879                 return DRFLAC_FALSE;
80880             }
80881             if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) {
80882                 return DRFLAC_FALSE;
80883             }
80884         } break;
80885         default: return DRFLAC_FALSE;
80886     }
80887     return DRFLAC_TRUE;
80888 }
80889 static DRFLAC_INLINE drflac_uint8 drflac__get_channel_count_from_channel_assignment(drflac_int8 channelAssignment)
80890 {
80891     drflac_uint8 lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2};
80892     DRFLAC_ASSERT(channelAssignment <= 10);
80893     return lookup[channelAssignment];
80894 }
80895 static drflac_result drflac__decode_flac_frame(drflac* pFlac)
80896 {
80897     int channelCount;
80898     int i;
80899     drflac_uint8 paddingSizeInBits;
80900     drflac_uint16 desiredCRC16;
80901 #ifndef DR_FLAC_NO_CRC
80902     drflac_uint16 actualCRC16;
80903 #endif
80904     DRFLAC_ZERO_MEMORY(pFlac->currentFLACFrame.subframes, sizeof(pFlac->currentFLACFrame.subframes));
80905     if (pFlac->currentFLACFrame.header.blockSizeInPCMFrames > pFlac->maxBlockSizeInPCMFrames) {
80906         return DRFLAC_ERROR;
80907     }
80908     channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
80909     if (channelCount != (int)pFlac->channels) {
80910         return DRFLAC_ERROR;
80911     }
80912     for (i = 0; i < channelCount; ++i) {
80913         if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i, pFlac->pDecodedSamples + (pFlac->currentFLACFrame.header.blockSizeInPCMFrames * i))) {
80914             return DRFLAC_ERROR;
80915         }
80916     }
80917     paddingSizeInBits = (drflac_uint8)(DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7);
80918     if (paddingSizeInBits > 0) {
80919         drflac_uint8 padding = 0;
80920         if (!drflac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) {
80921             return DRFLAC_AT_END;
80922         }
80923     }
80924 #ifndef DR_FLAC_NO_CRC
80925     actualCRC16 = drflac__flush_crc16(&pFlac->bs);
80926 #endif
80927     if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) {
80928         return DRFLAC_AT_END;
80929     }
80930 #ifndef DR_FLAC_NO_CRC
80931     if (actualCRC16 != desiredCRC16) {
80932         return DRFLAC_CRC_MISMATCH;
80933     }
80934 #endif
80935     pFlac->currentFLACFrame.pcmFramesRemaining = pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
80936     return DRFLAC_SUCCESS;
80937 }
80938 static drflac_result drflac__seek_flac_frame(drflac* pFlac)
80939 {
80940     int channelCount;
80941     int i;
80942     drflac_uint16 desiredCRC16;
80943 #ifndef DR_FLAC_NO_CRC
80944     drflac_uint16 actualCRC16;
80945 #endif
80946     channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
80947     for (i = 0; i < channelCount; ++i) {
80948         if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i)) {
80949             return DRFLAC_ERROR;
80950         }
80951     }
80952     if (!drflac__seek_bits(&pFlac->bs, DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) {
80953         return DRFLAC_ERROR;
80954     }
80955 #ifndef DR_FLAC_NO_CRC
80956     actualCRC16 = drflac__flush_crc16(&pFlac->bs);
80957 #endif
80958     if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) {
80959         return DRFLAC_AT_END;
80960     }
80961 #ifndef DR_FLAC_NO_CRC
80962     if (actualCRC16 != desiredCRC16) {
80963         return DRFLAC_CRC_MISMATCH;
80964     }
80965 #endif
80966     return DRFLAC_SUCCESS;
80967 }
80968 static drflac_bool32 drflac__read_and_decode_next_flac_frame(drflac* pFlac)
80969 {
80970     DRFLAC_ASSERT(pFlac != NULL);
80971     for (;;) {
80972         drflac_result result;
80973         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
80974             return DRFLAC_FALSE;
80975         }
80976         result = drflac__decode_flac_frame(pFlac);
80977         if (result != DRFLAC_SUCCESS) {
80978             if (result == DRFLAC_CRC_MISMATCH) {
80979                 continue;
80980             } else {
80981                 return DRFLAC_FALSE;
80982             }
80983         }
80984         return DRFLAC_TRUE;
80985     }
80986 }
80987 static void drflac__get_pcm_frame_range_of_current_flac_frame(drflac* pFlac, drflac_uint64* pFirstPCMFrame, drflac_uint64* pLastPCMFrame)
80988 {
80989     drflac_uint64 firstPCMFrame;
80990     drflac_uint64 lastPCMFrame;
80991     DRFLAC_ASSERT(pFlac != NULL);
80992     firstPCMFrame = pFlac->currentFLACFrame.header.pcmFrameNumber;
80993     if (firstPCMFrame == 0) {
80994         firstPCMFrame = ((drflac_uint64)pFlac->currentFLACFrame.header.flacFrameNumber) * pFlac->maxBlockSizeInPCMFrames;
80995     }
80996     lastPCMFrame = firstPCMFrame + pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
80997     if (lastPCMFrame > 0) {
80998         lastPCMFrame -= 1;
80999     }
81000     if (pFirstPCMFrame) {
81001         *pFirstPCMFrame = firstPCMFrame;
81002     }
81003     if (pLastPCMFrame) {
81004         *pLastPCMFrame = lastPCMFrame;
81005     }
81006 }
81007 static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac)
81008 {
81009     drflac_bool32 result;
81010     DRFLAC_ASSERT(pFlac != NULL);
81011     result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes);
81012     DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame));
81013     pFlac->currentPCMFrame = 0;
81014     return result;
81015 }
81016 static DRFLAC_INLINE drflac_result drflac__seek_to_next_flac_frame(drflac* pFlac)
81017 {
81018     DRFLAC_ASSERT(pFlac != NULL);
81019     return drflac__seek_flac_frame(pFlac);
81020 }
81021 static drflac_uint64 drflac__seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 pcmFramesToSeek)
81022 {
81023     drflac_uint64 pcmFramesRead = 0;
81024     while (pcmFramesToSeek > 0) {
81025         if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
81026             if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
81027                 break;
81028             }
81029         } else {
81030             if (pFlac->currentFLACFrame.pcmFramesRemaining > pcmFramesToSeek) {
81031                 pcmFramesRead   += pcmFramesToSeek;
81032                 pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)pcmFramesToSeek;
81033                 pcmFramesToSeek  = 0;
81034             } else {
81035                 pcmFramesRead   += pFlac->currentFLACFrame.pcmFramesRemaining;
81036                 pcmFramesToSeek -= pFlac->currentFLACFrame.pcmFramesRemaining;
81037                 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
81038             }
81039         }
81040     }
81041     pFlac->currentPCMFrame += pcmFramesRead;
81042     return pcmFramesRead;
81043 }
81044 static drflac_bool32 drflac__seek_to_pcm_frame__brute_force(drflac* pFlac, drflac_uint64 pcmFrameIndex)
81045 {
81046     drflac_bool32 isMidFrame = DRFLAC_FALSE;
81047     drflac_uint64 runningPCMFrameCount;
81048     DRFLAC_ASSERT(pFlac != NULL);
81049     if (pcmFrameIndex >= pFlac->currentPCMFrame) {
81050         runningPCMFrameCount = pFlac->currentPCMFrame;
81051         if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
81052             if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
81053                 return DRFLAC_FALSE;
81054             }
81055         } else {
81056             isMidFrame = DRFLAC_TRUE;
81057         }
81058     } else {
81059         runningPCMFrameCount = 0;
81060         if (!drflac__seek_to_first_frame(pFlac)) {
81061             return DRFLAC_FALSE;
81062         }
81063         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
81064             return DRFLAC_FALSE;
81065         }
81066     }
81067     for (;;) {
81068         drflac_uint64 pcmFrameCountInThisFLACFrame;
81069         drflac_uint64 firstPCMFrameInFLACFrame = 0;
81070         drflac_uint64 lastPCMFrameInFLACFrame = 0;
81071         drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
81072         pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
81073         if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) {
81074             drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount;
81075             if (!isMidFrame) {
81076                 drflac_result result = drflac__decode_flac_frame(pFlac);
81077                 if (result == DRFLAC_SUCCESS) {
81078                     return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
81079                 } else {
81080                     if (result == DRFLAC_CRC_MISMATCH) {
81081                         goto next_iteration;
81082                     } else {
81083                         return DRFLAC_FALSE;
81084                     }
81085                 }
81086             } else {
81087                 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
81088             }
81089         } else {
81090             if (!isMidFrame) {
81091                 drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
81092                 if (result == DRFLAC_SUCCESS) {
81093                     runningPCMFrameCount += pcmFrameCountInThisFLACFrame;
81094                 } else {
81095                     if (result == DRFLAC_CRC_MISMATCH) {
81096                         goto next_iteration;
81097                     } else {
81098                         return DRFLAC_FALSE;
81099                     }
81100                 }
81101             } else {
81102                 runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining;
81103                 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
81104                 isMidFrame = DRFLAC_FALSE;
81105             }
81106             if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) {
81107                 return DRFLAC_TRUE;
81108             }
81109         }
81110     next_iteration:
81111         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
81112             return DRFLAC_FALSE;
81113         }
81114     }
81115 }
81116 #if !defined(DR_FLAC_NO_CRC)
81117 #define DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO 0.6f
81118 static drflac_bool32 drflac__seek_to_approximate_flac_frame_to_byte(drflac* pFlac, drflac_uint64 targetByte, drflac_uint64 rangeLo, drflac_uint64 rangeHi, drflac_uint64* pLastSuccessfulSeekOffset)
81119 {
81120     DRFLAC_ASSERT(pFlac != NULL);
81121     DRFLAC_ASSERT(pLastSuccessfulSeekOffset != NULL);
81122     DRFLAC_ASSERT(targetByte >= rangeLo);
81123     DRFLAC_ASSERT(targetByte <= rangeHi);
81124     *pLastSuccessfulSeekOffset = pFlac->firstFLACFramePosInBytes;
81125     for (;;) {
81126         drflac_uint64 lastTargetByte = targetByte;
81127         if (!drflac__seek_to_byte(&pFlac->bs, targetByte)) {
81128             if (targetByte == 0) {
81129                 drflac__seek_to_first_frame(pFlac);
81130                 return DRFLAC_FALSE;
81131             }
81132             targetByte = rangeLo + ((rangeHi - rangeLo)/2);
81133             rangeHi = targetByte;
81134         } else {
81135             DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame));
81136 #if 1
81137             if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
81138                 targetByte = rangeLo + ((rangeHi - rangeLo)/2);
81139                 rangeHi = targetByte;
81140             } else {
81141                 break;
81142             }
81143 #else
81144             if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
81145                 targetByte = rangeLo + ((rangeHi - rangeLo)/2);
81146                 rangeHi = targetByte;
81147             } else {
81148                 break;
81149             }
81150 #endif
81151         }
81152         if(targetByte == lastTargetByte) {
81153             return DRFLAC_FALSE;
81154         }
81155     }
81156     drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL);
81157     DRFLAC_ASSERT(targetByte <= rangeHi);
81158     *pLastSuccessfulSeekOffset = targetByte;
81159     return DRFLAC_TRUE;
81160 }
81161 static drflac_bool32 drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 offset)
81162 {
81163 #if 0
81164     if (drflac__decode_flac_frame(pFlac) != DRFLAC_SUCCESS) {
81165         if (drflac__read_and_decode_next_flac_frame(pFlac) == DRFLAC_FALSE) {
81166             return DRFLAC_FALSE;
81167         }
81168     }
81169 #endif
81170     return drflac__seek_forward_by_pcm_frames(pFlac, offset) == offset;
81171 }
81172 static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* pFlac, drflac_uint64 pcmFrameIndex, drflac_uint64 byteRangeLo, drflac_uint64 byteRangeHi)
81173 {
81174     drflac_uint64 targetByte;
81175     drflac_uint64 pcmRangeLo = pFlac->totalPCMFrameCount;
81176     drflac_uint64 pcmRangeHi = 0;
81177     drflac_uint64 lastSuccessfulSeekOffset = (drflac_uint64)-1;
81178     drflac_uint64 closestSeekOffsetBeforeTargetPCMFrame = byteRangeLo;
81179     drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096;
81180     targetByte = byteRangeLo + (drflac_uint64)(((drflac_int64)((pcmFrameIndex - pFlac->currentPCMFrame) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO);
81181     if (targetByte > byteRangeHi) {
81182         targetByte = byteRangeHi;
81183     }
81184     for (;;) {
81185         if (drflac__seek_to_approximate_flac_frame_to_byte(pFlac, targetByte, byteRangeLo, byteRangeHi, &lastSuccessfulSeekOffset)) {
81186             drflac_uint64 newPCMRangeLo;
81187             drflac_uint64 newPCMRangeHi;
81188             drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &newPCMRangeLo, &newPCMRangeHi);
81189             if (pcmRangeLo == newPCMRangeLo) {
81190                 if (!drflac__seek_to_approximate_flac_frame_to_byte(pFlac, closestSeekOffsetBeforeTargetPCMFrame, closestSeekOffsetBeforeTargetPCMFrame, byteRangeHi, &lastSuccessfulSeekOffset)) {
81191                     break;
81192                 }
81193                 if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) {
81194                     return DRFLAC_TRUE;
81195                 } else {
81196                     break;
81197                 }
81198             }
81199             pcmRangeLo = newPCMRangeLo;
81200             pcmRangeHi = newPCMRangeHi;
81201             if (pcmRangeLo <= pcmFrameIndex && pcmRangeHi >= pcmFrameIndex) {
81202                 if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame) ) {
81203                     return DRFLAC_TRUE;
81204                 } else {
81205                     break;
81206                 }
81207             } else {
81208                 const float approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f);
81209                 if (pcmRangeLo > pcmFrameIndex) {
81210                     byteRangeHi = lastSuccessfulSeekOffset;
81211                     if (byteRangeLo > byteRangeHi) {
81212                         byteRangeLo = byteRangeHi;
81213                     }
81214                     targetByte = byteRangeLo + ((byteRangeHi - byteRangeLo) / 2);
81215                     if (targetByte < byteRangeLo) {
81216                         targetByte = byteRangeLo;
81217                     }
81218                 } else  {
81219                     if ((pcmFrameIndex - pcmRangeLo) < seekForwardThreshold) {
81220                         if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) {
81221                             return DRFLAC_TRUE;
81222                         } else {
81223                             break;
81224                         }
81225                     } else {
81226                         byteRangeLo = lastSuccessfulSeekOffset;
81227                         if (byteRangeHi < byteRangeLo) {
81228                             byteRangeHi = byteRangeLo;
81229                         }
81230                         targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio);
81231                         if (targetByte > byteRangeHi) {
81232                             targetByte = byteRangeHi;
81233                         }
81234                         if (closestSeekOffsetBeforeTargetPCMFrame < lastSuccessfulSeekOffset) {
81235                             closestSeekOffsetBeforeTargetPCMFrame = lastSuccessfulSeekOffset;
81236                         }
81237                     }
81238                 }
81239             }
81240         } else {
81241             break;
81242         }
81243     }
81244     drflac__seek_to_first_frame(pFlac);
81245     return DRFLAC_FALSE;
81246 }
81247 static drflac_bool32 drflac__seek_to_pcm_frame__binary_search(drflac* pFlac, drflac_uint64 pcmFrameIndex)
81248 {
81249     drflac_uint64 byteRangeLo;
81250     drflac_uint64 byteRangeHi;
81251     drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096;
81252     if (drflac__seek_to_first_frame(pFlac) == DRFLAC_FALSE) {
81253         return DRFLAC_FALSE;
81254     }
81255     if (pcmFrameIndex < seekForwardThreshold) {
81256         return drflac__seek_forward_by_pcm_frames(pFlac, pcmFrameIndex) == pcmFrameIndex;
81257     }
81258     byteRangeLo = pFlac->firstFLACFramePosInBytes;
81259     byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f);
81260     return drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi);
81261 }
81262 #endif
81263 static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac_uint64 pcmFrameIndex)
81264 {
81265     drflac_uint32 iClosestSeekpoint = 0;
81266     drflac_bool32 isMidFrame = DRFLAC_FALSE;
81267     drflac_uint64 runningPCMFrameCount;
81268     drflac_uint32 iSeekpoint;
81269     DRFLAC_ASSERT(pFlac != NULL);
81270     if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) {
81271         return DRFLAC_FALSE;
81272     }
81273     if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) {
81274         return DRFLAC_FALSE;
81275     }
81276     for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
81277         if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) {
81278             break;
81279         }
81280         iClosestSeekpoint = iSeekpoint;
81281     }
81282     if (pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount == 0 || pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount > pFlac->maxBlockSizeInPCMFrames) {
81283         return DRFLAC_FALSE;
81284     }
81285     if (pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame > pFlac->totalPCMFrameCount && pFlac->totalPCMFrameCount > 0) {
81286         return DRFLAC_FALSE;
81287     }
81288 #if !defined(DR_FLAC_NO_CRC)
81289     if (pFlac->totalPCMFrameCount > 0) {
81290         drflac_uint64 byteRangeLo;
81291         drflac_uint64 byteRangeHi;
81292         byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f);
81293         byteRangeLo = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset;
81294         if (iClosestSeekpoint < pFlac->seekpointCount-1) {
81295             drflac_uint32 iNextSeekpoint = iClosestSeekpoint + 1;
81296             if (pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset >= pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset || pFlac->pSeekpoints[iNextSeekpoint].pcmFrameCount == 0) {
81297                 return DRFLAC_FALSE;
81298             }
81299             if (pFlac->pSeekpoints[iNextSeekpoint].firstPCMFrame != (((drflac_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF)) {
81300                 byteRangeHi = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset - 1;
81301             }
81302         }
81303         if (drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) {
81304             if (drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
81305                 drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL);
81306                 if (drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi)) {
81307                     return DRFLAC_TRUE;
81308                 }
81309             }
81310         }
81311     }
81312 #endif
81313     if (pcmFrameIndex >= pFlac->currentPCMFrame && pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame <= pFlac->currentPCMFrame) {
81314         runningPCMFrameCount = pFlac->currentPCMFrame;
81315         if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
81316             if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
81317                 return DRFLAC_FALSE;
81318             }
81319         } else {
81320             isMidFrame = DRFLAC_TRUE;
81321         }
81322     } else {
81323         runningPCMFrameCount = pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame;
81324         if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) {
81325             return DRFLAC_FALSE;
81326         }
81327         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
81328             return DRFLAC_FALSE;
81329         }
81330     }
81331     for (;;) {
81332         drflac_uint64 pcmFrameCountInThisFLACFrame;
81333         drflac_uint64 firstPCMFrameInFLACFrame = 0;
81334         drflac_uint64 lastPCMFrameInFLACFrame = 0;
81335         drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
81336         pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
81337         if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) {
81338             drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount;
81339             if (!isMidFrame) {
81340                 drflac_result result = drflac__decode_flac_frame(pFlac);
81341                 if (result == DRFLAC_SUCCESS) {
81342                     return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
81343                 } else {
81344                     if (result == DRFLAC_CRC_MISMATCH) {
81345                         goto next_iteration;
81346                     } else {
81347                         return DRFLAC_FALSE;
81348                     }
81349                 }
81350             } else {
81351                 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
81352             }
81353         } else {
81354             if (!isMidFrame) {
81355                 drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
81356                 if (result == DRFLAC_SUCCESS) {
81357                     runningPCMFrameCount += pcmFrameCountInThisFLACFrame;
81358                 } else {
81359                     if (result == DRFLAC_CRC_MISMATCH) {
81360                         goto next_iteration;
81361                     } else {
81362                         return DRFLAC_FALSE;
81363                     }
81364                 }
81365             } else {
81366                 runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining;
81367                 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
81368                 isMidFrame = DRFLAC_FALSE;
81369             }
81370             if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) {
81371                 return DRFLAC_TRUE;
81372             }
81373         }
81374     next_iteration:
81375         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
81376             return DRFLAC_FALSE;
81377         }
81378     }
81379 }
81380 #ifndef DR_FLAC_NO_OGG
81381 typedef struct
81382 {
81383     drflac_uint8 capturePattern[4];
81384     drflac_uint8 structureVersion;
81385     drflac_uint8 headerType;
81386     drflac_uint64 granulePosition;
81387     drflac_uint32 serialNumber;
81388     drflac_uint32 sequenceNumber;
81389     drflac_uint32 checksum;
81390     drflac_uint8 segmentCount;
81391     drflac_uint8 segmentTable[255];
81392 } drflac_ogg_page_header;
81393 #endif
81394 typedef struct
81395 {
81396     drflac_read_proc onRead;
81397     drflac_seek_proc onSeek;
81398     drflac_meta_proc onMeta;
81399     drflac_container container;
81400     void* pUserData;
81401     void* pUserDataMD;
81402     drflac_uint32 sampleRate;
81403     drflac_uint8  channels;
81404     drflac_uint8  bitsPerSample;
81405     drflac_uint64 totalPCMFrameCount;
81406     drflac_uint16 maxBlockSizeInPCMFrames;
81407     drflac_uint64 runningFilePos;
81408     drflac_bool32 hasStreamInfoBlock;
81409     drflac_bool32 hasMetadataBlocks;
81410     drflac_bs bs;
81411     drflac_frame_header firstFrameHeader;
81412 #ifndef DR_FLAC_NO_OGG
81413     drflac_uint32 oggSerial;
81414     drflac_uint64 oggFirstBytePos;
81415     drflac_ogg_page_header oggBosHeader;
81416 #endif
81417 } drflac_init_info;
81418 static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
81419 {
81420     blockHeader = drflac__be2host_32(blockHeader);
81421     *isLastBlock = (drflac_uint8)((blockHeader & 0x80000000UL) >> 31);
81422     *blockType   = (drflac_uint8)((blockHeader & 0x7F000000UL) >> 24);
81423     *blockSize   =                (blockHeader & 0x00FFFFFFUL);
81424 }
81425 static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
81426 {
81427     drflac_uint32 blockHeader;
81428     *blockSize = 0;
81429     if (onRead(pUserData, &blockHeader, 4) != 4) {
81430         return DRFLAC_FALSE;
81431     }
81432     drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize);
81433     return DRFLAC_TRUE;
81434 }
81435 static drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
81436 {
81437     drflac_uint32 blockSizes;
81438     drflac_uint64 frameSizes = 0;
81439     drflac_uint64 importantProps;
81440     drflac_uint8 md5[16];
81441     if (onRead(pUserData, &blockSizes, 4) != 4) {
81442         return DRFLAC_FALSE;
81443     }
81444     if (onRead(pUserData, &frameSizes, 6) != 6) {
81445         return DRFLAC_FALSE;
81446     }
81447     if (onRead(pUserData, &importantProps, 8) != 8) {
81448         return DRFLAC_FALSE;
81449     }
81450     if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) {
81451         return DRFLAC_FALSE;
81452     }
81453     blockSizes     = drflac__be2host_32(blockSizes);
81454     frameSizes     = drflac__be2host_64(frameSizes);
81455     importantProps = drflac__be2host_64(importantProps);
81456     pStreamInfo->minBlockSizeInPCMFrames = (drflac_uint16)((blockSizes & 0xFFFF0000) >> 16);
81457     pStreamInfo->maxBlockSizeInPCMFrames = (drflac_uint16) (blockSizes & 0x0000FFFF);
81458     pStreamInfo->minFrameSizeInPCMFrames = (drflac_uint32)((frameSizes     &  (((drflac_uint64)0x00FFFFFF << 16) << 24)) >> 40);
81459     pStreamInfo->maxFrameSizeInPCMFrames = (drflac_uint32)((frameSizes     &  (((drflac_uint64)0x00FFFFFF << 16) <<  0)) >> 16);
81460     pStreamInfo->sampleRate              = (drflac_uint32)((importantProps &  (((drflac_uint64)0x000FFFFF << 16) << 28)) >> 44);
81461     pStreamInfo->channels                = (drflac_uint8 )((importantProps &  (((drflac_uint64)0x0000000E << 16) << 24)) >> 41) + 1;
81462     pStreamInfo->bitsPerSample           = (drflac_uint8 )((importantProps &  (((drflac_uint64)0x0000001F << 16) << 20)) >> 36) + 1;
81463     pStreamInfo->totalPCMFrameCount      =                ((importantProps & ((((drflac_uint64)0x0000000F << 16) << 16) | 0xFFFFFFFF)));
81464     DRFLAC_COPY_MEMORY(pStreamInfo->md5, md5, sizeof(md5));
81465     return DRFLAC_TRUE;
81466 }
81467 static void* drflac__malloc_default(size_t sz, void* pUserData)
81468 {
81469     (void)pUserData;
81470     return DRFLAC_MALLOC(sz);
81471 }
81472 static void* drflac__realloc_default(void* p, size_t sz, void* pUserData)
81473 {
81474     (void)pUserData;
81475     return DRFLAC_REALLOC(p, sz);
81476 }
81477 static void drflac__free_default(void* p, void* pUserData)
81478 {
81479     (void)pUserData;
81480     DRFLAC_FREE(p);
81481 }
81482 static void* drflac__malloc_from_callbacks(size_t sz, const drflac_allocation_callbacks* pAllocationCallbacks)
81483 {
81484     if (pAllocationCallbacks == NULL) {
81485         return NULL;
81486     }
81487     if (pAllocationCallbacks->onMalloc != NULL) {
81488         return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
81489     }
81490     if (pAllocationCallbacks->onRealloc != NULL) {
81491         return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
81492     }
81493     return NULL;
81494 }
81495 static void* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drflac_allocation_callbacks* pAllocationCallbacks)
81496 {
81497     if (pAllocationCallbacks == NULL) {
81498         return NULL;
81499     }
81500     if (pAllocationCallbacks->onRealloc != NULL) {
81501         return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
81502     }
81503     if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
81504         void* p2;
81505         p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
81506         if (p2 == NULL) {
81507             return NULL;
81508         }
81509         if (p != NULL) {
81510             DRFLAC_COPY_MEMORY(p2, p, szOld);
81511             pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
81512         }
81513         return p2;
81514     }
81515     return NULL;
81516 }
81517 static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbacks* pAllocationCallbacks)
81518 {
81519     if (p == NULL || pAllocationCallbacks == NULL) {
81520         return;
81521     }
81522     if (pAllocationCallbacks->onFree != NULL) {
81523         pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
81524     }
81525 }
81526 static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeektableSize, drflac_allocation_callbacks* pAllocationCallbacks)
81527 {
81528     drflac_uint64 runningFilePos = 42;
81529     drflac_uint64 seektablePos   = 0;
81530     drflac_uint32 seektableSize  = 0;
81531     for (;;) {
81532         drflac_metadata metadata;
81533         drflac_uint8 isLastBlock = 0;
81534         drflac_uint8 blockType;
81535         drflac_uint32 blockSize;
81536         if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) {
81537             return DRFLAC_FALSE;
81538         }
81539         runningFilePos += 4;
81540         metadata.type = blockType;
81541         metadata.pRawData = NULL;
81542         metadata.rawDataSize = 0;
81543         switch (blockType)
81544         {
81545             case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION:
81546             {
81547                 if (blockSize < 4) {
81548                     return DRFLAC_FALSE;
81549                 }
81550                 if (onMeta) {
81551                     void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
81552                     if (pRawData == NULL) {
81553                         return DRFLAC_FALSE;
81554                     }
81555                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
81556                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81557                         return DRFLAC_FALSE;
81558                     }
81559                     metadata.pRawData = pRawData;
81560                     metadata.rawDataSize = blockSize;
81561                     metadata.data.application.id       = drflac__be2host_32(*(drflac_uint32*)pRawData);
81562                     metadata.data.application.pData    = (const void*)((drflac_uint8*)pRawData + sizeof(drflac_uint32));
81563                     metadata.data.application.dataSize = blockSize - sizeof(drflac_uint32);
81564                     onMeta(pUserDataMD, &metadata);
81565                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81566                 }
81567             } break;
81568             case DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE:
81569             {
81570                 seektablePos  = runningFilePos;
81571                 seektableSize = blockSize;
81572                 if (onMeta) {
81573                     drflac_uint32 iSeekpoint;
81574                     void* pRawData;
81575                     pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
81576                     if (pRawData == NULL) {
81577                         return DRFLAC_FALSE;
81578                     }
81579                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
81580                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81581                         return DRFLAC_FALSE;
81582                     }
81583                     metadata.pRawData = pRawData;
81584                     metadata.rawDataSize = blockSize;
81585                     metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint);
81586                     metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData;
81587                     for (iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) {
81588                         drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint;
81589                         pSeekpoint->firstPCMFrame   = drflac__be2host_64(pSeekpoint->firstPCMFrame);
81590                         pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset);
81591                         pSeekpoint->pcmFrameCount   = drflac__be2host_16(pSeekpoint->pcmFrameCount);
81592                     }
81593                     onMeta(pUserDataMD, &metadata);
81594                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81595                 }
81596             } break;
81597             case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT:
81598             {
81599                 if (blockSize < 8) {
81600                     return DRFLAC_FALSE;
81601                 }
81602                 if (onMeta) {
81603                     void* pRawData;
81604                     const char* pRunningData;
81605                     const char* pRunningDataEnd;
81606                     drflac_uint32 i;
81607                     pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
81608                     if (pRawData == NULL) {
81609                         return DRFLAC_FALSE;
81610                     }
81611                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
81612                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81613                         return DRFLAC_FALSE;
81614                     }
81615                     metadata.pRawData = pRawData;
81616                     metadata.rawDataSize = blockSize;
81617                     pRunningData    = (const char*)pRawData;
81618                     pRunningDataEnd = (const char*)pRawData + blockSize;
81619                     metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
81620                     if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) {
81621                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81622                         return DRFLAC_FALSE;
81623                     }
81624                     metadata.data.vorbis_comment.vendor       = pRunningData;                                            pRunningData += metadata.data.vorbis_comment.vendorLength;
81625                     metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
81626                     if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) {
81627                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81628                         return DRFLAC_FALSE;
81629                     }
81630                     metadata.data.vorbis_comment.pComments    = pRunningData;
81631                     for (i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) {
81632                         drflac_uint32 commentLength;
81633                         if (pRunningDataEnd - pRunningData < 4) {
81634                             drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81635                             return DRFLAC_FALSE;
81636                         }
81637                         commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
81638                         if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) {
81639                             drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81640                             return DRFLAC_FALSE;
81641                         }
81642                         pRunningData += commentLength;
81643                     }
81644                     onMeta(pUserDataMD, &metadata);
81645                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81646                 }
81647             } break;
81648             case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET:
81649             {
81650                 if (blockSize < 396) {
81651                     return DRFLAC_FALSE;
81652                 }
81653                 if (onMeta) {
81654                     void* pRawData;
81655                     const char* pRunningData;
81656                     const char* pRunningDataEnd;
81657                     drflac_uint8 iTrack;
81658                     drflac_uint8 iIndex;
81659                     pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
81660                     if (pRawData == NULL) {
81661                         return DRFLAC_FALSE;
81662                     }
81663                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
81664                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81665                         return DRFLAC_FALSE;
81666                     }
81667                     metadata.pRawData = pRawData;
81668                     metadata.rawDataSize = blockSize;
81669                     pRunningData    = (const char*)pRawData;
81670                     pRunningDataEnd = (const char*)pRawData + blockSize;
81671                     DRFLAC_COPY_MEMORY(metadata.data.cuesheet.catalog, pRunningData, 128);                              pRunningData += 128;
81672                     metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8;
81673                     metadata.data.cuesheet.isCD              = (pRunningData[0] & 0x80) != 0;                           pRunningData += 259;
81674                     metadata.data.cuesheet.trackCount        = pRunningData[0];                                         pRunningData += 1;
81675                     metadata.data.cuesheet.pTrackData        = pRunningData;
81676                     for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) {
81677                         drflac_uint8 indexCount;
81678                         drflac_uint32 indexPointSize;
81679                         if (pRunningDataEnd - pRunningData < 36) {
81680                             drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81681                             return DRFLAC_FALSE;
81682                         }
81683                         pRunningData += 35;
81684                         indexCount = pRunningData[0]; pRunningData += 1;
81685                         indexPointSize = indexCount * sizeof(drflac_cuesheet_track_index);
81686                         if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) {
81687                             drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81688                             return DRFLAC_FALSE;
81689                         }
81690                         for (iIndex = 0; iIndex < indexCount; ++iIndex) {
81691                             drflac_cuesheet_track_index* pTrack = (drflac_cuesheet_track_index*)pRunningData;
81692                             pRunningData += sizeof(drflac_cuesheet_track_index);
81693                             pTrack->offset = drflac__be2host_64(pTrack->offset);
81694                         }
81695                     }
81696                     onMeta(pUserDataMD, &metadata);
81697                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81698                 }
81699             } break;
81700             case DRFLAC_METADATA_BLOCK_TYPE_PICTURE:
81701             {
81702                 if (blockSize < 32) {
81703                     return DRFLAC_FALSE;
81704                 }
81705                 if (onMeta) {
81706                     void* pRawData;
81707                     const char* pRunningData;
81708                     const char* pRunningDataEnd;
81709                     pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
81710                     if (pRawData == NULL) {
81711                         return DRFLAC_FALSE;
81712                     }
81713                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
81714                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81715                         return DRFLAC_FALSE;
81716                     }
81717                     metadata.pRawData = pRawData;
81718                     metadata.rawDataSize = blockSize;
81719                     pRunningData    = (const char*)pRawData;
81720                     pRunningDataEnd = (const char*)pRawData + blockSize;
81721                     metadata.data.picture.type       = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
81722                     metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
81723                     if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) {
81724                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81725                         return DRFLAC_FALSE;
81726                     }
81727                     metadata.data.picture.mime              = pRunningData;                                            pRunningData += metadata.data.picture.mimeLength;
81728                     metadata.data.picture.descriptionLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
81729                     if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) {
81730                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81731                         return DRFLAC_FALSE;
81732                     }
81733                     metadata.data.picture.description     = pRunningData;                                            pRunningData += metadata.data.picture.descriptionLength;
81734                     metadata.data.picture.width           = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
81735                     metadata.data.picture.height          = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
81736                     metadata.data.picture.colorDepth      = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
81737                     metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
81738                     metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
81739                     metadata.data.picture.pPictureData    = (const drflac_uint8*)pRunningData;
81740                     if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) {
81741                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81742                         return DRFLAC_FALSE;
81743                     }
81744                     onMeta(pUserDataMD, &metadata);
81745                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81746                 }
81747             } break;
81748             case DRFLAC_METADATA_BLOCK_TYPE_PADDING:
81749             {
81750                 if (onMeta) {
81751                     metadata.data.padding.unused = 0;
81752                     if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
81753                         isLastBlock = DRFLAC_TRUE;
81754                     } else {
81755                         onMeta(pUserDataMD, &metadata);
81756                     }
81757                 }
81758             } break;
81759             case DRFLAC_METADATA_BLOCK_TYPE_INVALID:
81760             {
81761                 if (onMeta) {
81762                     if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
81763                         isLastBlock = DRFLAC_TRUE;
81764                     }
81765                 }
81766             } break;
81767             default:
81768             {
81769                 if (onMeta) {
81770                     void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
81771                     if (pRawData == NULL) {
81772                         return DRFLAC_FALSE;
81773                     }
81774                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
81775                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81776                         return DRFLAC_FALSE;
81777                     }
81778                     metadata.pRawData = pRawData;
81779                     metadata.rawDataSize = blockSize;
81780                     onMeta(pUserDataMD, &metadata);
81781                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
81782                 }
81783             } break;
81784         }
81785         if (onMeta == NULL && blockSize > 0) {
81786             if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
81787                 isLastBlock = DRFLAC_TRUE;
81788             }
81789         }
81790         runningFilePos += blockSize;
81791         if (isLastBlock) {
81792             break;
81793         }
81794     }
81795     *pSeektablePos = seektablePos;
81796     *pSeektableSize = seektableSize;
81797     *pFirstFramePos = runningFilePos;
81798     return DRFLAC_TRUE;
81799 }
81800 static drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed)
81801 {
81802     drflac_uint8 isLastBlock;
81803     drflac_uint8 blockType;
81804     drflac_uint32 blockSize;
81805     (void)onSeek;
81806     pInit->container = drflac_container_native;
81807     if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
81808         return DRFLAC_FALSE;
81809     }
81810     if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
81811         if (!relaxed) {
81812             return DRFLAC_FALSE;
81813         } else {
81814             pInit->hasStreamInfoBlock = DRFLAC_FALSE;
81815             pInit->hasMetadataBlocks  = DRFLAC_FALSE;
81816             if (!drflac__read_next_flac_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) {
81817                 return DRFLAC_FALSE;
81818             }
81819             if (pInit->firstFrameHeader.bitsPerSample == 0) {
81820                 return DRFLAC_FALSE;
81821             }
81822             pInit->sampleRate              = pInit->firstFrameHeader.sampleRate;
81823             pInit->channels                = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment);
81824             pInit->bitsPerSample           = pInit->firstFrameHeader.bitsPerSample;
81825             pInit->maxBlockSizeInPCMFrames = 65535;
81826             return DRFLAC_TRUE;
81827         }
81828     } else {
81829         drflac_streaminfo streaminfo;
81830         if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
81831             return DRFLAC_FALSE;
81832         }
81833         pInit->hasStreamInfoBlock      = DRFLAC_TRUE;
81834         pInit->sampleRate              = streaminfo.sampleRate;
81835         pInit->channels                = streaminfo.channels;
81836         pInit->bitsPerSample           = streaminfo.bitsPerSample;
81837         pInit->totalPCMFrameCount      = streaminfo.totalPCMFrameCount;
81838         pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames;
81839         pInit->hasMetadataBlocks       = !isLastBlock;
81840         if (onMeta) {
81841             drflac_metadata metadata;
81842             metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
81843             metadata.pRawData = NULL;
81844             metadata.rawDataSize = 0;
81845             metadata.data.streaminfo = streaminfo;
81846             onMeta(pUserDataMD, &metadata);
81847         }
81848         return DRFLAC_TRUE;
81849     }
81850 }
81851 #ifndef DR_FLAC_NO_OGG
81852 #define DRFLAC_OGG_MAX_PAGE_SIZE            65307
81853 #define DRFLAC_OGG_CAPTURE_PATTERN_CRC32    1605413199
81854 typedef enum
81855 {
81856     drflac_ogg_recover_on_crc_mismatch,
81857     drflac_ogg_fail_on_crc_mismatch
81858 } drflac_ogg_crc_mismatch_recovery;
81859 #ifndef DR_FLAC_NO_CRC
81860 static drflac_uint32 drflac__crc32_table[] = {
81861     0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L,
81862     0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L,
81863     0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L,
81864     0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
81865     0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L,
81866     0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L,
81867     0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L,
81868     0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL,
81869     0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
81870     0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L,
81871     0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L,
81872     0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL,
81873     0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L,
81874     0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
81875     0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L,
81876     0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL,
81877     0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL,
81878     0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L,
81879     0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
81880     0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL,
81881     0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL,
81882     0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L,
81883     0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L,
81884     0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
81885     0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL,
81886     0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L,
81887     0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L,
81888     0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL,
81889     0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
81890     0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L,
81891     0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L,
81892     0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL,
81893     0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L,
81894     0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
81895     0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL,
81896     0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L,
81897     0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L,
81898     0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL,
81899     0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
81900     0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L,
81901     0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L,
81902     0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL,
81903     0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL,
81904     0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
81905     0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L,
81906     0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL,
81907     0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL,
81908     0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L,
81909     0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
81910     0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL,
81911     0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L,
81912     0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L,
81913     0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L,
81914     0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
81915     0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L,
81916     0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L,
81917     0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L,
81918     0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL,
81919     0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
81920     0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L,
81921     0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L,
81922     0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL,
81923     0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L,
81924     0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
81925 };
81926 #endif
81927 static DRFLAC_INLINE drflac_uint32 drflac_crc32_byte(drflac_uint32 crc32, drflac_uint8 data)
81928 {
81929 #ifndef DR_FLAC_NO_CRC
81930     return (crc32 << 8) ^ drflac__crc32_table[(drflac_uint8)((crc32 >> 24) & 0xFF) ^ data];
81931 #else
81932     (void)data;
81933     return crc32;
81934 #endif
81935 }
81936 #if 0
81937 static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint32(drflac_uint32 crc32, drflac_uint32 data)
81938 {
81939     crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 24) & 0xFF));
81940     crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 16) & 0xFF));
81941     crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >>  8) & 0xFF));
81942     crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >>  0) & 0xFF));
81943     return crc32;
81944 }
81945 static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint64(drflac_uint32 crc32, drflac_uint64 data)
81946 {
81947     crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 32) & 0xFFFFFFFF));
81948     crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >>  0) & 0xFFFFFFFF));
81949     return crc32;
81950 }
81951 #endif
81952 static DRFLAC_INLINE drflac_uint32 drflac_crc32_buffer(drflac_uint32 crc32, drflac_uint8* pData, drflac_uint32 dataSize)
81953 {
81954     drflac_uint32 i;
81955     for (i = 0; i < dataSize; ++i) {
81956         crc32 = drflac_crc32_byte(crc32, pData[i]);
81957     }
81958     return crc32;
81959 }
81960 static DRFLAC_INLINE drflac_bool32 drflac_ogg__is_capture_pattern(drflac_uint8 pattern[4])
81961 {
81962     return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S';
81963 }
81964 static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_header_size(drflac_ogg_page_header* pHeader)
81965 {
81966     return 27 + pHeader->segmentCount;
81967 }
81968 static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader)
81969 {
81970     drflac_uint32 pageBodySize = 0;
81971     int i;
81972     for (i = 0; i < pHeader->segmentCount; ++i) {
81973         pageBodySize += pHeader->segmentTable[i];
81974     }
81975     return pageBodySize;
81976 }
81977 static drflac_result drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32)
81978 {
81979     drflac_uint8 data[23];
81980     drflac_uint32 i;
81981     DRFLAC_ASSERT(*pCRC32 == DRFLAC_OGG_CAPTURE_PATTERN_CRC32);
81982     if (onRead(pUserData, data, 23) != 23) {
81983         return DRFLAC_AT_END;
81984     }
81985     *pBytesRead += 23;
81986     pHeader->capturePattern[0] = 'O';
81987     pHeader->capturePattern[1] = 'g';
81988     pHeader->capturePattern[2] = 'g';
81989     pHeader->capturePattern[3] = 'S';
81990     pHeader->structureVersion = data[0];
81991     pHeader->headerType       = data[1];
81992     DRFLAC_COPY_MEMORY(&pHeader->granulePosition, &data[ 2], 8);
81993     DRFLAC_COPY_MEMORY(&pHeader->serialNumber,    &data[10], 4);
81994     DRFLAC_COPY_MEMORY(&pHeader->sequenceNumber,  &data[14], 4);
81995     DRFLAC_COPY_MEMORY(&pHeader->checksum,        &data[18], 4);
81996     pHeader->segmentCount     = data[22];
81997     data[18] = 0;
81998     data[19] = 0;
81999     data[20] = 0;
82000     data[21] = 0;
82001     for (i = 0; i < 23; ++i) {
82002         *pCRC32 = drflac_crc32_byte(*pCRC32, data[i]);
82003     }
82004     if (onRead(pUserData, pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) {
82005         return DRFLAC_AT_END;
82006     }
82007     *pBytesRead += pHeader->segmentCount;
82008     for (i = 0; i < pHeader->segmentCount; ++i) {
82009         *pCRC32 = drflac_crc32_byte(*pCRC32, pHeader->segmentTable[i]);
82010     }
82011     return DRFLAC_SUCCESS;
82012 }
82013 static drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32)
82014 {
82015     drflac_uint8 id[4];
82016     *pBytesRead = 0;
82017     if (onRead(pUserData, id, 4) != 4) {
82018         return DRFLAC_AT_END;
82019     }
82020     *pBytesRead += 4;
82021     for (;;) {
82022         if (drflac_ogg__is_capture_pattern(id)) {
82023             drflac_result result;
82024             *pCRC32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32;
82025             result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32);
82026             if (result == DRFLAC_SUCCESS) {
82027                 return DRFLAC_SUCCESS;
82028             } else {
82029                 if (result == DRFLAC_CRC_MISMATCH) {
82030                     continue;
82031                 } else {
82032                     return result;
82033                 }
82034             }
82035         } else {
82036             id[0] = id[1];
82037             id[1] = id[2];
82038             id[2] = id[3];
82039             if (onRead(pUserData, &id[3], 1) != 1) {
82040                 return DRFLAC_AT_END;
82041             }
82042             *pBytesRead += 1;
82043         }
82044     }
82045 }
82046 typedef struct
82047 {
82048     drflac_read_proc onRead;
82049     drflac_seek_proc onSeek;
82050     void* pUserData;
82051     drflac_uint64 currentBytePos;
82052     drflac_uint64 firstBytePos;
82053     drflac_uint32 serialNumber;
82054     drflac_ogg_page_header bosPageHeader;
82055     drflac_ogg_page_header currentPageHeader;
82056     drflac_uint32 bytesRemainingInPage;
82057     drflac_uint32 pageDataSize;
82058     drflac_uint8 pageData[DRFLAC_OGG_MAX_PAGE_SIZE];
82059 } drflac_oggbs;
82060 static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead)
82061 {
82062     size_t bytesActuallyRead = oggbs->onRead(oggbs->pUserData, bufferOut, bytesToRead);
82063     oggbs->currentBytePos += bytesActuallyRead;
82064     return bytesActuallyRead;
82065 }
82066 static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin)
82067 {
82068     if (origin == drflac_seek_origin_start) {
82069         if (offset <= 0x7FFFFFFF) {
82070             if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) {
82071                 return DRFLAC_FALSE;
82072             }
82073             oggbs->currentBytePos = offset;
82074             return DRFLAC_TRUE;
82075         } else {
82076             if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
82077                 return DRFLAC_FALSE;
82078             }
82079             oggbs->currentBytePos = offset;
82080             return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current);
82081         }
82082     } else {
82083         while (offset > 0x7FFFFFFF) {
82084             if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
82085                 return DRFLAC_FALSE;
82086             }
82087             oggbs->currentBytePos += 0x7FFFFFFF;
82088             offset -= 0x7FFFFFFF;
82089         }
82090         if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) {
82091             return DRFLAC_FALSE;
82092         }
82093         oggbs->currentBytePos += offset;
82094         return DRFLAC_TRUE;
82095     }
82096 }
82097 static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_ogg_crc_mismatch_recovery recoveryMethod)
82098 {
82099     drflac_ogg_page_header header;
82100     for (;;) {
82101         drflac_uint32 crc32 = 0;
82102         drflac_uint32 bytesRead;
82103         drflac_uint32 pageBodySize;
82104 #ifndef DR_FLAC_NO_CRC
82105         drflac_uint32 actualCRC32;
82106 #endif
82107         if (drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
82108             return DRFLAC_FALSE;
82109         }
82110         oggbs->currentBytePos += bytesRead;
82111         pageBodySize = drflac_ogg__get_page_body_size(&header);
82112         if (pageBodySize > DRFLAC_OGG_MAX_PAGE_SIZE) {
82113             continue;
82114         }
82115         if (header.serialNumber != oggbs->serialNumber) {
82116             if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) {
82117                 return DRFLAC_FALSE;
82118             }
82119             continue;
82120         }
82121         if (drflac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) {
82122             return DRFLAC_FALSE;
82123         }
82124         oggbs->pageDataSize = pageBodySize;
82125 #ifndef DR_FLAC_NO_CRC
82126         actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize);
82127         if (actualCRC32 != header.checksum) {
82128             if (recoveryMethod == drflac_ogg_recover_on_crc_mismatch) {
82129                 continue;
82130             } else {
82131                 drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch);
82132                 return DRFLAC_FALSE;
82133             }
82134         }
82135 #else
82136         (void)recoveryMethod;
82137 #endif
82138         oggbs->currentPageHeader = header;
82139         oggbs->bytesRemainingInPage = pageBodySize;
82140         return DRFLAC_TRUE;
82141     }
82142 }
82143 #if 0
82144 static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, drflac_uint8* pBytesRemainingInSeg)
82145 {
82146     drflac_uint32 bytesConsumedInPage = drflac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage;
82147     drflac_uint8 iSeg = 0;
82148     drflac_uint32 iByte = 0;
82149     while (iByte < bytesConsumedInPage) {
82150         drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
82151         if (iByte + segmentSize > bytesConsumedInPage) {
82152             break;
82153         } else {
82154             iSeg += 1;
82155             iByte += segmentSize;
82156         }
82157     }
82158     *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (drflac_uint8)(bytesConsumedInPage - iByte);
82159     return iSeg;
82160 }
82161 static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
82162 {
82163     for (;;) {
82164         drflac_bool32 atEndOfPage = DRFLAC_FALSE;
82165         drflac_uint8 bytesRemainingInSeg;
82166         drflac_uint8 iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg);
82167         drflac_uint32 bytesToEndOfPacketOrPage = bytesRemainingInSeg;
82168         for (drflac_uint8 iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) {
82169             drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
82170             if (segmentSize < 255) {
82171                 if (iSeg == oggbs->currentPageHeader.segmentCount-1) {
82172                     atEndOfPage = DRFLAC_TRUE;
82173                 }
82174                 break;
82175             }
82176             bytesToEndOfPacketOrPage += segmentSize;
82177         }
82178         drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current);
82179         oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage;
82180         if (atEndOfPage) {
82181             if (!drflac_oggbs__goto_next_page(oggbs)) {
82182                 return DRFLAC_FALSE;
82183             }
82184             if ((oggbs->currentPageHeader.headerType & 0x01) == 0) {
82185                 return DRFLAC_TRUE;
82186             }
82187         } else {
82188             return DRFLAC_TRUE;
82189         }
82190     }
82191 }
82192 static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs)
82193 {
82194     return drflac_oggbs__seek_to_next_packet(oggbs);
82195 }
82196 #endif
82197 static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead)
82198 {
82199     drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
82200     drflac_uint8* pRunningBufferOut = (drflac_uint8*)bufferOut;
82201     size_t bytesRead = 0;
82202     DRFLAC_ASSERT(oggbs != NULL);
82203     DRFLAC_ASSERT(pRunningBufferOut != NULL);
82204     while (bytesRead < bytesToRead) {
82205         size_t bytesRemainingToRead = bytesToRead - bytesRead;
82206         if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) {
82207             DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), bytesRemainingToRead);
82208             bytesRead += bytesRemainingToRead;
82209             oggbs->bytesRemainingInPage -= (drflac_uint32)bytesRemainingToRead;
82210             break;
82211         }
82212         if (oggbs->bytesRemainingInPage > 0) {
82213             DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), oggbs->bytesRemainingInPage);
82214             bytesRead += oggbs->bytesRemainingInPage;
82215             pRunningBufferOut += oggbs->bytesRemainingInPage;
82216             oggbs->bytesRemainingInPage = 0;
82217         }
82218         DRFLAC_ASSERT(bytesRemainingToRead > 0);
82219         if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
82220             break;
82221         }
82222     }
82223     return bytesRead;
82224 }
82225 static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin)
82226 {
82227     drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
82228     int bytesSeeked = 0;
82229     DRFLAC_ASSERT(oggbs != NULL);
82230     DRFLAC_ASSERT(offset >= 0);
82231     if (origin == drflac_seek_origin_start) {
82232         if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) {
82233             return DRFLAC_FALSE;
82234         }
82235         if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
82236             return DRFLAC_FALSE;
82237         }
82238         return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current);
82239     }
82240     DRFLAC_ASSERT(origin == drflac_seek_origin_current);
82241     while (bytesSeeked < offset) {
82242         int bytesRemainingToSeek = offset - bytesSeeked;
82243         DRFLAC_ASSERT(bytesRemainingToSeek >= 0);
82244         if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) {
82245             bytesSeeked += bytesRemainingToSeek;
82246             (void)bytesSeeked;
82247             oggbs->bytesRemainingInPage -= bytesRemainingToSeek;
82248             break;
82249         }
82250         if (oggbs->bytesRemainingInPage > 0) {
82251             bytesSeeked += (int)oggbs->bytesRemainingInPage;
82252             oggbs->bytesRemainingInPage = 0;
82253         }
82254         DRFLAC_ASSERT(bytesRemainingToSeek > 0);
82255         if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
82256             return DRFLAC_FALSE;
82257         }
82258     }
82259     return DRFLAC_TRUE;
82260 }
82261 static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
82262 {
82263     drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
82264     drflac_uint64 originalBytePos;
82265     drflac_uint64 runningGranulePosition;
82266     drflac_uint64 runningFrameBytePos;
82267     drflac_uint64 runningPCMFrameCount;
82268     DRFLAC_ASSERT(oggbs != NULL);
82269     originalBytePos = oggbs->currentBytePos;
82270     if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes)) {
82271         return DRFLAC_FALSE;
82272     }
82273     oggbs->bytesRemainingInPage = 0;
82274     runningGranulePosition = 0;
82275     for (;;) {
82276         if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
82277             drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
82278             return DRFLAC_FALSE;
82279         }
82280         runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize;
82281         if (oggbs->currentPageHeader.granulePosition >= pcmFrameIndex) {
82282             break;
82283         }
82284         if ((oggbs->currentPageHeader.headerType & 0x01) == 0) {
82285             if (oggbs->currentPageHeader.segmentTable[0] >= 2) {
82286                 drflac_uint8 firstBytesInPage[2];
82287                 firstBytesInPage[0] = oggbs->pageData[0];
82288                 firstBytesInPage[1] = oggbs->pageData[1];
82289                 if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) {
82290                     runningGranulePosition = oggbs->currentPageHeader.granulePosition;
82291                 }
82292                 continue;
82293             }
82294         }
82295     }
82296     if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) {
82297         return DRFLAC_FALSE;
82298     }
82299     if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
82300         return DRFLAC_FALSE;
82301     }
82302     runningPCMFrameCount = runningGranulePosition;
82303     for (;;) {
82304         drflac_uint64 firstPCMFrameInFLACFrame = 0;
82305         drflac_uint64 lastPCMFrameInFLACFrame = 0;
82306         drflac_uint64 pcmFrameCountInThisFrame;
82307         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
82308             return DRFLAC_FALSE;
82309         }
82310         drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
82311         pcmFrameCountInThisFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
82312         if (pcmFrameIndex == pFlac->totalPCMFrameCount && (runningPCMFrameCount + pcmFrameCountInThisFrame) == pFlac->totalPCMFrameCount) {
82313             drflac_result result = drflac__decode_flac_frame(pFlac);
82314             if (result == DRFLAC_SUCCESS) {
82315                 pFlac->currentPCMFrame = pcmFrameIndex;
82316                 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
82317                 return DRFLAC_TRUE;
82318             } else {
82319                 return DRFLAC_FALSE;
82320             }
82321         }
82322         if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFrame)) {
82323             drflac_result result = drflac__decode_flac_frame(pFlac);
82324             if (result == DRFLAC_SUCCESS) {
82325                 drflac_uint64 pcmFramesToDecode = (size_t)(pcmFrameIndex - runningPCMFrameCount);
82326                 if (pcmFramesToDecode == 0) {
82327                     return DRFLAC_TRUE;
82328                 }
82329                 pFlac->currentPCMFrame = runningPCMFrameCount;
82330                 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
82331             } else {
82332                 if (result == DRFLAC_CRC_MISMATCH) {
82333                     continue;
82334                 } else {
82335                     return DRFLAC_FALSE;
82336                 }
82337             }
82338         } else {
82339             drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
82340             if (result == DRFLAC_SUCCESS) {
82341                 runningPCMFrameCount += pcmFrameCountInThisFrame;
82342             } else {
82343                 if (result == DRFLAC_CRC_MISMATCH) {
82344                     continue;
82345                 } else {
82346                     return DRFLAC_FALSE;
82347                 }
82348             }
82349         }
82350     }
82351 }
82352 static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed)
82353 {
82354     drflac_ogg_page_header header;
82355     drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32;
82356     drflac_uint32 bytesRead = 0;
82357     (void)relaxed;
82358     pInit->container = drflac_container_ogg;
82359     pInit->oggFirstBytePos = 0;
82360     if (drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
82361         return DRFLAC_FALSE;
82362     }
82363     pInit->runningFilePos += bytesRead;
82364     for (;;) {
82365         int pageBodySize;
82366         if ((header.headerType & 0x02) == 0) {
82367             return DRFLAC_FALSE;
82368         }
82369         pageBodySize = drflac_ogg__get_page_body_size(&header);
82370         if (pageBodySize == 51) {
82371             drflac_uint32 bytesRemainingInPage = pageBodySize;
82372             drflac_uint8 packetType;
82373             if (onRead(pUserData, &packetType, 1) != 1) {
82374                 return DRFLAC_FALSE;
82375             }
82376             bytesRemainingInPage -= 1;
82377             if (packetType == 0x7F) {
82378                 drflac_uint8 sig[4];
82379                 if (onRead(pUserData, sig, 4) != 4) {
82380                     return DRFLAC_FALSE;
82381                 }
82382                 bytesRemainingInPage -= 4;
82383                 if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') {
82384                     drflac_uint8 mappingVersion[2];
82385                     if (onRead(pUserData, mappingVersion, 2) != 2) {
82386                         return DRFLAC_FALSE;
82387                     }
82388                     if (mappingVersion[0] != 1) {
82389                         return DRFLAC_FALSE;
82390                     }
82391                     if (!onSeek(pUserData, 2, drflac_seek_origin_current)) {
82392                         return DRFLAC_FALSE;
82393                     }
82394                     if (onRead(pUserData, sig, 4) != 4) {
82395                         return DRFLAC_FALSE;
82396                     }
82397                     if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C') {
82398                         drflac_streaminfo streaminfo;
82399                         drflac_uint8 isLastBlock;
82400                         drflac_uint8 blockType;
82401                         drflac_uint32 blockSize;
82402                         if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
82403                             return DRFLAC_FALSE;
82404                         }
82405                         if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
82406                             return DRFLAC_FALSE;
82407                         }
82408                         if (drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
82409                             pInit->hasStreamInfoBlock      = DRFLAC_TRUE;
82410                             pInit->sampleRate              = streaminfo.sampleRate;
82411                             pInit->channels                = streaminfo.channels;
82412                             pInit->bitsPerSample           = streaminfo.bitsPerSample;
82413                             pInit->totalPCMFrameCount      = streaminfo.totalPCMFrameCount;
82414                             pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames;
82415                             pInit->hasMetadataBlocks       = !isLastBlock;
82416                             if (onMeta) {
82417                                 drflac_metadata metadata;
82418                                 metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
82419                                 metadata.pRawData = NULL;
82420                                 metadata.rawDataSize = 0;
82421                                 metadata.data.streaminfo = streaminfo;
82422                                 onMeta(pUserDataMD, &metadata);
82423                             }
82424                             pInit->runningFilePos  += pageBodySize;
82425                             pInit->oggFirstBytePos  = pInit->runningFilePos - 79;
82426                             pInit->oggSerial        = header.serialNumber;
82427                             pInit->oggBosHeader     = header;
82428                             break;
82429                         } else {
82430                             return DRFLAC_FALSE;
82431                         }
82432                     } else {
82433                         return DRFLAC_FALSE;
82434                     }
82435                 } else {
82436                     if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
82437                         return DRFLAC_FALSE;
82438                     }
82439                 }
82440             } else {
82441                 if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
82442                     return DRFLAC_FALSE;
82443                 }
82444             }
82445         } else {
82446             if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) {
82447                 return DRFLAC_FALSE;
82448             }
82449         }
82450         pInit->runningFilePos += pageBodySize;
82451         if (drflac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
82452             return DRFLAC_FALSE;
82453         }
82454         pInit->runningFilePos += bytesRead;
82455     }
82456     pInit->hasMetadataBlocks = DRFLAC_TRUE;
82457     return DRFLAC_TRUE;
82458 }
82459 #endif
82460 static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD)
82461 {
82462     drflac_bool32 relaxed;
82463     drflac_uint8 id[4];
82464     if (pInit == NULL || onRead == NULL || onSeek == NULL) {
82465         return DRFLAC_FALSE;
82466     }
82467     DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit));
82468     pInit->onRead       = onRead;
82469     pInit->onSeek       = onSeek;
82470     pInit->onMeta       = onMeta;
82471     pInit->container    = container;
82472     pInit->pUserData    = pUserData;
82473     pInit->pUserDataMD  = pUserDataMD;
82474     pInit->bs.onRead    = onRead;
82475     pInit->bs.onSeek    = onSeek;
82476     pInit->bs.pUserData = pUserData;
82477     drflac__reset_cache(&pInit->bs);
82478     relaxed = container != drflac_container_unknown;
82479     for (;;) {
82480         if (onRead(pUserData, id, 4) != 4) {
82481             return DRFLAC_FALSE;
82482         }
82483         pInit->runningFilePos += 4;
82484         if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') {
82485             drflac_uint8 header[6];
82486             drflac_uint8 flags;
82487             drflac_uint32 headerSize;
82488             if (onRead(pUserData, header, 6) != 6) {
82489                 return DRFLAC_FALSE;
82490             }
82491             pInit->runningFilePos += 6;
82492             flags = header[1];
82493             DRFLAC_COPY_MEMORY(&headerSize, header+2, 4);
82494             headerSize = drflac__unsynchsafe_32(drflac__be2host_32(headerSize));
82495             if (flags & 0x10) {
82496                 headerSize += 10;
82497             }
82498             if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) {
82499                 return DRFLAC_FALSE;
82500             }
82501             pInit->runningFilePos += headerSize;
82502         } else {
82503             break;
82504         }
82505     }
82506     if (id[0] == 'f' && id[1] == 'L' && id[2] == 'a' && id[3] == 'C') {
82507         return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
82508     }
82509 #ifndef DR_FLAC_NO_OGG
82510     if (id[0] == 'O' && id[1] == 'g' && id[2] == 'g' && id[3] == 'S') {
82511         return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
82512     }
82513 #endif
82514     if (relaxed) {
82515         if (container == drflac_container_native) {
82516             return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
82517         }
82518 #ifndef DR_FLAC_NO_OGG
82519         if (container == drflac_container_ogg) {
82520             return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
82521         }
82522 #endif
82523     }
82524     return DRFLAC_FALSE;
82525 }
82526 static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit)
82527 {
82528     DRFLAC_ASSERT(pFlac != NULL);
82529     DRFLAC_ASSERT(pInit != NULL);
82530     DRFLAC_ZERO_MEMORY(pFlac, sizeof(*pFlac));
82531     pFlac->bs                      = pInit->bs;
82532     pFlac->onMeta                  = pInit->onMeta;
82533     pFlac->pUserDataMD             = pInit->pUserDataMD;
82534     pFlac->maxBlockSizeInPCMFrames = pInit->maxBlockSizeInPCMFrames;
82535     pFlac->sampleRate              = pInit->sampleRate;
82536     pFlac->channels                = (drflac_uint8)pInit->channels;
82537     pFlac->bitsPerSample           = (drflac_uint8)pInit->bitsPerSample;
82538     pFlac->totalPCMFrameCount      = pInit->totalPCMFrameCount;
82539     pFlac->container               = pInit->container;
82540 }
82541 static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks)
82542 {
82543     drflac_init_info init;
82544     drflac_uint32 allocationSize;
82545     drflac_uint32 wholeSIMDVectorCountPerChannel;
82546     drflac_uint32 decodedSamplesAllocationSize;
82547 #ifndef DR_FLAC_NO_OGG
82548     drflac_oggbs oggbs;
82549 #endif
82550     drflac_uint64 firstFramePos;
82551     drflac_uint64 seektablePos;
82552     drflac_uint32 seektableSize;
82553     drflac_allocation_callbacks allocationCallbacks;
82554     drflac* pFlac;
82555     drflac__init_cpu_caps();
82556     if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) {
82557         return NULL;
82558     }
82559     if (pAllocationCallbacks != NULL) {
82560         allocationCallbacks = *pAllocationCallbacks;
82561         if (allocationCallbacks.onFree == NULL || (allocationCallbacks.onMalloc == NULL && allocationCallbacks.onRealloc == NULL)) {
82562             return NULL;
82563         }
82564     } else {
82565         allocationCallbacks.pUserData = NULL;
82566         allocationCallbacks.onMalloc  = drflac__malloc_default;
82567         allocationCallbacks.onRealloc = drflac__realloc_default;
82568         allocationCallbacks.onFree    = drflac__free_default;
82569     }
82570     allocationSize = sizeof(drflac);
82571     if ((init.maxBlockSizeInPCMFrames % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) {
82572         wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32)));
82573     } else {
82574         wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1;
82575     }
82576     decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels;
82577     allocationSize += decodedSamplesAllocationSize;
82578     allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE;
82579 #ifndef DR_FLAC_NO_OGG
82580     if (init.container == drflac_container_ogg) {
82581         allocationSize += sizeof(drflac_oggbs);
82582     }
82583     DRFLAC_ZERO_MEMORY(&oggbs, sizeof(oggbs));
82584     if (init.container == drflac_container_ogg) {
82585         oggbs.onRead = onRead;
82586         oggbs.onSeek = onSeek;
82587         oggbs.pUserData = pUserData;
82588         oggbs.currentBytePos = init.oggFirstBytePos;
82589         oggbs.firstBytePos = init.oggFirstBytePos;
82590         oggbs.serialNumber = init.oggSerial;
82591         oggbs.bosPageHeader = init.oggBosHeader;
82592         oggbs.bytesRemainingInPage = 0;
82593     }
82594 #endif
82595     firstFramePos = 42;
82596     seektablePos  = 0;
82597     seektableSize = 0;
82598     if (init.hasMetadataBlocks) {
82599         drflac_read_proc onReadOverride = onRead;
82600         drflac_seek_proc onSeekOverride = onSeek;
82601         void* pUserDataOverride = pUserData;
82602 #ifndef DR_FLAC_NO_OGG
82603         if (init.container == drflac_container_ogg) {
82604             onReadOverride = drflac__on_read_ogg;
82605             onSeekOverride = drflac__on_seek_ogg;
82606             pUserDataOverride = (void*)&oggbs;
82607         }
82608 #endif
82609         if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seektableSize, &allocationCallbacks)) {
82610             return NULL;
82611         }
82612         allocationSize += seektableSize;
82613     }
82614     pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks);
82615     if (pFlac == NULL) {
82616         return NULL;
82617     }
82618     drflac__init_from_info(pFlac, &init);
82619     pFlac->allocationCallbacks = allocationCallbacks;
82620     pFlac->pDecodedSamples = (drflac_int32*)drflac_align((size_t)pFlac->pExtraData, DRFLAC_MAX_SIMD_VECTOR_SIZE);
82621 #ifndef DR_FLAC_NO_OGG
82622     if (init.container == drflac_container_ogg) {
82623         drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + seektableSize);
82624         *pInternalOggbs = oggbs;
82625         pFlac->bs.onRead = drflac__on_read_ogg;
82626         pFlac->bs.onSeek = drflac__on_seek_ogg;
82627         pFlac->bs.pUserData = (void*)pInternalOggbs;
82628         pFlac->_oggbs = (void*)pInternalOggbs;
82629     }
82630 #endif
82631     pFlac->firstFLACFramePosInBytes = firstFramePos;
82632 #ifndef DR_FLAC_NO_OGG
82633     if (init.container == drflac_container_ogg)
82634     {
82635         pFlac->pSeekpoints = NULL;
82636         pFlac->seekpointCount = 0;
82637     }
82638     else
82639 #endif
82640     {
82641         if (seektablePos != 0) {
82642             pFlac->seekpointCount = seektableSize / sizeof(*pFlac->pSeekpoints);
82643             pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize);
82644             DRFLAC_ASSERT(pFlac->bs.onSeek != NULL);
82645             DRFLAC_ASSERT(pFlac->bs.onRead != NULL);
82646             if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) {
82647                 if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints, seektableSize) == seektableSize) {
82648                     drflac_uint32 iSeekpoint;
82649                     for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
82650                         pFlac->pSeekpoints[iSeekpoint].firstPCMFrame   = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame);
82651                         pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset);
82652                         pFlac->pSeekpoints[iSeekpoint].pcmFrameCount   = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount);
82653                     }
82654                 } else {
82655                     pFlac->pSeekpoints = NULL;
82656                     pFlac->seekpointCount = 0;
82657                 }
82658                 if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) {
82659                     drflac__free_from_callbacks(pFlac, &allocationCallbacks);
82660                     return NULL;
82661                 }
82662             } else {
82663                 pFlac->pSeekpoints = NULL;
82664                 pFlac->seekpointCount = 0;
82665             }
82666         }
82667     }
82668     if (!init.hasStreamInfoBlock) {
82669         pFlac->currentFLACFrame.header = init.firstFrameHeader;
82670         for (;;) {
82671             drflac_result result = drflac__decode_flac_frame(pFlac);
82672             if (result == DRFLAC_SUCCESS) {
82673                 break;
82674             } else {
82675                 if (result == DRFLAC_CRC_MISMATCH) {
82676                     if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
82677                         drflac__free_from_callbacks(pFlac, &allocationCallbacks);
82678                         return NULL;
82679                     }
82680                     continue;
82681                 } else {
82682                     drflac__free_from_callbacks(pFlac, &allocationCallbacks);
82683                     return NULL;
82684                 }
82685             }
82686         }
82687     }
82688     return pFlac;
82689 }
82690 #ifndef DR_FLAC_NO_STDIO
82691 #include <stdio.h>
82692 #include <wchar.h>
82693 #include <errno.h>
82694 static drflac_result drflac_result_from_errno(int e)
82695 {
82696     switch (e)
82697     {
82698         case 0: return DRFLAC_SUCCESS;
82699     #ifdef EPERM
82700         case EPERM: return DRFLAC_INVALID_OPERATION;
82701     #endif
82702     #ifdef ENOENT
82703         case ENOENT: return DRFLAC_DOES_NOT_EXIST;
82704     #endif
82705     #ifdef ESRCH
82706         case ESRCH: return DRFLAC_DOES_NOT_EXIST;
82707     #endif
82708     #ifdef EINTR
82709         case EINTR: return DRFLAC_INTERRUPT;
82710     #endif
82711     #ifdef EIO
82712         case EIO: return DRFLAC_IO_ERROR;
82713     #endif
82714     #ifdef ENXIO
82715         case ENXIO: return DRFLAC_DOES_NOT_EXIST;
82716     #endif
82717     #ifdef E2BIG
82718         case E2BIG: return DRFLAC_INVALID_ARGS;
82719     #endif
82720     #ifdef ENOEXEC
82721         case ENOEXEC: return DRFLAC_INVALID_FILE;
82722     #endif
82723     #ifdef EBADF
82724         case EBADF: return DRFLAC_INVALID_FILE;
82725     #endif
82726     #ifdef ECHILD
82727         case ECHILD: return DRFLAC_ERROR;
82728     #endif
82729     #ifdef EAGAIN
82730         case EAGAIN: return DRFLAC_UNAVAILABLE;
82731     #endif
82732     #ifdef ENOMEM
82733         case ENOMEM: return DRFLAC_OUT_OF_MEMORY;
82734     #endif
82735     #ifdef EACCES
82736         case EACCES: return DRFLAC_ACCESS_DENIED;
82737     #endif
82738     #ifdef EFAULT
82739         case EFAULT: return DRFLAC_BAD_ADDRESS;
82740     #endif
82741     #ifdef ENOTBLK
82742         case ENOTBLK: return DRFLAC_ERROR;
82743     #endif
82744     #ifdef EBUSY
82745         case EBUSY: return DRFLAC_BUSY;
82746     #endif
82747     #ifdef EEXIST
82748         case EEXIST: return DRFLAC_ALREADY_EXISTS;
82749     #endif
82750     #ifdef EXDEV
82751         case EXDEV: return DRFLAC_ERROR;
82752     #endif
82753     #ifdef ENODEV
82754         case ENODEV: return DRFLAC_DOES_NOT_EXIST;
82755     #endif
82756     #ifdef ENOTDIR
82757         case ENOTDIR: return DRFLAC_NOT_DIRECTORY;
82758     #endif
82759     #ifdef EISDIR
82760         case EISDIR: return DRFLAC_IS_DIRECTORY;
82761     #endif
82762     #ifdef EINVAL
82763         case EINVAL: return DRFLAC_INVALID_ARGS;
82764     #endif
82765     #ifdef ENFILE
82766         case ENFILE: return DRFLAC_TOO_MANY_OPEN_FILES;
82767     #endif
82768     #ifdef EMFILE
82769         case EMFILE: return DRFLAC_TOO_MANY_OPEN_FILES;
82770     #endif
82771     #ifdef ENOTTY
82772         case ENOTTY: return DRFLAC_INVALID_OPERATION;
82773     #endif
82774     #ifdef ETXTBSY
82775         case ETXTBSY: return DRFLAC_BUSY;
82776     #endif
82777     #ifdef EFBIG
82778         case EFBIG: return DRFLAC_TOO_BIG;
82779     #endif
82780     #ifdef ENOSPC
82781         case ENOSPC: return DRFLAC_NO_SPACE;
82782     #endif
82783     #ifdef ESPIPE
82784         case ESPIPE: return DRFLAC_BAD_SEEK;
82785     #endif
82786     #ifdef EROFS
82787         case EROFS: return DRFLAC_ACCESS_DENIED;
82788     #endif
82789     #ifdef EMLINK
82790         case EMLINK: return DRFLAC_TOO_MANY_LINKS;
82791     #endif
82792     #ifdef EPIPE
82793         case EPIPE: return DRFLAC_BAD_PIPE;
82794     #endif
82795     #ifdef EDOM
82796         case EDOM: return DRFLAC_OUT_OF_RANGE;
82797     #endif
82798     #ifdef ERANGE
82799         case ERANGE: return DRFLAC_OUT_OF_RANGE;
82800     #endif
82801     #ifdef EDEADLK
82802         case EDEADLK: return DRFLAC_DEADLOCK;
82803     #endif
82804     #ifdef ENAMETOOLONG
82805         case ENAMETOOLONG: return DRFLAC_PATH_TOO_LONG;
82806     #endif
82807     #ifdef ENOLCK
82808         case ENOLCK: return DRFLAC_ERROR;
82809     #endif
82810     #ifdef ENOSYS
82811         case ENOSYS: return DRFLAC_NOT_IMPLEMENTED;
82812     #endif
82813     #ifdef ENOTEMPTY
82814         case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY;
82815     #endif
82816     #ifdef ELOOP
82817         case ELOOP: return DRFLAC_TOO_MANY_LINKS;
82818     #endif
82819     #ifdef ENOMSG
82820         case ENOMSG: return DRFLAC_NO_MESSAGE;
82821     #endif
82822     #ifdef EIDRM
82823         case EIDRM: return DRFLAC_ERROR;
82824     #endif
82825     #ifdef ECHRNG
82826         case ECHRNG: return DRFLAC_ERROR;
82827     #endif
82828     #ifdef EL2NSYNC
82829         case EL2NSYNC: return DRFLAC_ERROR;
82830     #endif
82831     #ifdef EL3HLT
82832         case EL3HLT: return DRFLAC_ERROR;
82833     #endif
82834     #ifdef EL3RST
82835         case EL3RST: return DRFLAC_ERROR;
82836     #endif
82837     #ifdef ELNRNG
82838         case ELNRNG: return DRFLAC_OUT_OF_RANGE;
82839     #endif
82840     #ifdef EUNATCH
82841         case EUNATCH: return DRFLAC_ERROR;
82842     #endif
82843     #ifdef ENOCSI
82844         case ENOCSI: return DRFLAC_ERROR;
82845     #endif
82846     #ifdef EL2HLT
82847         case EL2HLT: return DRFLAC_ERROR;
82848     #endif
82849     #ifdef EBADE
82850         case EBADE: return DRFLAC_ERROR;
82851     #endif
82852     #ifdef EBADR
82853         case EBADR: return DRFLAC_ERROR;
82854     #endif
82855     #ifdef EXFULL
82856         case EXFULL: return DRFLAC_ERROR;
82857     #endif
82858     #ifdef ENOANO
82859         case ENOANO: return DRFLAC_ERROR;
82860     #endif
82861     #ifdef EBADRQC
82862         case EBADRQC: return DRFLAC_ERROR;
82863     #endif
82864     #ifdef EBADSLT
82865         case EBADSLT: return DRFLAC_ERROR;
82866     #endif
82867     #ifdef EBFONT
82868         case EBFONT: return DRFLAC_INVALID_FILE;
82869     #endif
82870     #ifdef ENOSTR
82871         case ENOSTR: return DRFLAC_ERROR;
82872     #endif
82873     #ifdef ENODATA
82874         case ENODATA: return DRFLAC_NO_DATA_AVAILABLE;
82875     #endif
82876     #ifdef ETIME
82877         case ETIME: return DRFLAC_TIMEOUT;
82878     #endif
82879     #ifdef ENOSR
82880         case ENOSR: return DRFLAC_NO_DATA_AVAILABLE;
82881     #endif
82882     #ifdef ENONET
82883         case ENONET: return DRFLAC_NO_NETWORK;
82884     #endif
82885     #ifdef ENOPKG
82886         case ENOPKG: return DRFLAC_ERROR;
82887     #endif
82888     #ifdef EREMOTE
82889         case EREMOTE: return DRFLAC_ERROR;
82890     #endif
82891     #ifdef ENOLINK
82892         case ENOLINK: return DRFLAC_ERROR;
82893     #endif
82894     #ifdef EADV
82895         case EADV: return DRFLAC_ERROR;
82896     #endif
82897     #ifdef ESRMNT
82898         case ESRMNT: return DRFLAC_ERROR;
82899     #endif
82900     #ifdef ECOMM
82901         case ECOMM: return DRFLAC_ERROR;
82902     #endif
82903     #ifdef EPROTO
82904         case EPROTO: return DRFLAC_ERROR;
82905     #endif
82906     #ifdef EMULTIHOP
82907         case EMULTIHOP: return DRFLAC_ERROR;
82908     #endif
82909     #ifdef EDOTDOT
82910         case EDOTDOT: return DRFLAC_ERROR;
82911     #endif
82912     #ifdef EBADMSG
82913         case EBADMSG: return DRFLAC_BAD_MESSAGE;
82914     #endif
82915     #ifdef EOVERFLOW
82916         case EOVERFLOW: return DRFLAC_TOO_BIG;
82917     #endif
82918     #ifdef ENOTUNIQ
82919         case ENOTUNIQ: return DRFLAC_NOT_UNIQUE;
82920     #endif
82921     #ifdef EBADFD
82922         case EBADFD: return DRFLAC_ERROR;
82923     #endif
82924     #ifdef EREMCHG
82925         case EREMCHG: return DRFLAC_ERROR;
82926     #endif
82927     #ifdef ELIBACC
82928         case ELIBACC: return DRFLAC_ACCESS_DENIED;
82929     #endif
82930     #ifdef ELIBBAD
82931         case ELIBBAD: return DRFLAC_INVALID_FILE;
82932     #endif
82933     #ifdef ELIBSCN
82934         case ELIBSCN: return DRFLAC_INVALID_FILE;
82935     #endif
82936     #ifdef ELIBMAX
82937         case ELIBMAX: return DRFLAC_ERROR;
82938     #endif
82939     #ifdef ELIBEXEC
82940         case ELIBEXEC: return DRFLAC_ERROR;
82941     #endif
82942     #ifdef EILSEQ
82943         case EILSEQ: return DRFLAC_INVALID_DATA;
82944     #endif
82945     #ifdef ERESTART
82946         case ERESTART: return DRFLAC_ERROR;
82947     #endif
82948     #ifdef ESTRPIPE
82949         case ESTRPIPE: return DRFLAC_ERROR;
82950     #endif
82951     #ifdef EUSERS
82952         case EUSERS: return DRFLAC_ERROR;
82953     #endif
82954     #ifdef ENOTSOCK
82955         case ENOTSOCK: return DRFLAC_NOT_SOCKET;
82956     #endif
82957     #ifdef EDESTADDRREQ
82958         case EDESTADDRREQ: return DRFLAC_NO_ADDRESS;
82959     #endif
82960     #ifdef EMSGSIZE
82961         case EMSGSIZE: return DRFLAC_TOO_BIG;
82962     #endif
82963     #ifdef EPROTOTYPE
82964         case EPROTOTYPE: return DRFLAC_BAD_PROTOCOL;
82965     #endif
82966     #ifdef ENOPROTOOPT
82967         case ENOPROTOOPT: return DRFLAC_PROTOCOL_UNAVAILABLE;
82968     #endif
82969     #ifdef EPROTONOSUPPORT
82970         case EPROTONOSUPPORT: return DRFLAC_PROTOCOL_NOT_SUPPORTED;
82971     #endif
82972     #ifdef ESOCKTNOSUPPORT
82973         case ESOCKTNOSUPPORT: return DRFLAC_SOCKET_NOT_SUPPORTED;
82974     #endif
82975     #ifdef EOPNOTSUPP
82976         case EOPNOTSUPP: return DRFLAC_INVALID_OPERATION;
82977     #endif
82978     #ifdef EPFNOSUPPORT
82979         case EPFNOSUPPORT: return DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED;
82980     #endif
82981     #ifdef EAFNOSUPPORT
82982         case EAFNOSUPPORT: return DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED;
82983     #endif
82984     #ifdef EADDRINUSE
82985         case EADDRINUSE: return DRFLAC_ALREADY_IN_USE;
82986     #endif
82987     #ifdef EADDRNOTAVAIL
82988         case EADDRNOTAVAIL: return DRFLAC_ERROR;
82989     #endif
82990     #ifdef ENETDOWN
82991         case ENETDOWN: return DRFLAC_NO_NETWORK;
82992     #endif
82993     #ifdef ENETUNREACH
82994         case ENETUNREACH: return DRFLAC_NO_NETWORK;
82995     #endif
82996     #ifdef ENETRESET
82997         case ENETRESET: return DRFLAC_NO_NETWORK;
82998     #endif
82999     #ifdef ECONNABORTED
83000         case ECONNABORTED: return DRFLAC_NO_NETWORK;
83001     #endif
83002     #ifdef ECONNRESET
83003         case ECONNRESET: return DRFLAC_CONNECTION_RESET;
83004     #endif
83005     #ifdef ENOBUFS
83006         case ENOBUFS: return DRFLAC_NO_SPACE;
83007     #endif
83008     #ifdef EISCONN
83009         case EISCONN: return DRFLAC_ALREADY_CONNECTED;
83010     #endif
83011     #ifdef ENOTCONN
83012         case ENOTCONN: return DRFLAC_NOT_CONNECTED;
83013     #endif
83014     #ifdef ESHUTDOWN
83015         case ESHUTDOWN: return DRFLAC_ERROR;
83016     #endif
83017     #ifdef ETOOMANYREFS
83018         case ETOOMANYREFS: return DRFLAC_ERROR;
83019     #endif
83020     #ifdef ETIMEDOUT
83021         case ETIMEDOUT: return DRFLAC_TIMEOUT;
83022     #endif
83023     #ifdef ECONNREFUSED
83024         case ECONNREFUSED: return DRFLAC_CONNECTION_REFUSED;
83025     #endif
83026     #ifdef EHOSTDOWN
83027         case EHOSTDOWN: return DRFLAC_NO_HOST;
83028     #endif
83029     #ifdef EHOSTUNREACH
83030         case EHOSTUNREACH: return DRFLAC_NO_HOST;
83031     #endif
83032     #ifdef EALREADY
83033         case EALREADY: return DRFLAC_IN_PROGRESS;
83034     #endif
83035     #ifdef EINPROGRESS
83036         case EINPROGRESS: return DRFLAC_IN_PROGRESS;
83037     #endif
83038     #ifdef ESTALE
83039         case ESTALE: return DRFLAC_INVALID_FILE;
83040     #endif
83041     #ifdef EUCLEAN
83042         case EUCLEAN: return DRFLAC_ERROR;
83043     #endif
83044     #ifdef ENOTNAM
83045         case ENOTNAM: return DRFLAC_ERROR;
83046     #endif
83047     #ifdef ENAVAIL
83048         case ENAVAIL: return DRFLAC_ERROR;
83049     #endif
83050     #ifdef EISNAM
83051         case EISNAM: return DRFLAC_ERROR;
83052     #endif
83053     #ifdef EREMOTEIO
83054         case EREMOTEIO: return DRFLAC_IO_ERROR;
83055     #endif
83056     #ifdef EDQUOT
83057         case EDQUOT: return DRFLAC_NO_SPACE;
83058     #endif
83059     #ifdef ENOMEDIUM
83060         case ENOMEDIUM: return DRFLAC_DOES_NOT_EXIST;
83061     #endif
83062     #ifdef EMEDIUMTYPE
83063         case EMEDIUMTYPE: return DRFLAC_ERROR;
83064     #endif
83065     #ifdef ECANCELED
83066         case ECANCELED: return DRFLAC_CANCELLED;
83067     #endif
83068     #ifdef ENOKEY
83069         case ENOKEY: return DRFLAC_ERROR;
83070     #endif
83071     #ifdef EKEYEXPIRED
83072         case EKEYEXPIRED: return DRFLAC_ERROR;
83073     #endif
83074     #ifdef EKEYREVOKED
83075         case EKEYREVOKED: return DRFLAC_ERROR;
83076     #endif
83077     #ifdef EKEYREJECTED
83078         case EKEYREJECTED: return DRFLAC_ERROR;
83079     #endif
83080     #ifdef EOWNERDEAD
83081         case EOWNERDEAD: return DRFLAC_ERROR;
83082     #endif
83083     #ifdef ENOTRECOVERABLE
83084         case ENOTRECOVERABLE: return DRFLAC_ERROR;
83085     #endif
83086     #ifdef ERFKILL
83087         case ERFKILL: return DRFLAC_ERROR;
83088     #endif
83089     #ifdef EHWPOISON
83090         case EHWPOISON: return DRFLAC_ERROR;
83091     #endif
83092         default: return DRFLAC_ERROR;
83093     }
83094 }
83095 static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
83096 {
83097 #if defined(_MSC_VER) && _MSC_VER >= 1400
83098     errno_t err;
83099 #endif
83100     if (ppFile != NULL) {
83101         *ppFile = NULL;
83102     }
83103     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
83104         return DRFLAC_INVALID_ARGS;
83105     }
83106 #if defined(_MSC_VER) && _MSC_VER >= 1400
83107     err = fopen_s(ppFile, pFilePath, pOpenMode);
83108     if (err != 0) {
83109         return drflac_result_from_errno(err);
83110     }
83111 #else
83112 #if defined(_WIN32) || defined(__APPLE__)
83113     *ppFile = fopen(pFilePath, pOpenMode);
83114 #else
83115     #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
83116         *ppFile = fopen64(pFilePath, pOpenMode);
83117     #else
83118         *ppFile = fopen(pFilePath, pOpenMode);
83119     #endif
83120 #endif
83121     if (*ppFile == NULL) {
83122         drflac_result result = drflac_result_from_errno(errno);
83123         if (result == DRFLAC_SUCCESS) {
83124             result = DRFLAC_ERROR;
83125         }
83126         return result;
83127     }
83128 #endif
83129     return DRFLAC_SUCCESS;
83130 }
83131 #if defined(_WIN32)
83132     #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
83133         #define DRFLAC_HAS_WFOPEN
83134     #endif
83135 #endif
83136 static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks)
83137 {
83138     if (ppFile != NULL) {
83139         *ppFile = NULL;
83140     }
83141     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
83142         return DRFLAC_INVALID_ARGS;
83143     }
83144 #if defined(DRFLAC_HAS_WFOPEN)
83145     {
83146     #if defined(_MSC_VER) && _MSC_VER >= 1400
83147         errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
83148         if (err != 0) {
83149             return drflac_result_from_errno(err);
83150         }
83151     #else
83152         *ppFile = _wfopen(pFilePath, pOpenMode);
83153         if (*ppFile == NULL) {
83154             return drflac_result_from_errno(errno);
83155         }
83156     #endif
83157         (void)pAllocationCallbacks;
83158     }
83159 #else
83160     {
83161         mbstate_t mbs;
83162         size_t lenMB;
83163         const wchar_t* pFilePathTemp = pFilePath;
83164         char* pFilePathMB = NULL;
83165         char pOpenModeMB[32] = {0};
83166         DRFLAC_ZERO_OBJECT(&mbs);
83167         lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
83168         if (lenMB == (size_t)-1) {
83169             return drflac_result_from_errno(errno);
83170         }
83171         pFilePathMB = (char*)drflac__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
83172         if (pFilePathMB == NULL) {
83173             return DRFLAC_OUT_OF_MEMORY;
83174         }
83175         pFilePathTemp = pFilePath;
83176         DRFLAC_ZERO_OBJECT(&mbs);
83177         wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
83178         {
83179             size_t i = 0;
83180             for (;;) {
83181                 if (pOpenMode[i] == 0) {
83182                     pOpenModeMB[i] = '\0';
83183                     break;
83184                 }
83185                 pOpenModeMB[i] = (char)pOpenMode[i];
83186                 i += 1;
83187             }
83188         }
83189         *ppFile = fopen(pFilePathMB, pOpenModeMB);
83190         drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
83191     }
83192     if (*ppFile == NULL) {
83193         return DRFLAC_ERROR;
83194     }
83195 #endif
83196     return DRFLAC_SUCCESS;
83197 }
83198 static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
83199 {
83200     return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
83201 }
83202 static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
83203 {
83204     DRFLAC_ASSERT(offset >= 0);
83205     return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
83206 }
83207 DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
83208 {
83209     drflac* pFlac;
83210     FILE* pFile;
83211     if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
83212         return NULL;
83213     }
83214     pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
83215     if (pFlac == NULL) {
83216         fclose(pFile);
83217         return NULL;
83218     }
83219     return pFlac;
83220 }
83221 DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
83222 {
83223     drflac* pFlac;
83224     FILE* pFile;
83225     if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) {
83226         return NULL;
83227     }
83228     pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
83229     if (pFlac == NULL) {
83230         fclose(pFile);
83231         return NULL;
83232     }
83233     return pFlac;
83234 }
83235 DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
83236 {
83237     drflac* pFlac;
83238     FILE* pFile;
83239     if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
83240         return NULL;
83241     }
83242     pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
83243     if (pFlac == NULL) {
83244         fclose(pFile);
83245         return pFlac;
83246     }
83247     return pFlac;
83248 }
83249 DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
83250 {
83251     drflac* pFlac;
83252     FILE* pFile;
83253     if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) {
83254         return NULL;
83255     }
83256     pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
83257     if (pFlac == NULL) {
83258         fclose(pFile);
83259         return pFlac;
83260     }
83261     return pFlac;
83262 }
83263 #endif
83264 static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead)
83265 {
83266     drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
83267     size_t bytesRemaining;
83268     DRFLAC_ASSERT(memoryStream != NULL);
83269     DRFLAC_ASSERT(memoryStream->dataSize >= memoryStream->currentReadPos);
83270     bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos;
83271     if (bytesToRead > bytesRemaining) {
83272         bytesToRead = bytesRemaining;
83273     }
83274     if (bytesToRead > 0) {
83275         DRFLAC_COPY_MEMORY(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead);
83276         memoryStream->currentReadPos += bytesToRead;
83277     }
83278     return bytesToRead;
83279 }
83280 static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
83281 {
83282     drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
83283     DRFLAC_ASSERT(memoryStream != NULL);
83284     DRFLAC_ASSERT(offset >= 0);
83285     if (offset > (drflac_int64)memoryStream->dataSize) {
83286         return DRFLAC_FALSE;
83287     }
83288     if (origin == drflac_seek_origin_current) {
83289         if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) {
83290             memoryStream->currentReadPos += offset;
83291         } else {
83292             return DRFLAC_FALSE;
83293         }
83294     } else {
83295         if ((drflac_uint32)offset <= memoryStream->dataSize) {
83296             memoryStream->currentReadPos = offset;
83297         } else {
83298             return DRFLAC_FALSE;
83299         }
83300     }
83301     return DRFLAC_TRUE;
83302 }
83303 DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks)
83304 {
83305     drflac__memory_stream memoryStream;
83306     drflac* pFlac;
83307     memoryStream.data = (const drflac_uint8*)pData;
83308     memoryStream.dataSize = dataSize;
83309     memoryStream.currentReadPos = 0;
83310     pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream, pAllocationCallbacks);
83311     if (pFlac == NULL) {
83312         return NULL;
83313     }
83314     pFlac->memoryStream = memoryStream;
83315 #ifndef DR_FLAC_NO_OGG
83316     if (pFlac->container == drflac_container_ogg)
83317     {
83318         drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
83319         oggbs->pUserData = &pFlac->memoryStream;
83320     }
83321     else
83322 #endif
83323     {
83324         pFlac->bs.pUserData = &pFlac->memoryStream;
83325     }
83326     return pFlac;
83327 }
83328 DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
83329 {
83330     drflac__memory_stream memoryStream;
83331     drflac* pFlac;
83332     memoryStream.data = (const drflac_uint8*)pData;
83333     memoryStream.dataSize = dataSize;
83334     memoryStream.currentReadPos = 0;
83335     pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks);
83336     if (pFlac == NULL) {
83337         return NULL;
83338     }
83339     pFlac->memoryStream = memoryStream;
83340 #ifndef DR_FLAC_NO_OGG
83341     if (pFlac->container == drflac_container_ogg)
83342     {
83343         drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
83344         oggbs->pUserData = &pFlac->memoryStream;
83345     }
83346     else
83347 #endif
83348     {
83349         pFlac->bs.pUserData = &pFlac->memoryStream;
83350     }
83351     return pFlac;
83352 }
83353 DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
83354 {
83355     return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
83356 }
83357 DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
83358 {
83359     return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks);
83360 }
83361 DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
83362 {
83363     return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
83364 }
83365 DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
83366 {
83367     return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
83368 }
83369 DRFLAC_API void drflac_close(drflac* pFlac)
83370 {
83371     if (pFlac == NULL) {
83372         return;
83373     }
83374 #ifndef DR_FLAC_NO_STDIO
83375     if (pFlac->bs.onRead == drflac__on_read_stdio) {
83376         fclose((FILE*)pFlac->bs.pUserData);
83377     }
83378 #ifndef DR_FLAC_NO_OGG
83379     if (pFlac->container == drflac_container_ogg) {
83380         drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
83381         DRFLAC_ASSERT(pFlac->bs.onRead == drflac__on_read_ogg);
83382         if (oggbs->onRead == drflac__on_read_stdio) {
83383             fclose((FILE*)oggbs->pUserData);
83384         }
83385     }
83386 #endif
83387 #endif
83388     drflac__free_from_callbacks(pFlac, &pFlac->allocationCallbacks);
83389 }
83390 #if 0
83391 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83392 {
83393     drflac_uint64 i;
83394     for (i = 0; i < frameCount; ++i) {
83395         drflac_uint32 left  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
83396         drflac_uint32 side  = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
83397         drflac_uint32 right = left - side;
83398         pOutputSamples[i*2+0] = (drflac_int32)left;
83399         pOutputSamples[i*2+1] = (drflac_int32)right;
83400     }
83401 }
83402 #endif
83403 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83404 {
83405     drflac_uint64 i;
83406     drflac_uint64 frameCount4 = frameCount >> 2;
83407     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83408     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83409     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83410     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83411     for (i = 0; i < frameCount4; ++i) {
83412         drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
83413         drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
83414         drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
83415         drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
83416         drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
83417         drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
83418         drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
83419         drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
83420         drflac_uint32 right0 = left0 - side0;
83421         drflac_uint32 right1 = left1 - side1;
83422         drflac_uint32 right2 = left2 - side2;
83423         drflac_uint32 right3 = left3 - side3;
83424         pOutputSamples[i*8+0] = (drflac_int32)left0;
83425         pOutputSamples[i*8+1] = (drflac_int32)right0;
83426         pOutputSamples[i*8+2] = (drflac_int32)left1;
83427         pOutputSamples[i*8+3] = (drflac_int32)right1;
83428         pOutputSamples[i*8+4] = (drflac_int32)left2;
83429         pOutputSamples[i*8+5] = (drflac_int32)right2;
83430         pOutputSamples[i*8+6] = (drflac_int32)left3;
83431         pOutputSamples[i*8+7] = (drflac_int32)right3;
83432     }
83433     for (i = (frameCount4 << 2); i < frameCount; ++i) {
83434         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
83435         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
83436         drflac_uint32 right = left - side;
83437         pOutputSamples[i*2+0] = (drflac_int32)left;
83438         pOutputSamples[i*2+1] = (drflac_int32)right;
83439     }
83440 }
83441 #if defined(DRFLAC_SUPPORT_SSE2)
83442 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83443 {
83444     drflac_uint64 i;
83445     drflac_uint64 frameCount4 = frameCount >> 2;
83446     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83447     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83448     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83449     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83450     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
83451     for (i = 0; i < frameCount4; ++i) {
83452         __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
83453         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
83454         __m128i right = _mm_sub_epi32(left, side);
83455         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
83456         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
83457     }
83458     for (i = (frameCount4 << 2); i < frameCount; ++i) {
83459         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
83460         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
83461         drflac_uint32 right = left - side;
83462         pOutputSamples[i*2+0] = (drflac_int32)left;
83463         pOutputSamples[i*2+1] = (drflac_int32)right;
83464     }
83465 }
83466 #endif
83467 #if defined(DRFLAC_SUPPORT_NEON)
83468 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83469 {
83470     drflac_uint64 i;
83471     drflac_uint64 frameCount4 = frameCount >> 2;
83472     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83473     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83474     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83475     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83476     int32x4_t shift0_4;
83477     int32x4_t shift1_4;
83478     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
83479     shift0_4 = vdupq_n_s32(shift0);
83480     shift1_4 = vdupq_n_s32(shift1);
83481     for (i = 0; i < frameCount4; ++i) {
83482         uint32x4_t left;
83483         uint32x4_t side;
83484         uint32x4_t right;
83485         left  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
83486         side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
83487         right = vsubq_u32(left, side);
83488         drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right));
83489     }
83490     for (i = (frameCount4 << 2); i < frameCount; ++i) {
83491         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
83492         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
83493         drflac_uint32 right = left - side;
83494         pOutputSamples[i*2+0] = (drflac_int32)left;
83495         pOutputSamples[i*2+1] = (drflac_int32)right;
83496     }
83497 }
83498 #endif
83499 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83500 {
83501 #if defined(DRFLAC_SUPPORT_SSE2)
83502     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
83503         drflac_read_pcm_frames_s32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83504     } else
83505 #elif defined(DRFLAC_SUPPORT_NEON)
83506     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
83507         drflac_read_pcm_frames_s32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83508     } else
83509 #endif
83510     {
83511 #if 0
83512         drflac_read_pcm_frames_s32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83513 #else
83514         drflac_read_pcm_frames_s32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83515 #endif
83516     }
83517 }
83518 #if 0
83519 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83520 {
83521     drflac_uint64 i;
83522     for (i = 0; i < frameCount; ++i) {
83523         drflac_uint32 side  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
83524         drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
83525         drflac_uint32 left  = right + side;
83526         pOutputSamples[i*2+0] = (drflac_int32)left;
83527         pOutputSamples[i*2+1] = (drflac_int32)right;
83528     }
83529 }
83530 #endif
83531 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83532 {
83533     drflac_uint64 i;
83534     drflac_uint64 frameCount4 = frameCount >> 2;
83535     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83536     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83537     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83538     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83539     for (i = 0; i < frameCount4; ++i) {
83540         drflac_uint32 side0  = pInputSamples0U32[i*4+0] << shift0;
83541         drflac_uint32 side1  = pInputSamples0U32[i*4+1] << shift0;
83542         drflac_uint32 side2  = pInputSamples0U32[i*4+2] << shift0;
83543         drflac_uint32 side3  = pInputSamples0U32[i*4+3] << shift0;
83544         drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
83545         drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
83546         drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
83547         drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
83548         drflac_uint32 left0 = right0 + side0;
83549         drflac_uint32 left1 = right1 + side1;
83550         drflac_uint32 left2 = right2 + side2;
83551         drflac_uint32 left3 = right3 + side3;
83552         pOutputSamples[i*8+0] = (drflac_int32)left0;
83553         pOutputSamples[i*8+1] = (drflac_int32)right0;
83554         pOutputSamples[i*8+2] = (drflac_int32)left1;
83555         pOutputSamples[i*8+3] = (drflac_int32)right1;
83556         pOutputSamples[i*8+4] = (drflac_int32)left2;
83557         pOutputSamples[i*8+5] = (drflac_int32)right2;
83558         pOutputSamples[i*8+6] = (drflac_int32)left3;
83559         pOutputSamples[i*8+7] = (drflac_int32)right3;
83560     }
83561     for (i = (frameCount4 << 2); i < frameCount; ++i) {
83562         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
83563         drflac_uint32 right = pInputSamples1U32[i] << shift1;
83564         drflac_uint32 left  = right + side;
83565         pOutputSamples[i*2+0] = (drflac_int32)left;
83566         pOutputSamples[i*2+1] = (drflac_int32)right;
83567     }
83568 }
83569 #if defined(DRFLAC_SUPPORT_SSE2)
83570 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83571 {
83572     drflac_uint64 i;
83573     drflac_uint64 frameCount4 = frameCount >> 2;
83574     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83575     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83576     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83577     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83578     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
83579     for (i = 0; i < frameCount4; ++i) {
83580         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
83581         __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
83582         __m128i left  = _mm_add_epi32(right, side);
83583         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
83584         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
83585     }
83586     for (i = (frameCount4 << 2); i < frameCount; ++i) {
83587         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
83588         drflac_uint32 right = pInputSamples1U32[i] << shift1;
83589         drflac_uint32 left  = right + side;
83590         pOutputSamples[i*2+0] = (drflac_int32)left;
83591         pOutputSamples[i*2+1] = (drflac_int32)right;
83592     }
83593 }
83594 #endif
83595 #if defined(DRFLAC_SUPPORT_NEON)
83596 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83597 {
83598     drflac_uint64 i;
83599     drflac_uint64 frameCount4 = frameCount >> 2;
83600     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83601     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83602     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83603     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83604     int32x4_t shift0_4;
83605     int32x4_t shift1_4;
83606     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
83607     shift0_4 = vdupq_n_s32(shift0);
83608     shift1_4 = vdupq_n_s32(shift1);
83609     for (i = 0; i < frameCount4; ++i) {
83610         uint32x4_t side;
83611         uint32x4_t right;
83612         uint32x4_t left;
83613         side  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
83614         right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
83615         left  = vaddq_u32(right, side);
83616         drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right));
83617     }
83618     for (i = (frameCount4 << 2); i < frameCount; ++i) {
83619         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
83620         drflac_uint32 right = pInputSamples1U32[i] << shift1;
83621         drflac_uint32 left  = right + side;
83622         pOutputSamples[i*2+0] = (drflac_int32)left;
83623         pOutputSamples[i*2+1] = (drflac_int32)right;
83624     }
83625 }
83626 #endif
83627 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83628 {
83629 #if defined(DRFLAC_SUPPORT_SSE2)
83630     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
83631         drflac_read_pcm_frames_s32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83632     } else
83633 #elif defined(DRFLAC_SUPPORT_NEON)
83634     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
83635         drflac_read_pcm_frames_s32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83636     } else
83637 #endif
83638     {
83639 #if 0
83640         drflac_read_pcm_frames_s32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83641 #else
83642         drflac_read_pcm_frames_s32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83643 #endif
83644     }
83645 }
83646 #if 0
83647 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83648 {
83649     for (drflac_uint64 i = 0; i < frameCount; ++i) {
83650         drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83651         drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83652         mid = (mid << 1) | (side & 0x01);
83653         pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample);
83654         pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample);
83655     }
83656 }
83657 #endif
83658 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83659 {
83660     drflac_uint64 i;
83661     drflac_uint64 frameCount4 = frameCount >> 2;
83662     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83663     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83664     drflac_int32 shift = unusedBitsPerSample;
83665     if (shift > 0) {
83666         shift -= 1;
83667         for (i = 0; i < frameCount4; ++i) {
83668             drflac_uint32 temp0L;
83669             drflac_uint32 temp1L;
83670             drflac_uint32 temp2L;
83671             drflac_uint32 temp3L;
83672             drflac_uint32 temp0R;
83673             drflac_uint32 temp1R;
83674             drflac_uint32 temp2R;
83675             drflac_uint32 temp3R;
83676             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83677             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83678             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83679             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83680             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83681             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83682             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83683             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83684             mid0 = (mid0 << 1) | (side0 & 0x01);
83685             mid1 = (mid1 << 1) | (side1 & 0x01);
83686             mid2 = (mid2 << 1) | (side2 & 0x01);
83687             mid3 = (mid3 << 1) | (side3 & 0x01);
83688             temp0L = (mid0 + side0) << shift;
83689             temp1L = (mid1 + side1) << shift;
83690             temp2L = (mid2 + side2) << shift;
83691             temp3L = (mid3 + side3) << shift;
83692             temp0R = (mid0 - side0) << shift;
83693             temp1R = (mid1 - side1) << shift;
83694             temp2R = (mid2 - side2) << shift;
83695             temp3R = (mid3 - side3) << shift;
83696             pOutputSamples[i*8+0] = (drflac_int32)temp0L;
83697             pOutputSamples[i*8+1] = (drflac_int32)temp0R;
83698             pOutputSamples[i*8+2] = (drflac_int32)temp1L;
83699             pOutputSamples[i*8+3] = (drflac_int32)temp1R;
83700             pOutputSamples[i*8+4] = (drflac_int32)temp2L;
83701             pOutputSamples[i*8+5] = (drflac_int32)temp2R;
83702             pOutputSamples[i*8+6] = (drflac_int32)temp3L;
83703             pOutputSamples[i*8+7] = (drflac_int32)temp3R;
83704         }
83705     } else {
83706         for (i = 0; i < frameCount4; ++i) {
83707             drflac_uint32 temp0L;
83708             drflac_uint32 temp1L;
83709             drflac_uint32 temp2L;
83710             drflac_uint32 temp3L;
83711             drflac_uint32 temp0R;
83712             drflac_uint32 temp1R;
83713             drflac_uint32 temp2R;
83714             drflac_uint32 temp3R;
83715             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83716             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83717             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83718             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83719             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83720             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83721             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83722             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83723             mid0 = (mid0 << 1) | (side0 & 0x01);
83724             mid1 = (mid1 << 1) | (side1 & 0x01);
83725             mid2 = (mid2 << 1) | (side2 & 0x01);
83726             mid3 = (mid3 << 1) | (side3 & 0x01);
83727             temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1);
83728             temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1);
83729             temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1);
83730             temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1);
83731             temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1);
83732             temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1);
83733             temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1);
83734             temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1);
83735             pOutputSamples[i*8+0] = (drflac_int32)temp0L;
83736             pOutputSamples[i*8+1] = (drflac_int32)temp0R;
83737             pOutputSamples[i*8+2] = (drflac_int32)temp1L;
83738             pOutputSamples[i*8+3] = (drflac_int32)temp1R;
83739             pOutputSamples[i*8+4] = (drflac_int32)temp2L;
83740             pOutputSamples[i*8+5] = (drflac_int32)temp2R;
83741             pOutputSamples[i*8+6] = (drflac_int32)temp3L;
83742             pOutputSamples[i*8+7] = (drflac_int32)temp3R;
83743         }
83744     }
83745     for (i = (frameCount4 << 2); i < frameCount; ++i) {
83746         drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83747         drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83748         mid = (mid << 1) | (side & 0x01);
83749         pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample);
83750         pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample);
83751     }
83752 }
83753 #if defined(DRFLAC_SUPPORT_SSE2)
83754 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83755 {
83756     drflac_uint64 i;
83757     drflac_uint64 frameCount4 = frameCount >> 2;
83758     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83759     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83760     drflac_int32 shift = unusedBitsPerSample;
83761     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
83762     if (shift == 0) {
83763         for (i = 0; i < frameCount4; ++i) {
83764             __m128i mid;
83765             __m128i side;
83766             __m128i left;
83767             __m128i right;
83768             mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
83769             side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
83770             mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
83771             left  = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
83772             right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
83773             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
83774             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
83775         }
83776         for (i = (frameCount4 << 2); i < frameCount; ++i) {
83777             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83778             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83779             mid = (mid << 1) | (side & 0x01);
83780             pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1;
83781             pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1;
83782         }
83783     } else {
83784         shift -= 1;
83785         for (i = 0; i < frameCount4; ++i) {
83786             __m128i mid;
83787             __m128i side;
83788             __m128i left;
83789             __m128i right;
83790             mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
83791             side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
83792             mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
83793             left  = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
83794             right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
83795             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
83796             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
83797         }
83798         for (i = (frameCount4 << 2); i < frameCount; ++i) {
83799             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83800             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83801             mid = (mid << 1) | (side & 0x01);
83802             pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift);
83803             pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift);
83804         }
83805     }
83806 }
83807 #endif
83808 #if defined(DRFLAC_SUPPORT_NEON)
83809 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83810 {
83811     drflac_uint64 i;
83812     drflac_uint64 frameCount4 = frameCount >> 2;
83813     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83814     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83815     drflac_int32 shift = unusedBitsPerSample;
83816     int32x4_t  wbpsShift0_4;
83817     int32x4_t  wbpsShift1_4;
83818     uint32x4_t one4;
83819     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
83820     wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
83821     wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
83822     one4         = vdupq_n_u32(1);
83823     if (shift == 0) {
83824         for (i = 0; i < frameCount4; ++i) {
83825             uint32x4_t mid;
83826             uint32x4_t side;
83827             int32x4_t left;
83828             int32x4_t right;
83829             mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
83830             side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
83831             mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4));
83832             left  = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
83833             right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
83834             drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
83835         }
83836         for (i = (frameCount4 << 2); i < frameCount; ++i) {
83837             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83838             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83839             mid = (mid << 1) | (side & 0x01);
83840             pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1;
83841             pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1;
83842         }
83843     } else {
83844         int32x4_t shift4;
83845         shift -= 1;
83846         shift4 = vdupq_n_s32(shift);
83847         for (i = 0; i < frameCount4; ++i) {
83848             uint32x4_t mid;
83849             uint32x4_t side;
83850             int32x4_t left;
83851             int32x4_t right;
83852             mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
83853             side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
83854             mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4));
83855             left  = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
83856             right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
83857             drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
83858         }
83859         for (i = (frameCount4 << 2); i < frameCount; ++i) {
83860             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83861             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83862             mid = (mid << 1) | (side & 0x01);
83863             pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift);
83864             pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift);
83865         }
83866     }
83867 }
83868 #endif
83869 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83870 {
83871 #if defined(DRFLAC_SUPPORT_SSE2)
83872     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
83873         drflac_read_pcm_frames_s32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83874     } else
83875 #elif defined(DRFLAC_SUPPORT_NEON)
83876     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
83877         drflac_read_pcm_frames_s32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83878     } else
83879 #endif
83880     {
83881 #if 0
83882         drflac_read_pcm_frames_s32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83883 #else
83884         drflac_read_pcm_frames_s32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83885 #endif
83886     }
83887 }
83888 #if 0
83889 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83890 {
83891     for (drflac_uint64 i = 0; i < frameCount; ++i) {
83892         pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample));
83893         pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample));
83894     }
83895 }
83896 #endif
83897 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83898 {
83899     drflac_uint64 i;
83900     drflac_uint64 frameCount4 = frameCount >> 2;
83901     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83902     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83903     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83904     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83905     for (i = 0; i < frameCount4; ++i) {
83906         drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
83907         drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
83908         drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
83909         drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
83910         drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
83911         drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
83912         drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
83913         drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
83914         pOutputSamples[i*8+0] = (drflac_int32)tempL0;
83915         pOutputSamples[i*8+1] = (drflac_int32)tempR0;
83916         pOutputSamples[i*8+2] = (drflac_int32)tempL1;
83917         pOutputSamples[i*8+3] = (drflac_int32)tempR1;
83918         pOutputSamples[i*8+4] = (drflac_int32)tempL2;
83919         pOutputSamples[i*8+5] = (drflac_int32)tempR2;
83920         pOutputSamples[i*8+6] = (drflac_int32)tempL3;
83921         pOutputSamples[i*8+7] = (drflac_int32)tempR3;
83922     }
83923     for (i = (frameCount4 << 2); i < frameCount; ++i) {
83924         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
83925         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
83926     }
83927 }
83928 #if defined(DRFLAC_SUPPORT_SSE2)
83929 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83930 {
83931     drflac_uint64 i;
83932     drflac_uint64 frameCount4 = frameCount >> 2;
83933     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83934     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83935     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83936     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83937     for (i = 0; i < frameCount4; ++i) {
83938         __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
83939         __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
83940         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
83941         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
83942     }
83943     for (i = (frameCount4 << 2); i < frameCount; ++i) {
83944         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
83945         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
83946     }
83947 }
83948 #endif
83949 #if defined(DRFLAC_SUPPORT_NEON)
83950 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83951 {
83952     drflac_uint64 i;
83953     drflac_uint64 frameCount4 = frameCount >> 2;
83954     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
83955     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
83956     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
83957     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
83958     int32x4_t shift4_0 = vdupq_n_s32(shift0);
83959     int32x4_t shift4_1 = vdupq_n_s32(shift1);
83960     for (i = 0; i < frameCount4; ++i) {
83961         int32x4_t left;
83962         int32x4_t right;
83963         left  = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift4_0));
83964         right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift4_1));
83965         drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
83966     }
83967     for (i = (frameCount4 << 2); i < frameCount; ++i) {
83968         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
83969         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
83970     }
83971 }
83972 #endif
83973 static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
83974 {
83975 #if defined(DRFLAC_SUPPORT_SSE2)
83976     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
83977         drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83978     } else
83979 #elif defined(DRFLAC_SUPPORT_NEON)
83980     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
83981         drflac_read_pcm_frames_s32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83982     } else
83983 #endif
83984     {
83985 #if 0
83986         drflac_read_pcm_frames_s32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83987 #else
83988         drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
83989 #endif
83990     }
83991 }
83992 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut)
83993 {
83994     drflac_uint64 framesRead;
83995     drflac_uint32 unusedBitsPerSample;
83996     if (pFlac == NULL || framesToRead == 0) {
83997         return 0;
83998     }
83999     if (pBufferOut == NULL) {
84000         return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
84001     }
84002     DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
84003     unusedBitsPerSample = 32 - pFlac->bitsPerSample;
84004     framesRead = 0;
84005     while (framesToRead > 0) {
84006         if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
84007             if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
84008                 break;
84009             }
84010         } else {
84011             unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
84012             drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
84013             drflac_uint64 frameCountThisIteration = framesToRead;
84014             if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
84015                 frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
84016             }
84017             if (channelCount == 2) {
84018                 const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
84019                 const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
84020                 switch (pFlac->currentFLACFrame.header.channelAssignment)
84021                 {
84022                     case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
84023                     {
84024                         drflac_read_pcm_frames_s32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
84025                     } break;
84026                     case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
84027                     {
84028                         drflac_read_pcm_frames_s32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
84029                     } break;
84030                     case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
84031                     {
84032                         drflac_read_pcm_frames_s32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
84033                     } break;
84034                     case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
84035                     default:
84036                     {
84037                         drflac_read_pcm_frames_s32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
84038                     } break;
84039                 }
84040             } else {
84041                 drflac_uint64 i;
84042                 for (i = 0; i < frameCountThisIteration; ++i) {
84043                     unsigned int j;
84044                     for (j = 0; j < channelCount; ++j) {
84045                         pBufferOut[(i*channelCount)+j] = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
84046                     }
84047                 }
84048             }
84049             framesRead                += frameCountThisIteration;
84050             pBufferOut                += frameCountThisIteration * channelCount;
84051             framesToRead              -= frameCountThisIteration;
84052             pFlac->currentPCMFrame    += frameCountThisIteration;
84053             pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration;
84054         }
84055     }
84056     return framesRead;
84057 }
84058 #if 0
84059 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84060 {
84061     drflac_uint64 i;
84062     for (i = 0; i < frameCount; ++i) {
84063         drflac_uint32 left  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
84064         drflac_uint32 side  = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
84065         drflac_uint32 right = left - side;
84066         left  >>= 16;
84067         right >>= 16;
84068         pOutputSamples[i*2+0] = (drflac_int16)left;
84069         pOutputSamples[i*2+1] = (drflac_int16)right;
84070     }
84071 }
84072 #endif
84073 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84074 {
84075     drflac_uint64 i;
84076     drflac_uint64 frameCount4 = frameCount >> 2;
84077     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84078     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84079     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84080     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84081     for (i = 0; i < frameCount4; ++i) {
84082         drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
84083         drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
84084         drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
84085         drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
84086         drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
84087         drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
84088         drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
84089         drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
84090         drflac_uint32 right0 = left0 - side0;
84091         drflac_uint32 right1 = left1 - side1;
84092         drflac_uint32 right2 = left2 - side2;
84093         drflac_uint32 right3 = left3 - side3;
84094         left0  >>= 16;
84095         left1  >>= 16;
84096         left2  >>= 16;
84097         left3  >>= 16;
84098         right0 >>= 16;
84099         right1 >>= 16;
84100         right2 >>= 16;
84101         right3 >>= 16;
84102         pOutputSamples[i*8+0] = (drflac_int16)left0;
84103         pOutputSamples[i*8+1] = (drflac_int16)right0;
84104         pOutputSamples[i*8+2] = (drflac_int16)left1;
84105         pOutputSamples[i*8+3] = (drflac_int16)right1;
84106         pOutputSamples[i*8+4] = (drflac_int16)left2;
84107         pOutputSamples[i*8+5] = (drflac_int16)right2;
84108         pOutputSamples[i*8+6] = (drflac_int16)left3;
84109         pOutputSamples[i*8+7] = (drflac_int16)right3;
84110     }
84111     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84112         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
84113         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
84114         drflac_uint32 right = left - side;
84115         left  >>= 16;
84116         right >>= 16;
84117         pOutputSamples[i*2+0] = (drflac_int16)left;
84118         pOutputSamples[i*2+1] = (drflac_int16)right;
84119     }
84120 }
84121 #if defined(DRFLAC_SUPPORT_SSE2)
84122 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84123 {
84124     drflac_uint64 i;
84125     drflac_uint64 frameCount4 = frameCount >> 2;
84126     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84127     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84128     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84129     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84130     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
84131     for (i = 0; i < frameCount4; ++i) {
84132         __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
84133         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
84134         __m128i right = _mm_sub_epi32(left, side);
84135         left  = _mm_srai_epi32(left,  16);
84136         right = _mm_srai_epi32(right, 16);
84137         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
84138     }
84139     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84140         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
84141         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
84142         drflac_uint32 right = left - side;
84143         left  >>= 16;
84144         right >>= 16;
84145         pOutputSamples[i*2+0] = (drflac_int16)left;
84146         pOutputSamples[i*2+1] = (drflac_int16)right;
84147     }
84148 }
84149 #endif
84150 #if defined(DRFLAC_SUPPORT_NEON)
84151 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84152 {
84153     drflac_uint64 i;
84154     drflac_uint64 frameCount4 = frameCount >> 2;
84155     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84156     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84157     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84158     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84159     int32x4_t shift0_4;
84160     int32x4_t shift1_4;
84161     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
84162     shift0_4 = vdupq_n_s32(shift0);
84163     shift1_4 = vdupq_n_s32(shift1);
84164     for (i = 0; i < frameCount4; ++i) {
84165         uint32x4_t left;
84166         uint32x4_t side;
84167         uint32x4_t right;
84168         left  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
84169         side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
84170         right = vsubq_u32(left, side);
84171         left  = vshrq_n_u32(left,  16);
84172         right = vshrq_n_u32(right, 16);
84173         drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right)));
84174     }
84175     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84176         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
84177         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
84178         drflac_uint32 right = left - side;
84179         left  >>= 16;
84180         right >>= 16;
84181         pOutputSamples[i*2+0] = (drflac_int16)left;
84182         pOutputSamples[i*2+1] = (drflac_int16)right;
84183     }
84184 }
84185 #endif
84186 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84187 {
84188 #if defined(DRFLAC_SUPPORT_SSE2)
84189     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
84190         drflac_read_pcm_frames_s16__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84191     } else
84192 #elif defined(DRFLAC_SUPPORT_NEON)
84193     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
84194         drflac_read_pcm_frames_s16__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84195     } else
84196 #endif
84197     {
84198 #if 0
84199         drflac_read_pcm_frames_s16__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84200 #else
84201         drflac_read_pcm_frames_s16__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84202 #endif
84203     }
84204 }
84205 #if 0
84206 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84207 {
84208     drflac_uint64 i;
84209     for (i = 0; i < frameCount; ++i) {
84210         drflac_uint32 side  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
84211         drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
84212         drflac_uint32 left  = right + side;
84213         left  >>= 16;
84214         right >>= 16;
84215         pOutputSamples[i*2+0] = (drflac_int16)left;
84216         pOutputSamples[i*2+1] = (drflac_int16)right;
84217     }
84218 }
84219 #endif
84220 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84221 {
84222     drflac_uint64 i;
84223     drflac_uint64 frameCount4 = frameCount >> 2;
84224     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84225     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84226     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84227     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84228     for (i = 0; i < frameCount4; ++i) {
84229         drflac_uint32 side0  = pInputSamples0U32[i*4+0] << shift0;
84230         drflac_uint32 side1  = pInputSamples0U32[i*4+1] << shift0;
84231         drflac_uint32 side2  = pInputSamples0U32[i*4+2] << shift0;
84232         drflac_uint32 side3  = pInputSamples0U32[i*4+3] << shift0;
84233         drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
84234         drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
84235         drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
84236         drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
84237         drflac_uint32 left0 = right0 + side0;
84238         drflac_uint32 left1 = right1 + side1;
84239         drflac_uint32 left2 = right2 + side2;
84240         drflac_uint32 left3 = right3 + side3;
84241         left0  >>= 16;
84242         left1  >>= 16;
84243         left2  >>= 16;
84244         left3  >>= 16;
84245         right0 >>= 16;
84246         right1 >>= 16;
84247         right2 >>= 16;
84248         right3 >>= 16;
84249         pOutputSamples[i*8+0] = (drflac_int16)left0;
84250         pOutputSamples[i*8+1] = (drflac_int16)right0;
84251         pOutputSamples[i*8+2] = (drflac_int16)left1;
84252         pOutputSamples[i*8+3] = (drflac_int16)right1;
84253         pOutputSamples[i*8+4] = (drflac_int16)left2;
84254         pOutputSamples[i*8+5] = (drflac_int16)right2;
84255         pOutputSamples[i*8+6] = (drflac_int16)left3;
84256         pOutputSamples[i*8+7] = (drflac_int16)right3;
84257     }
84258     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84259         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
84260         drflac_uint32 right = pInputSamples1U32[i] << shift1;
84261         drflac_uint32 left  = right + side;
84262         left  >>= 16;
84263         right >>= 16;
84264         pOutputSamples[i*2+0] = (drflac_int16)left;
84265         pOutputSamples[i*2+1] = (drflac_int16)right;
84266     }
84267 }
84268 #if defined(DRFLAC_SUPPORT_SSE2)
84269 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84270 {
84271     drflac_uint64 i;
84272     drflac_uint64 frameCount4 = frameCount >> 2;
84273     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84274     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84275     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84276     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84277     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
84278     for (i = 0; i < frameCount4; ++i) {
84279         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
84280         __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
84281         __m128i left  = _mm_add_epi32(right, side);
84282         left  = _mm_srai_epi32(left,  16);
84283         right = _mm_srai_epi32(right, 16);
84284         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
84285     }
84286     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84287         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
84288         drflac_uint32 right = pInputSamples1U32[i] << shift1;
84289         drflac_uint32 left  = right + side;
84290         left  >>= 16;
84291         right >>= 16;
84292         pOutputSamples[i*2+0] = (drflac_int16)left;
84293         pOutputSamples[i*2+1] = (drflac_int16)right;
84294     }
84295 }
84296 #endif
84297 #if defined(DRFLAC_SUPPORT_NEON)
84298 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84299 {
84300     drflac_uint64 i;
84301     drflac_uint64 frameCount4 = frameCount >> 2;
84302     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84303     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84304     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84305     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84306     int32x4_t shift0_4;
84307     int32x4_t shift1_4;
84308     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
84309     shift0_4 = vdupq_n_s32(shift0);
84310     shift1_4 = vdupq_n_s32(shift1);
84311     for (i = 0; i < frameCount4; ++i) {
84312         uint32x4_t side;
84313         uint32x4_t right;
84314         uint32x4_t left;
84315         side  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
84316         right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
84317         left  = vaddq_u32(right, side);
84318         left  = vshrq_n_u32(left,  16);
84319         right = vshrq_n_u32(right, 16);
84320         drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right)));
84321     }
84322     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84323         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
84324         drflac_uint32 right = pInputSamples1U32[i] << shift1;
84325         drflac_uint32 left  = right + side;
84326         left  >>= 16;
84327         right >>= 16;
84328         pOutputSamples[i*2+0] = (drflac_int16)left;
84329         pOutputSamples[i*2+1] = (drflac_int16)right;
84330     }
84331 }
84332 #endif
84333 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84334 {
84335 #if defined(DRFLAC_SUPPORT_SSE2)
84336     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
84337         drflac_read_pcm_frames_s16__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84338     } else
84339 #elif defined(DRFLAC_SUPPORT_NEON)
84340     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
84341         drflac_read_pcm_frames_s16__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84342     } else
84343 #endif
84344     {
84345 #if 0
84346         drflac_read_pcm_frames_s16__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84347 #else
84348         drflac_read_pcm_frames_s16__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84349 #endif
84350     }
84351 }
84352 #if 0
84353 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84354 {
84355     for (drflac_uint64 i = 0; i < frameCount; ++i) {
84356         drflac_uint32 mid  = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84357         drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84358         mid = (mid << 1) | (side & 0x01);
84359         pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16);
84360         pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16);
84361     }
84362 }
84363 #endif
84364 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84365 {
84366     drflac_uint64 i;
84367     drflac_uint64 frameCount4 = frameCount >> 2;
84368     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84369     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84370     drflac_uint32 shift = unusedBitsPerSample;
84371     if (shift > 0) {
84372         shift -= 1;
84373         for (i = 0; i < frameCount4; ++i) {
84374             drflac_uint32 temp0L;
84375             drflac_uint32 temp1L;
84376             drflac_uint32 temp2L;
84377             drflac_uint32 temp3L;
84378             drflac_uint32 temp0R;
84379             drflac_uint32 temp1R;
84380             drflac_uint32 temp2R;
84381             drflac_uint32 temp3R;
84382             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84383             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84384             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84385             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84386             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84387             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84388             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84389             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84390             mid0 = (mid0 << 1) | (side0 & 0x01);
84391             mid1 = (mid1 << 1) | (side1 & 0x01);
84392             mid2 = (mid2 << 1) | (side2 & 0x01);
84393             mid3 = (mid3 << 1) | (side3 & 0x01);
84394             temp0L = (mid0 + side0) << shift;
84395             temp1L = (mid1 + side1) << shift;
84396             temp2L = (mid2 + side2) << shift;
84397             temp3L = (mid3 + side3) << shift;
84398             temp0R = (mid0 - side0) << shift;
84399             temp1R = (mid1 - side1) << shift;
84400             temp2R = (mid2 - side2) << shift;
84401             temp3R = (mid3 - side3) << shift;
84402             temp0L >>= 16;
84403             temp1L >>= 16;
84404             temp2L >>= 16;
84405             temp3L >>= 16;
84406             temp0R >>= 16;
84407             temp1R >>= 16;
84408             temp2R >>= 16;
84409             temp3R >>= 16;
84410             pOutputSamples[i*8+0] = (drflac_int16)temp0L;
84411             pOutputSamples[i*8+1] = (drflac_int16)temp0R;
84412             pOutputSamples[i*8+2] = (drflac_int16)temp1L;
84413             pOutputSamples[i*8+3] = (drflac_int16)temp1R;
84414             pOutputSamples[i*8+4] = (drflac_int16)temp2L;
84415             pOutputSamples[i*8+5] = (drflac_int16)temp2R;
84416             pOutputSamples[i*8+6] = (drflac_int16)temp3L;
84417             pOutputSamples[i*8+7] = (drflac_int16)temp3R;
84418         }
84419     } else {
84420         for (i = 0; i < frameCount4; ++i) {
84421             drflac_uint32 temp0L;
84422             drflac_uint32 temp1L;
84423             drflac_uint32 temp2L;
84424             drflac_uint32 temp3L;
84425             drflac_uint32 temp0R;
84426             drflac_uint32 temp1R;
84427             drflac_uint32 temp2R;
84428             drflac_uint32 temp3R;
84429             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84430             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84431             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84432             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84433             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84434             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84435             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84436             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84437             mid0 = (mid0 << 1) | (side0 & 0x01);
84438             mid1 = (mid1 << 1) | (side1 & 0x01);
84439             mid2 = (mid2 << 1) | (side2 & 0x01);
84440             mid3 = (mid3 << 1) | (side3 & 0x01);
84441             temp0L = ((drflac_int32)(mid0 + side0) >> 1);
84442             temp1L = ((drflac_int32)(mid1 + side1) >> 1);
84443             temp2L = ((drflac_int32)(mid2 + side2) >> 1);
84444             temp3L = ((drflac_int32)(mid3 + side3) >> 1);
84445             temp0R = ((drflac_int32)(mid0 - side0) >> 1);
84446             temp1R = ((drflac_int32)(mid1 - side1) >> 1);
84447             temp2R = ((drflac_int32)(mid2 - side2) >> 1);
84448             temp3R = ((drflac_int32)(mid3 - side3) >> 1);
84449             temp0L >>= 16;
84450             temp1L >>= 16;
84451             temp2L >>= 16;
84452             temp3L >>= 16;
84453             temp0R >>= 16;
84454             temp1R >>= 16;
84455             temp2R >>= 16;
84456             temp3R >>= 16;
84457             pOutputSamples[i*8+0] = (drflac_int16)temp0L;
84458             pOutputSamples[i*8+1] = (drflac_int16)temp0R;
84459             pOutputSamples[i*8+2] = (drflac_int16)temp1L;
84460             pOutputSamples[i*8+3] = (drflac_int16)temp1R;
84461             pOutputSamples[i*8+4] = (drflac_int16)temp2L;
84462             pOutputSamples[i*8+5] = (drflac_int16)temp2R;
84463             pOutputSamples[i*8+6] = (drflac_int16)temp3L;
84464             pOutputSamples[i*8+7] = (drflac_int16)temp3R;
84465         }
84466     }
84467     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84468         drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84469         drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84470         mid = (mid << 1) | (side & 0x01);
84471         pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16);
84472         pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16);
84473     }
84474 }
84475 #if defined(DRFLAC_SUPPORT_SSE2)
84476 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84477 {
84478     drflac_uint64 i;
84479     drflac_uint64 frameCount4 = frameCount >> 2;
84480     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84481     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84482     drflac_uint32 shift = unusedBitsPerSample;
84483     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
84484     if (shift == 0) {
84485         for (i = 0; i < frameCount4; ++i) {
84486             __m128i mid;
84487             __m128i side;
84488             __m128i left;
84489             __m128i right;
84490             mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
84491             side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
84492             mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
84493             left  = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
84494             right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
84495             left  = _mm_srai_epi32(left,  16);
84496             right = _mm_srai_epi32(right, 16);
84497             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
84498         }
84499         for (i = (frameCount4 << 2); i < frameCount; ++i) {
84500             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84501             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84502             mid = (mid << 1) | (side & 0x01);
84503             pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16);
84504             pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16);
84505         }
84506     } else {
84507         shift -= 1;
84508         for (i = 0; i < frameCount4; ++i) {
84509             __m128i mid;
84510             __m128i side;
84511             __m128i left;
84512             __m128i right;
84513             mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
84514             side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
84515             mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
84516             left  = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
84517             right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
84518             left  = _mm_srai_epi32(left,  16);
84519             right = _mm_srai_epi32(right, 16);
84520             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
84521         }
84522         for (i = (frameCount4 << 2); i < frameCount; ++i) {
84523             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84524             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84525             mid = (mid << 1) | (side & 0x01);
84526             pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16);
84527             pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16);
84528         }
84529     }
84530 }
84531 #endif
84532 #if defined(DRFLAC_SUPPORT_NEON)
84533 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84534 {
84535     drflac_uint64 i;
84536     drflac_uint64 frameCount4 = frameCount >> 2;
84537     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84538     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84539     drflac_uint32 shift = unusedBitsPerSample;
84540     int32x4_t wbpsShift0_4;
84541     int32x4_t wbpsShift1_4;
84542     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
84543     wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
84544     wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
84545     if (shift == 0) {
84546         for (i = 0; i < frameCount4; ++i) {
84547             uint32x4_t mid;
84548             uint32x4_t side;
84549             int32x4_t left;
84550             int32x4_t right;
84551             mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
84552             side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
84553             mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
84554             left  = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
84555             right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
84556             left  = vshrq_n_s32(left,  16);
84557             right = vshrq_n_s32(right, 16);
84558             drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
84559         }
84560         for (i = (frameCount4 << 2); i < frameCount; ++i) {
84561             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84562             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84563             mid = (mid << 1) | (side & 0x01);
84564             pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16);
84565             pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16);
84566         }
84567     } else {
84568         int32x4_t shift4;
84569         shift -= 1;
84570         shift4 = vdupq_n_s32(shift);
84571         for (i = 0; i < frameCount4; ++i) {
84572             uint32x4_t mid;
84573             uint32x4_t side;
84574             int32x4_t left;
84575             int32x4_t right;
84576             mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
84577             side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
84578             mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
84579             left  = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
84580             right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
84581             left  = vshrq_n_s32(left,  16);
84582             right = vshrq_n_s32(right, 16);
84583             drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
84584         }
84585         for (i = (frameCount4 << 2); i < frameCount; ++i) {
84586             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84587             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84588             mid = (mid << 1) | (side & 0x01);
84589             pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16);
84590             pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16);
84591         }
84592     }
84593 }
84594 #endif
84595 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84596 {
84597 #if defined(DRFLAC_SUPPORT_SSE2)
84598     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
84599         drflac_read_pcm_frames_s16__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84600     } else
84601 #elif defined(DRFLAC_SUPPORT_NEON)
84602     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
84603         drflac_read_pcm_frames_s16__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84604     } else
84605 #endif
84606     {
84607 #if 0
84608         drflac_read_pcm_frames_s16__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84609 #else
84610         drflac_read_pcm_frames_s16__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84611 #endif
84612     }
84613 }
84614 #if 0
84615 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84616 {
84617     for (drflac_uint64 i = 0; i < frameCount; ++i) {
84618         pOutputSamples[i*2+0] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) >> 16);
84619         pOutputSamples[i*2+1] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) >> 16);
84620     }
84621 }
84622 #endif
84623 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84624 {
84625     drflac_uint64 i;
84626     drflac_uint64 frameCount4 = frameCount >> 2;
84627     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84628     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84629     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84630     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84631     for (i = 0; i < frameCount4; ++i) {
84632         drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
84633         drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
84634         drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
84635         drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
84636         drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
84637         drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
84638         drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
84639         drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
84640         tempL0 >>= 16;
84641         tempL1 >>= 16;
84642         tempL2 >>= 16;
84643         tempL3 >>= 16;
84644         tempR0 >>= 16;
84645         tempR1 >>= 16;
84646         tempR2 >>= 16;
84647         tempR3 >>= 16;
84648         pOutputSamples[i*8+0] = (drflac_int16)tempL0;
84649         pOutputSamples[i*8+1] = (drflac_int16)tempR0;
84650         pOutputSamples[i*8+2] = (drflac_int16)tempL1;
84651         pOutputSamples[i*8+3] = (drflac_int16)tempR1;
84652         pOutputSamples[i*8+4] = (drflac_int16)tempL2;
84653         pOutputSamples[i*8+5] = (drflac_int16)tempR2;
84654         pOutputSamples[i*8+6] = (drflac_int16)tempL3;
84655         pOutputSamples[i*8+7] = (drflac_int16)tempR3;
84656     }
84657     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84658         pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
84659         pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
84660     }
84661 }
84662 #if defined(DRFLAC_SUPPORT_SSE2)
84663 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84664 {
84665     drflac_uint64 i;
84666     drflac_uint64 frameCount4 = frameCount >> 2;
84667     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84668     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84669     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84670     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84671     for (i = 0; i < frameCount4; ++i) {
84672         __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
84673         __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
84674         left  = _mm_srai_epi32(left,  16);
84675         right = _mm_srai_epi32(right, 16);
84676         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
84677     }
84678     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84679         pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
84680         pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
84681     }
84682 }
84683 #endif
84684 #if defined(DRFLAC_SUPPORT_NEON)
84685 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84686 {
84687     drflac_uint64 i;
84688     drflac_uint64 frameCount4 = frameCount >> 2;
84689     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84690     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84691     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84692     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84693     int32x4_t shift0_4 = vdupq_n_s32(shift0);
84694     int32x4_t shift1_4 = vdupq_n_s32(shift1);
84695     for (i = 0; i < frameCount4; ++i) {
84696         int32x4_t left;
84697         int32x4_t right;
84698         left  = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4));
84699         right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4));
84700         left  = vshrq_n_s32(left,  16);
84701         right = vshrq_n_s32(right, 16);
84702         drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
84703     }
84704     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84705         pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
84706         pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
84707     }
84708 }
84709 #endif
84710 static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
84711 {
84712 #if defined(DRFLAC_SUPPORT_SSE2)
84713     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
84714         drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84715     } else
84716 #elif defined(DRFLAC_SUPPORT_NEON)
84717     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
84718         drflac_read_pcm_frames_s16__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84719     } else
84720 #endif
84721     {
84722 #if 0
84723         drflac_read_pcm_frames_s16__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84724 #else
84725         drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84726 #endif
84727     }
84728 }
84729 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut)
84730 {
84731     drflac_uint64 framesRead;
84732     drflac_uint32 unusedBitsPerSample;
84733     if (pFlac == NULL || framesToRead == 0) {
84734         return 0;
84735     }
84736     if (pBufferOut == NULL) {
84737         return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
84738     }
84739     DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
84740     unusedBitsPerSample = 32 - pFlac->bitsPerSample;
84741     framesRead = 0;
84742     while (framesToRead > 0) {
84743         if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
84744             if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
84745                 break;
84746             }
84747         } else {
84748             unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
84749             drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
84750             drflac_uint64 frameCountThisIteration = framesToRead;
84751             if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
84752                 frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
84753             }
84754             if (channelCount == 2) {
84755                 const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
84756                 const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
84757                 switch (pFlac->currentFLACFrame.header.channelAssignment)
84758                 {
84759                     case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
84760                     {
84761                         drflac_read_pcm_frames_s16__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
84762                     } break;
84763                     case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
84764                     {
84765                         drflac_read_pcm_frames_s16__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
84766                     } break;
84767                     case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
84768                     {
84769                         drflac_read_pcm_frames_s16__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
84770                     } break;
84771                     case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
84772                     default:
84773                     {
84774                         drflac_read_pcm_frames_s16__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
84775                     } break;
84776                 }
84777             } else {
84778                 drflac_uint64 i;
84779                 for (i = 0; i < frameCountThisIteration; ++i) {
84780                     unsigned int j;
84781                     for (j = 0; j < channelCount; ++j) {
84782                         drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
84783                         pBufferOut[(i*channelCount)+j] = (drflac_int16)(sampleS32 >> 16);
84784                     }
84785                 }
84786             }
84787             framesRead                += frameCountThisIteration;
84788             pBufferOut                += frameCountThisIteration * channelCount;
84789             framesToRead              -= frameCountThisIteration;
84790             pFlac->currentPCMFrame    += frameCountThisIteration;
84791             pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration;
84792         }
84793     }
84794     return framesRead;
84795 }
84796 #if 0
84797 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
84798 {
84799     drflac_uint64 i;
84800     for (i = 0; i < frameCount; ++i) {
84801         drflac_uint32 left  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
84802         drflac_uint32 side  = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
84803         drflac_uint32 right = left - side;
84804         pOutputSamples[i*2+0] = (float)((drflac_int32)left  / 2147483648.0);
84805         pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0);
84806     }
84807 }
84808 #endif
84809 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
84810 {
84811     drflac_uint64 i;
84812     drflac_uint64 frameCount4 = frameCount >> 2;
84813     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84814     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84815     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84816     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84817     float factor = 1 / 2147483648.0;
84818     for (i = 0; i < frameCount4; ++i) {
84819         drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
84820         drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
84821         drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
84822         drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
84823         drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
84824         drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
84825         drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
84826         drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
84827         drflac_uint32 right0 = left0 - side0;
84828         drflac_uint32 right1 = left1 - side1;
84829         drflac_uint32 right2 = left2 - side2;
84830         drflac_uint32 right3 = left3 - side3;
84831         pOutputSamples[i*8+0] = (drflac_int32)left0  * factor;
84832         pOutputSamples[i*8+1] = (drflac_int32)right0 * factor;
84833         pOutputSamples[i*8+2] = (drflac_int32)left1  * factor;
84834         pOutputSamples[i*8+3] = (drflac_int32)right1 * factor;
84835         pOutputSamples[i*8+4] = (drflac_int32)left2  * factor;
84836         pOutputSamples[i*8+5] = (drflac_int32)right2 * factor;
84837         pOutputSamples[i*8+6] = (drflac_int32)left3  * factor;
84838         pOutputSamples[i*8+7] = (drflac_int32)right3 * factor;
84839     }
84840     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84841         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
84842         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
84843         drflac_uint32 right = left - side;
84844         pOutputSamples[i*2+0] = (drflac_int32)left  * factor;
84845         pOutputSamples[i*2+1] = (drflac_int32)right * factor;
84846     }
84847 }
84848 #if defined(DRFLAC_SUPPORT_SSE2)
84849 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
84850 {
84851     drflac_uint64 i;
84852     drflac_uint64 frameCount4 = frameCount >> 2;
84853     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84854     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84855     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
84856     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
84857     __m128 factor;
84858     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
84859     factor = _mm_set1_ps(1.0f / 8388608.0f);
84860     for (i = 0; i < frameCount4; ++i) {
84861         __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
84862         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
84863         __m128i right = _mm_sub_epi32(left, side);
84864         __m128 leftf  = _mm_mul_ps(_mm_cvtepi32_ps(left),  factor);
84865         __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor);
84866         _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
84867         _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
84868     }
84869     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84870         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
84871         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
84872         drflac_uint32 right = left - side;
84873         pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
84874         pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
84875     }
84876 }
84877 #endif
84878 #if defined(DRFLAC_SUPPORT_NEON)
84879 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
84880 {
84881     drflac_uint64 i;
84882     drflac_uint64 frameCount4 = frameCount >> 2;
84883     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84884     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84885     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
84886     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
84887     float32x4_t factor4;
84888     int32x4_t shift0_4;
84889     int32x4_t shift1_4;
84890     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
84891     factor4  = vdupq_n_f32(1.0f / 8388608.0f);
84892     shift0_4 = vdupq_n_s32(shift0);
84893     shift1_4 = vdupq_n_s32(shift1);
84894     for (i = 0; i < frameCount4; ++i) {
84895         uint32x4_t left;
84896         uint32x4_t side;
84897         uint32x4_t right;
84898         float32x4_t leftf;
84899         float32x4_t rightf;
84900         left   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
84901         side   = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
84902         right  = vsubq_u32(left, side);
84903         leftf  = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)),  factor4);
84904         rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4);
84905         drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
84906     }
84907     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84908         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
84909         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
84910         drflac_uint32 right = left - side;
84911         pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
84912         pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
84913     }
84914 }
84915 #endif
84916 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
84917 {
84918 #if defined(DRFLAC_SUPPORT_SSE2)
84919     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
84920         drflac_read_pcm_frames_f32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84921     } else
84922 #elif defined(DRFLAC_SUPPORT_NEON)
84923     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
84924         drflac_read_pcm_frames_f32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84925     } else
84926 #endif
84927     {
84928 #if 0
84929         drflac_read_pcm_frames_f32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84930 #else
84931         drflac_read_pcm_frames_f32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
84932 #endif
84933     }
84934 }
84935 #if 0
84936 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
84937 {
84938     drflac_uint64 i;
84939     for (i = 0; i < frameCount; ++i) {
84940         drflac_uint32 side  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
84941         drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
84942         drflac_uint32 left  = right + side;
84943         pOutputSamples[i*2+0] = (float)((drflac_int32)left  / 2147483648.0);
84944         pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0);
84945     }
84946 }
84947 #endif
84948 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
84949 {
84950     drflac_uint64 i;
84951     drflac_uint64 frameCount4 = frameCount >> 2;
84952     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84953     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84954     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
84955     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
84956     float factor = 1 / 2147483648.0;
84957     for (i = 0; i < frameCount4; ++i) {
84958         drflac_uint32 side0  = pInputSamples0U32[i*4+0] << shift0;
84959         drflac_uint32 side1  = pInputSamples0U32[i*4+1] << shift0;
84960         drflac_uint32 side2  = pInputSamples0U32[i*4+2] << shift0;
84961         drflac_uint32 side3  = pInputSamples0U32[i*4+3] << shift0;
84962         drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
84963         drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
84964         drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
84965         drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
84966         drflac_uint32 left0 = right0 + side0;
84967         drflac_uint32 left1 = right1 + side1;
84968         drflac_uint32 left2 = right2 + side2;
84969         drflac_uint32 left3 = right3 + side3;
84970         pOutputSamples[i*8+0] = (drflac_int32)left0  * factor;
84971         pOutputSamples[i*8+1] = (drflac_int32)right0 * factor;
84972         pOutputSamples[i*8+2] = (drflac_int32)left1  * factor;
84973         pOutputSamples[i*8+3] = (drflac_int32)right1 * factor;
84974         pOutputSamples[i*8+4] = (drflac_int32)left2  * factor;
84975         pOutputSamples[i*8+5] = (drflac_int32)right2 * factor;
84976         pOutputSamples[i*8+6] = (drflac_int32)left3  * factor;
84977         pOutputSamples[i*8+7] = (drflac_int32)right3 * factor;
84978     }
84979     for (i = (frameCount4 << 2); i < frameCount; ++i) {
84980         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
84981         drflac_uint32 right = pInputSamples1U32[i] << shift1;
84982         drflac_uint32 left  = right + side;
84983         pOutputSamples[i*2+0] = (drflac_int32)left  * factor;
84984         pOutputSamples[i*2+1] = (drflac_int32)right * factor;
84985     }
84986 }
84987 #if defined(DRFLAC_SUPPORT_SSE2)
84988 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
84989 {
84990     drflac_uint64 i;
84991     drflac_uint64 frameCount4 = frameCount >> 2;
84992     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
84993     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
84994     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
84995     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
84996     __m128 factor;
84997     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
84998     factor = _mm_set1_ps(1.0f / 8388608.0f);
84999     for (i = 0; i < frameCount4; ++i) {
85000         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
85001         __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
85002         __m128i left  = _mm_add_epi32(right, side);
85003         __m128 leftf  = _mm_mul_ps(_mm_cvtepi32_ps(left),  factor);
85004         __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor);
85005         _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
85006         _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
85007     }
85008     for (i = (frameCount4 << 2); i < frameCount; ++i) {
85009         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
85010         drflac_uint32 right = pInputSamples1U32[i] << shift1;
85011         drflac_uint32 left  = right + side;
85012         pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
85013         pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
85014     }
85015 }
85016 #endif
85017 #if defined(DRFLAC_SUPPORT_NEON)
85018 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85019 {
85020     drflac_uint64 i;
85021     drflac_uint64 frameCount4 = frameCount >> 2;
85022     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
85023     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
85024     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
85025     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
85026     float32x4_t factor4;
85027     int32x4_t shift0_4;
85028     int32x4_t shift1_4;
85029     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
85030     factor4  = vdupq_n_f32(1.0f / 8388608.0f);
85031     shift0_4 = vdupq_n_s32(shift0);
85032     shift1_4 = vdupq_n_s32(shift1);
85033     for (i = 0; i < frameCount4; ++i) {
85034         uint32x4_t side;
85035         uint32x4_t right;
85036         uint32x4_t left;
85037         float32x4_t leftf;
85038         float32x4_t rightf;
85039         side   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
85040         right  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
85041         left   = vaddq_u32(right, side);
85042         leftf  = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)),  factor4);
85043         rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4);
85044         drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
85045     }
85046     for (i = (frameCount4 << 2); i < frameCount; ++i) {
85047         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
85048         drflac_uint32 right = pInputSamples1U32[i] << shift1;
85049         drflac_uint32 left  = right + side;
85050         pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
85051         pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
85052     }
85053 }
85054 #endif
85055 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85056 {
85057 #if defined(DRFLAC_SUPPORT_SSE2)
85058     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
85059         drflac_read_pcm_frames_f32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85060     } else
85061 #elif defined(DRFLAC_SUPPORT_NEON)
85062     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
85063         drflac_read_pcm_frames_f32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85064     } else
85065 #endif
85066     {
85067 #if 0
85068         drflac_read_pcm_frames_f32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85069 #else
85070         drflac_read_pcm_frames_f32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85071 #endif
85072     }
85073 }
85074 #if 0
85075 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85076 {
85077     for (drflac_uint64 i = 0; i < frameCount; ++i) {
85078         drflac_uint32 mid  = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85079         drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85080         mid = (mid << 1) | (side & 0x01);
85081         pOutputSamples[i*2+0] = (float)((((drflac_int32)(mid + side) >> 1) << (unusedBitsPerSample)) / 2147483648.0);
85082         pOutputSamples[i*2+1] = (float)((((drflac_int32)(mid - side) >> 1) << (unusedBitsPerSample)) / 2147483648.0);
85083     }
85084 }
85085 #endif
85086 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85087 {
85088     drflac_uint64 i;
85089     drflac_uint64 frameCount4 = frameCount >> 2;
85090     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
85091     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
85092     drflac_uint32 shift = unusedBitsPerSample;
85093     float factor = 1 / 2147483648.0;
85094     if (shift > 0) {
85095         shift -= 1;
85096         for (i = 0; i < frameCount4; ++i) {
85097             drflac_uint32 temp0L;
85098             drflac_uint32 temp1L;
85099             drflac_uint32 temp2L;
85100             drflac_uint32 temp3L;
85101             drflac_uint32 temp0R;
85102             drflac_uint32 temp1R;
85103             drflac_uint32 temp2R;
85104             drflac_uint32 temp3R;
85105             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85106             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85107             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85108             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85109             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85110             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85111             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85112             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85113             mid0 = (mid0 << 1) | (side0 & 0x01);
85114             mid1 = (mid1 << 1) | (side1 & 0x01);
85115             mid2 = (mid2 << 1) | (side2 & 0x01);
85116             mid3 = (mid3 << 1) | (side3 & 0x01);
85117             temp0L = (mid0 + side0) << shift;
85118             temp1L = (mid1 + side1) << shift;
85119             temp2L = (mid2 + side2) << shift;
85120             temp3L = (mid3 + side3) << shift;
85121             temp0R = (mid0 - side0) << shift;
85122             temp1R = (mid1 - side1) << shift;
85123             temp2R = (mid2 - side2) << shift;
85124             temp3R = (mid3 - side3) << shift;
85125             pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor;
85126             pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor;
85127             pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor;
85128             pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor;
85129             pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor;
85130             pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor;
85131             pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor;
85132             pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor;
85133         }
85134     } else {
85135         for (i = 0; i < frameCount4; ++i) {
85136             drflac_uint32 temp0L;
85137             drflac_uint32 temp1L;
85138             drflac_uint32 temp2L;
85139             drflac_uint32 temp3L;
85140             drflac_uint32 temp0R;
85141             drflac_uint32 temp1R;
85142             drflac_uint32 temp2R;
85143             drflac_uint32 temp3R;
85144             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85145             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85146             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85147             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85148             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85149             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85150             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85151             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85152             mid0 = (mid0 << 1) | (side0 & 0x01);
85153             mid1 = (mid1 << 1) | (side1 & 0x01);
85154             mid2 = (mid2 << 1) | (side2 & 0x01);
85155             mid3 = (mid3 << 1) | (side3 & 0x01);
85156             temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1);
85157             temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1);
85158             temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1);
85159             temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1);
85160             temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1);
85161             temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1);
85162             temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1);
85163             temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1);
85164             pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor;
85165             pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor;
85166             pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor;
85167             pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor;
85168             pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor;
85169             pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor;
85170             pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor;
85171             pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor;
85172         }
85173     }
85174     for (i = (frameCount4 << 2); i < frameCount; ++i) {
85175         drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85176         drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85177         mid = (mid << 1) | (side & 0x01);
85178         pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) * factor;
85179         pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) * factor;
85180     }
85181 }
85182 #if defined(DRFLAC_SUPPORT_SSE2)
85183 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85184 {
85185     drflac_uint64 i;
85186     drflac_uint64 frameCount4 = frameCount >> 2;
85187     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
85188     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
85189     drflac_uint32 shift = unusedBitsPerSample - 8;
85190     float factor;
85191     __m128 factor128;
85192     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
85193     factor = 1.0f / 8388608.0f;
85194     factor128 = _mm_set1_ps(factor);
85195     if (shift == 0) {
85196         for (i = 0; i < frameCount4; ++i) {
85197             __m128i mid;
85198             __m128i side;
85199             __m128i tempL;
85200             __m128i tempR;
85201             __m128  leftf;
85202             __m128  rightf;
85203             mid    = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
85204             side   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
85205             mid    = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
85206             tempL  = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
85207             tempR  = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
85208             leftf  = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128);
85209             rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128);
85210             _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
85211             _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
85212         }
85213         for (i = (frameCount4 << 2); i < frameCount; ++i) {
85214             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85215             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85216             mid = (mid << 1) | (side & 0x01);
85217             pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor;
85218             pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor;
85219         }
85220     } else {
85221         shift -= 1;
85222         for (i = 0; i < frameCount4; ++i) {
85223             __m128i mid;
85224             __m128i side;
85225             __m128i tempL;
85226             __m128i tempR;
85227             __m128 leftf;
85228             __m128 rightf;
85229             mid    = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
85230             side   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
85231             mid    = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
85232             tempL  = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
85233             tempR  = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
85234             leftf  = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128);
85235             rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128);
85236             _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
85237             _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
85238         }
85239         for (i = (frameCount4 << 2); i < frameCount; ++i) {
85240             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85241             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85242             mid = (mid << 1) | (side & 0x01);
85243             pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor;
85244             pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor;
85245         }
85246     }
85247 }
85248 #endif
85249 #if defined(DRFLAC_SUPPORT_NEON)
85250 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85251 {
85252     drflac_uint64 i;
85253     drflac_uint64 frameCount4 = frameCount >> 2;
85254     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
85255     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
85256     drflac_uint32 shift = unusedBitsPerSample - 8;
85257     float factor;
85258     float32x4_t factor4;
85259     int32x4_t shift4;
85260     int32x4_t wbps0_4;
85261     int32x4_t wbps1_4;
85262     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
85263     factor  = 1.0f / 8388608.0f;
85264     factor4 = vdupq_n_f32(factor);
85265     wbps0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
85266     wbps1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
85267     if (shift == 0) {
85268         for (i = 0; i < frameCount4; ++i) {
85269             int32x4_t lefti;
85270             int32x4_t righti;
85271             float32x4_t leftf;
85272             float32x4_t rightf;
85273             uint32x4_t mid  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4);
85274             uint32x4_t side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4);
85275             mid    = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
85276             lefti  = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
85277             righti = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
85278             leftf  = vmulq_f32(vcvtq_f32_s32(lefti),  factor4);
85279             rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
85280             drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
85281         }
85282         for (i = (frameCount4 << 2); i < frameCount; ++i) {
85283             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85284             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85285             mid = (mid << 1) | (side & 0x01);
85286             pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor;
85287             pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor;
85288         }
85289     } else {
85290         shift -= 1;
85291         shift4 = vdupq_n_s32(shift);
85292         for (i = 0; i < frameCount4; ++i) {
85293             uint32x4_t mid;
85294             uint32x4_t side;
85295             int32x4_t lefti;
85296             int32x4_t righti;
85297             float32x4_t leftf;
85298             float32x4_t rightf;
85299             mid    = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4);
85300             side   = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4);
85301             mid    = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
85302             lefti  = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
85303             righti = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
85304             leftf  = vmulq_f32(vcvtq_f32_s32(lefti),  factor4);
85305             rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
85306             drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
85307         }
85308         for (i = (frameCount4 << 2); i < frameCount; ++i) {
85309             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85310             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85311             mid = (mid << 1) | (side & 0x01);
85312             pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor;
85313             pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor;
85314         }
85315     }
85316 }
85317 #endif
85318 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85319 {
85320 #if defined(DRFLAC_SUPPORT_SSE2)
85321     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
85322         drflac_read_pcm_frames_f32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85323     } else
85324 #elif defined(DRFLAC_SUPPORT_NEON)
85325     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
85326         drflac_read_pcm_frames_f32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85327     } else
85328 #endif
85329     {
85330 #if 0
85331         drflac_read_pcm_frames_f32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85332 #else
85333         drflac_read_pcm_frames_f32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85334 #endif
85335     }
85336 }
85337 #if 0
85338 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85339 {
85340     for (drflac_uint64 i = 0; i < frameCount; ++i) {
85341         pOutputSamples[i*2+0] = (float)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) / 2147483648.0);
85342         pOutputSamples[i*2+1] = (float)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) / 2147483648.0);
85343     }
85344 }
85345 #endif
85346 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85347 {
85348     drflac_uint64 i;
85349     drflac_uint64 frameCount4 = frameCount >> 2;
85350     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
85351     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
85352     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
85353     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
85354     float factor = 1 / 2147483648.0;
85355     for (i = 0; i < frameCount4; ++i) {
85356         drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
85357         drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
85358         drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
85359         drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
85360         drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
85361         drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
85362         drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
85363         drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
85364         pOutputSamples[i*8+0] = (drflac_int32)tempL0 * factor;
85365         pOutputSamples[i*8+1] = (drflac_int32)tempR0 * factor;
85366         pOutputSamples[i*8+2] = (drflac_int32)tempL1 * factor;
85367         pOutputSamples[i*8+3] = (drflac_int32)tempR1 * factor;
85368         pOutputSamples[i*8+4] = (drflac_int32)tempL2 * factor;
85369         pOutputSamples[i*8+5] = (drflac_int32)tempR2 * factor;
85370         pOutputSamples[i*8+6] = (drflac_int32)tempL3 * factor;
85371         pOutputSamples[i*8+7] = (drflac_int32)tempR3 * factor;
85372     }
85373     for (i = (frameCount4 << 2); i < frameCount; ++i) {
85374         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
85375         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
85376     }
85377 }
85378 #if defined(DRFLAC_SUPPORT_SSE2)
85379 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85380 {
85381     drflac_uint64 i;
85382     drflac_uint64 frameCount4 = frameCount >> 2;
85383     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
85384     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
85385     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
85386     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
85387     float factor = 1.0f / 8388608.0f;
85388     __m128 factor128 = _mm_set1_ps(factor);
85389     for (i = 0; i < frameCount4; ++i) {
85390         __m128i lefti;
85391         __m128i righti;
85392         __m128 leftf;
85393         __m128 rightf;
85394         lefti  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
85395         righti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
85396         leftf  = _mm_mul_ps(_mm_cvtepi32_ps(lefti),  factor128);
85397         rightf = _mm_mul_ps(_mm_cvtepi32_ps(righti), factor128);
85398         _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
85399         _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
85400     }
85401     for (i = (frameCount4 << 2); i < frameCount; ++i) {
85402         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
85403         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
85404     }
85405 }
85406 #endif
85407 #if defined(DRFLAC_SUPPORT_NEON)
85408 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85409 {
85410     drflac_uint64 i;
85411     drflac_uint64 frameCount4 = frameCount >> 2;
85412     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
85413     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
85414     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
85415     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
85416     float factor = 1.0f / 8388608.0f;
85417     float32x4_t factor4 = vdupq_n_f32(factor);
85418     int32x4_t shift0_4  = vdupq_n_s32(shift0);
85419     int32x4_t shift1_4  = vdupq_n_s32(shift1);
85420     for (i = 0; i < frameCount4; ++i) {
85421         int32x4_t lefti;
85422         int32x4_t righti;
85423         float32x4_t leftf;
85424         float32x4_t rightf;
85425         lefti  = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4));
85426         righti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4));
85427         leftf  = vmulq_f32(vcvtq_f32_s32(lefti),  factor4);
85428         rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
85429         drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
85430     }
85431     for (i = (frameCount4 << 2); i < frameCount; ++i) {
85432         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
85433         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
85434     }
85435 }
85436 #endif
85437 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
85438 {
85439 #if defined(DRFLAC_SUPPORT_SSE2)
85440     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
85441         drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85442     } else
85443 #elif defined(DRFLAC_SUPPORT_NEON)
85444     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
85445         drflac_read_pcm_frames_f32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85446     } else
85447 #endif
85448     {
85449 #if 0
85450         drflac_read_pcm_frames_f32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85451 #else
85452         drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
85453 #endif
85454     }
85455 }
85456 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut)
85457 {
85458     drflac_uint64 framesRead;
85459     drflac_uint32 unusedBitsPerSample;
85460     if (pFlac == NULL || framesToRead == 0) {
85461         return 0;
85462     }
85463     if (pBufferOut == NULL) {
85464         return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
85465     }
85466     DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
85467     unusedBitsPerSample = 32 - pFlac->bitsPerSample;
85468     framesRead = 0;
85469     while (framesToRead > 0) {
85470         if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
85471             if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
85472                 break;
85473             }
85474         } else {
85475             unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
85476             drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
85477             drflac_uint64 frameCountThisIteration = framesToRead;
85478             if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
85479                 frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
85480             }
85481             if (channelCount == 2) {
85482                 const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
85483                 const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
85484                 switch (pFlac->currentFLACFrame.header.channelAssignment)
85485                 {
85486                     case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
85487                     {
85488                         drflac_read_pcm_frames_f32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
85489                     } break;
85490                     case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
85491                     {
85492                         drflac_read_pcm_frames_f32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
85493                     } break;
85494                     case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
85495                     {
85496                         drflac_read_pcm_frames_f32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
85497                     } break;
85498                     case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
85499                     default:
85500                     {
85501                         drflac_read_pcm_frames_f32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
85502                     } break;
85503                 }
85504             } else {
85505                 drflac_uint64 i;
85506                 for (i = 0; i < frameCountThisIteration; ++i) {
85507                     unsigned int j;
85508                     for (j = 0; j < channelCount; ++j) {
85509                         drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
85510                         pBufferOut[(i*channelCount)+j] = (float)(sampleS32 / 2147483648.0);
85511                     }
85512                 }
85513             }
85514             framesRead                += frameCountThisIteration;
85515             pBufferOut                += frameCountThisIteration * channelCount;
85516             framesToRead              -= frameCountThisIteration;
85517             pFlac->currentPCMFrame    += frameCountThisIteration;
85518             pFlac->currentFLACFrame.pcmFramesRemaining -= (unsigned int)frameCountThisIteration;
85519         }
85520     }
85521     return framesRead;
85522 }
85523 DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
85524 {
85525     if (pFlac == NULL) {
85526         return DRFLAC_FALSE;
85527     }
85528     if (pFlac->currentPCMFrame == pcmFrameIndex) {
85529         return DRFLAC_TRUE;
85530     }
85531     if (pFlac->firstFLACFramePosInBytes == 0) {
85532         return DRFLAC_FALSE;
85533     }
85534     if (pcmFrameIndex == 0) {
85535         pFlac->currentPCMFrame = 0;
85536         return drflac__seek_to_first_frame(pFlac);
85537     } else {
85538         drflac_bool32 wasSuccessful = DRFLAC_FALSE;
85539         drflac_uint64 originalPCMFrame = pFlac->currentPCMFrame;
85540         if (pcmFrameIndex > pFlac->totalPCMFrameCount) {
85541             pcmFrameIndex = pFlac->totalPCMFrameCount;
85542         }
85543         if (pcmFrameIndex > pFlac->currentPCMFrame) {
85544             drflac_uint32 offset = (drflac_uint32)(pcmFrameIndex - pFlac->currentPCMFrame);
85545             if (pFlac->currentFLACFrame.pcmFramesRemaining >  offset) {
85546                 pFlac->currentFLACFrame.pcmFramesRemaining -= offset;
85547                 pFlac->currentPCMFrame = pcmFrameIndex;
85548                 return DRFLAC_TRUE;
85549             }
85550         } else {
85551             drflac_uint32 offsetAbs = (drflac_uint32)(pFlac->currentPCMFrame - pcmFrameIndex);
85552             drflac_uint32 currentFLACFramePCMFrameCount = pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
85553             drflac_uint32 currentFLACFramePCMFramesConsumed = currentFLACFramePCMFrameCount - pFlac->currentFLACFrame.pcmFramesRemaining;
85554             if (currentFLACFramePCMFramesConsumed > offsetAbs) {
85555                 pFlac->currentFLACFrame.pcmFramesRemaining += offsetAbs;
85556                 pFlac->currentPCMFrame = pcmFrameIndex;
85557                 return DRFLAC_TRUE;
85558             }
85559         }
85560 #ifndef DR_FLAC_NO_OGG
85561         if (pFlac->container == drflac_container_ogg)
85562         {
85563             wasSuccessful = drflac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex);
85564         }
85565         else
85566 #endif
85567         {
85568             if (!pFlac->_noSeekTableSeek) {
85569                 wasSuccessful = drflac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex);
85570             }
85571 #if !defined(DR_FLAC_NO_CRC)
85572             if (!wasSuccessful && !pFlac->_noBinarySearchSeek && pFlac->totalPCMFrameCount > 0) {
85573                 wasSuccessful = drflac__seek_to_pcm_frame__binary_search(pFlac, pcmFrameIndex);
85574             }
85575 #endif
85576             if (!wasSuccessful && !pFlac->_noBruteForceSeek) {
85577                 wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex);
85578             }
85579         }
85580         if (wasSuccessful) {
85581             pFlac->currentPCMFrame = pcmFrameIndex;
85582         } else {
85583             if (drflac_seek_to_pcm_frame(pFlac, originalPCMFrame) == DRFLAC_FALSE) {
85584                 drflac_seek_to_pcm_frame(pFlac, 0);
85585             }
85586         }
85587         return wasSuccessful;
85588     }
85589 }
85590 #if defined(SIZE_MAX)
85591     #define DRFLAC_SIZE_MAX  SIZE_MAX
85592 #else
85593     #if defined(DRFLAC_64BIT)
85594         #define DRFLAC_SIZE_MAX  ((drflac_uint64)0xFFFFFFFFFFFFFFFF)
85595     #else
85596         #define DRFLAC_SIZE_MAX  0xFFFFFFFF
85597     #endif
85598 #endif
85599 #define DRFLAC_DEFINE_FULL_READ_AND_CLOSE(extension, type) \
85600 static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut)\
85601 {                                                                                                                                                                   \
85602     type* pSampleData = NULL;                                                                                                                                       \
85603     drflac_uint64 totalPCMFrameCount;                                                                                                                               \
85604                                                                                                                                                                     \
85605     DRFLAC_ASSERT(pFlac != NULL);                                                                                                                                   \
85606                                                                                                                                                                     \
85607     totalPCMFrameCount = pFlac->totalPCMFrameCount;                                                                                                                 \
85608                                                                                                                                                                     \
85609     if (totalPCMFrameCount == 0) {                                                                                                                                  \
85610         type buffer[4096];                                                                                                                                          \
85611         drflac_uint64 pcmFramesRead;                                                                                                                                \
85612         size_t sampleDataBufferSize = sizeof(buffer);                                                                                                               \
85613                                                                                                                                                                     \
85614         pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks);                                                      \
85615         if (pSampleData == NULL) {                                                                                                                                  \
85616             goto on_error;                                                                                                                                          \
85617         }                                                                                                                                                           \
85618                                                                                                                                                                     \
85619         while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) {          \
85620             if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) {                                                   \
85621                 type* pNewSampleData;                                                                                                                               \
85622                 size_t newSampleDataBufferSize;                                                                                                                     \
85623                                                                                                                                                                     \
85624                 newSampleDataBufferSize = sampleDataBufferSize * 2;                                                                                                 \
85625                 pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks);    \
85626                 if (pNewSampleData == NULL) {                                                                                                                       \
85627                     drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks);                                                                          \
85628                     goto on_error;                                                                                                                                  \
85629                 }                                                                                                                                                   \
85630                                                                                                                                                                     \
85631                 sampleDataBufferSize = newSampleDataBufferSize;                                                                                                     \
85632                 pSampleData = pNewSampleData;                                                                                                                       \
85633             }                                                                                                                                                       \
85634                                                                                                                                                                     \
85635             DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type)));                   \
85636             totalPCMFrameCount += pcmFramesRead;                                                                                                                    \
85637         }                                                                                                                                                           \
85638                                                                                                                                                                     \
85639                                                                                                                          \
85640         DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type)));   \
85641     } else {                                                                                                                                                        \
85642         drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type);                                                                                   \
85643         if (dataSize > (drflac_uint64)DRFLAC_SIZE_MAX) {                                                                                                            \
85644             goto on_error;                                                                                                        \
85645         }                                                                                                                                                           \
85646                                                                                                                                                                     \
85647         pSampleData = (type*)drflac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks);               \
85648         if (pSampleData == NULL) {                                                                                                                                  \
85649             goto on_error;                                                                                                                                          \
85650         }                                                                                                                                                           \
85651                                                                                                                                                                     \
85652         totalPCMFrameCount = drflac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData);                                                     \
85653     }                                                                                                                                                               \
85654                                                                                                                                                                     \
85655     if (sampleRateOut) *sampleRateOut = pFlac->sampleRate;                                                                                                          \
85656     if (channelsOut) *channelsOut = pFlac->channels;                                                                                                                \
85657     if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount;                                                                                         \
85658                                                                                                                                                                     \
85659     drflac_close(pFlac);                                                                                                                                            \
85660     return pSampleData;                                                                                                                                             \
85661                                                                                                                                                                     \
85662 on_error:                                                                                                                                                           \
85663     drflac_close(pFlac);                                                                                                                                            \
85664     return NULL;                                                                                                                                                    \
85665 }
85666 DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32)
85667 DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16)
85668 DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float)
85669 DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
85670 {
85671     drflac* pFlac;
85672     if (channelsOut) {
85673         *channelsOut = 0;
85674     }
85675     if (sampleRateOut) {
85676         *sampleRateOut = 0;
85677     }
85678     if (totalPCMFrameCountOut) {
85679         *totalPCMFrameCountOut = 0;
85680     }
85681     pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
85682     if (pFlac == NULL) {
85683         return NULL;
85684     }
85685     return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
85686 }
85687 DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
85688 {
85689     drflac* pFlac;
85690     if (channelsOut) {
85691         *channelsOut = 0;
85692     }
85693     if (sampleRateOut) {
85694         *sampleRateOut = 0;
85695     }
85696     if (totalPCMFrameCountOut) {
85697         *totalPCMFrameCountOut = 0;
85698     }
85699     pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
85700     if (pFlac == NULL) {
85701         return NULL;
85702     }
85703     return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
85704 }
85705 DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
85706 {
85707     drflac* pFlac;
85708     if (channelsOut) {
85709         *channelsOut = 0;
85710     }
85711     if (sampleRateOut) {
85712         *sampleRateOut = 0;
85713     }
85714     if (totalPCMFrameCountOut) {
85715         *totalPCMFrameCountOut = 0;
85716     }
85717     pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
85718     if (pFlac == NULL) {
85719         return NULL;
85720     }
85721     return drflac__full_read_and_close_f32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
85722 }
85723 #ifndef DR_FLAC_NO_STDIO
85724 DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
85725 {
85726     drflac* pFlac;
85727     if (sampleRate) {
85728         *sampleRate = 0;
85729     }
85730     if (channels) {
85731         *channels = 0;
85732     }
85733     if (totalPCMFrameCount) {
85734         *totalPCMFrameCount = 0;
85735     }
85736     pFlac = drflac_open_file(filename, pAllocationCallbacks);
85737     if (pFlac == NULL) {
85738         return NULL;
85739     }
85740     return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
85741 }
85742 DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
85743 {
85744     drflac* pFlac;
85745     if (sampleRate) {
85746         *sampleRate = 0;
85747     }
85748     if (channels) {
85749         *channels = 0;
85750     }
85751     if (totalPCMFrameCount) {
85752         *totalPCMFrameCount = 0;
85753     }
85754     pFlac = drflac_open_file(filename, pAllocationCallbacks);
85755     if (pFlac == NULL) {
85756         return NULL;
85757     }
85758     return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
85759 }
85760 DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
85761 {
85762     drflac* pFlac;
85763     if (sampleRate) {
85764         *sampleRate = 0;
85765     }
85766     if (channels) {
85767         *channels = 0;
85768     }
85769     if (totalPCMFrameCount) {
85770         *totalPCMFrameCount = 0;
85771     }
85772     pFlac = drflac_open_file(filename, pAllocationCallbacks);
85773     if (pFlac == NULL) {
85774         return NULL;
85775     }
85776     return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
85777 }
85778 #endif
85779 DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
85780 {
85781     drflac* pFlac;
85782     if (sampleRate) {
85783         *sampleRate = 0;
85784     }
85785     if (channels) {
85786         *channels = 0;
85787     }
85788     if (totalPCMFrameCount) {
85789         *totalPCMFrameCount = 0;
85790     }
85791     pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
85792     if (pFlac == NULL) {
85793         return NULL;
85794     }
85795     return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
85796 }
85797 DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
85798 {
85799     drflac* pFlac;
85800     if (sampleRate) {
85801         *sampleRate = 0;
85802     }
85803     if (channels) {
85804         *channels = 0;
85805     }
85806     if (totalPCMFrameCount) {
85807         *totalPCMFrameCount = 0;
85808     }
85809     pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
85810     if (pFlac == NULL) {
85811         return NULL;
85812     }
85813     return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
85814 }
85815 DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
85816 {
85817     drflac* pFlac;
85818     if (sampleRate) {
85819         *sampleRate = 0;
85820     }
85821     if (channels) {
85822         *channels = 0;
85823     }
85824     if (totalPCMFrameCount) {
85825         *totalPCMFrameCount = 0;
85826     }
85827     pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
85828     if (pFlac == NULL) {
85829         return NULL;
85830     }
85831     return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
85832 }
85833 DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks)
85834 {
85835     if (pAllocationCallbacks != NULL) {
85836         drflac__free_from_callbacks(p, pAllocationCallbacks);
85837     } else {
85838         drflac__free_default(p, NULL);
85839     }
85840 }
85841 DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments)
85842 {
85843     if (pIter == NULL) {
85844         return;
85845     }
85846     pIter->countRemaining = commentCount;
85847     pIter->pRunningData   = (const char*)pComments;
85848 }
85849 DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut)
85850 {
85851     drflac_int32 length;
85852     const char* pComment;
85853     if (pCommentLengthOut) {
85854         *pCommentLengthOut = 0;
85855     }
85856     if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
85857         return NULL;
85858     }
85859     length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData);
85860     pIter->pRunningData += 4;
85861     pComment = pIter->pRunningData;
85862     pIter->pRunningData += length;
85863     pIter->countRemaining -= 1;
85864     if (pCommentLengthOut) {
85865         *pCommentLengthOut = length;
85866     }
85867     return pComment;
85868 }
85869 DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData)
85870 {
85871     if (pIter == NULL) {
85872         return;
85873     }
85874     pIter->countRemaining = trackCount;
85875     pIter->pRunningData   = (const char*)pTrackData;
85876 }
85877 DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack)
85878 {
85879     drflac_cuesheet_track cuesheetTrack;
85880     const char* pRunningData;
85881     drflac_uint64 offsetHi;
85882     drflac_uint64 offsetLo;
85883     if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
85884         return DRFLAC_FALSE;
85885     }
85886     pRunningData = pIter->pRunningData;
85887     offsetHi                   = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
85888     offsetLo                   = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
85889     cuesheetTrack.offset       = offsetLo | (offsetHi << 32);
85890     cuesheetTrack.trackNumber  = pRunningData[0];                                         pRunningData += 1;
85891     DRFLAC_COPY_MEMORY(cuesheetTrack.ISRC, pRunningData, sizeof(cuesheetTrack.ISRC));     pRunningData += 12;
85892     cuesheetTrack.isAudio      = (pRunningData[0] & 0x80) != 0;
85893     cuesheetTrack.preEmphasis  = (pRunningData[0] & 0x40) != 0;                           pRunningData += 14;
85894     cuesheetTrack.indexCount   = pRunningData[0];                                         pRunningData += 1;
85895     cuesheetTrack.pIndexPoints = (const drflac_cuesheet_track_index*)pRunningData;        pRunningData += cuesheetTrack.indexCount * sizeof(drflac_cuesheet_track_index);
85896     pIter->pRunningData = pRunningData;
85897     pIter->countRemaining -= 1;
85898     if (pCuesheetTrack) {
85899         *pCuesheetTrack = cuesheetTrack;
85900     }
85901     return DRFLAC_TRUE;
85902 }
85903 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
85904     #pragma GCC diagnostic pop
85905 #endif
85906 #endif
85907 /* dr_flac_c end */
85908 #endif  /* DRFLAC_IMPLEMENTATION */
85909 #endif  /* MA_NO_FLAC */
85910
85911 #if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING)
85912 #if !defined(DR_MP3_IMPLEMENTATION) && !defined(DRMP3_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */
85913 /* dr_mp3_c begin */
85914 #ifndef dr_mp3_c
85915 #define dr_mp3_c
85916 #include <stdlib.h>
85917 #include <string.h>
85918 #include <limits.h>
85919 DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision)
85920 {
85921     if (pMajor) {
85922         *pMajor = DRMP3_VERSION_MAJOR;
85923     }
85924     if (pMinor) {
85925         *pMinor = DRMP3_VERSION_MINOR;
85926     }
85927     if (pRevision) {
85928         *pRevision = DRMP3_VERSION_REVISION;
85929     }
85930 }
85931 DRMP3_API const char* drmp3_version_string(void)
85932 {
85933     return DRMP3_VERSION_STRING;
85934 }
85935 #if defined(__TINYC__)
85936 #define DR_MP3_NO_SIMD
85937 #endif
85938 #define DRMP3_OFFSET_PTR(p, offset) ((void*)((drmp3_uint8*)(p) + (offset)))
85939 #define DRMP3_MAX_FREE_FORMAT_FRAME_SIZE  2304
85940 #ifndef DRMP3_MAX_FRAME_SYNC_MATCHES
85941 #define DRMP3_MAX_FRAME_SYNC_MATCHES      10
85942 #endif
85943 #define DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES  DRMP3_MAX_FREE_FORMAT_FRAME_SIZE
85944 #define DRMP3_MAX_BITRESERVOIR_BYTES      511
85945 #define DRMP3_SHORT_BLOCK_TYPE            2
85946 #define DRMP3_STOP_BLOCK_TYPE             3
85947 #define DRMP3_MODE_MONO                   3
85948 #define DRMP3_MODE_JOINT_STEREO           1
85949 #define DRMP3_HDR_SIZE                    4
85950 #define DRMP3_HDR_IS_MONO(h)              (((h[3]) & 0xC0) == 0xC0)
85951 #define DRMP3_HDR_IS_MS_STEREO(h)         (((h[3]) & 0xE0) == 0x60)
85952 #define DRMP3_HDR_IS_FREE_FORMAT(h)       (((h[2]) & 0xF0) == 0)
85953 #define DRMP3_HDR_IS_CRC(h)               (!((h[1]) & 1))
85954 #define DRMP3_HDR_TEST_PADDING(h)         ((h[2]) & 0x2)
85955 #define DRMP3_HDR_TEST_MPEG1(h)           ((h[1]) & 0x8)
85956 #define DRMP3_HDR_TEST_NOT_MPEG25(h)      ((h[1]) & 0x10)
85957 #define DRMP3_HDR_TEST_I_STEREO(h)        ((h[3]) & 0x10)
85958 #define DRMP3_HDR_TEST_MS_STEREO(h)       ((h[3]) & 0x20)
85959 #define DRMP3_HDR_GET_STEREO_MODE(h)      (((h[3]) >> 6) & 3)
85960 #define DRMP3_HDR_GET_STEREO_MODE_EXT(h)  (((h[3]) >> 4) & 3)
85961 #define DRMP3_HDR_GET_LAYER(h)            (((h[1]) >> 1) & 3)
85962 #define DRMP3_HDR_GET_BITRATE(h)          ((h[2]) >> 4)
85963 #define DRMP3_HDR_GET_SAMPLE_RATE(h)      (((h[2]) >> 2) & 3)
85964 #define DRMP3_HDR_GET_MY_SAMPLE_RATE(h)   (DRMP3_HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1))*3)
85965 #define DRMP3_HDR_IS_FRAME_576(h)         ((h[1] & 14) == 2)
85966 #define DRMP3_HDR_IS_LAYER_1(h)           ((h[1] & 6) == 6)
85967 #define DRMP3_BITS_DEQUANTIZER_OUT        -1
85968 #define DRMP3_MAX_SCF                     (255 + DRMP3_BITS_DEQUANTIZER_OUT*4 - 210)
85969 #define DRMP3_MAX_SCFI                    ((DRMP3_MAX_SCF + 3) & ~3)
85970 #define DRMP3_MIN(a, b)           ((a) > (b) ? (b) : (a))
85971 #define DRMP3_MAX(a, b)           ((a) < (b) ? (b) : (a))
85972 #if !defined(DR_MP3_NO_SIMD)
85973 #if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64))
85974 #define DR_MP3_ONLY_SIMD
85975 #endif
85976 #if ((defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__))
85977 #if defined(_MSC_VER)
85978 #include <intrin.h>
85979 #endif
85980 #include <emmintrin.h>
85981 #define DRMP3_HAVE_SSE 1
85982 #define DRMP3_HAVE_SIMD 1
85983 #define DRMP3_VSTORE _mm_storeu_ps
85984 #define DRMP3_VLD _mm_loadu_ps
85985 #define DRMP3_VSET _mm_set1_ps
85986 #define DRMP3_VADD _mm_add_ps
85987 #define DRMP3_VSUB _mm_sub_ps
85988 #define DRMP3_VMUL _mm_mul_ps
85989 #define DRMP3_VMAC(a, x, y) _mm_add_ps(a, _mm_mul_ps(x, y))
85990 #define DRMP3_VMSB(a, x, y) _mm_sub_ps(a, _mm_mul_ps(x, y))
85991 #define DRMP3_VMUL_S(x, s)  _mm_mul_ps(x, _mm_set1_ps(s))
85992 #define DRMP3_VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3))
85993 typedef __m128 drmp3_f4;
85994 #if defined(_MSC_VER) || defined(DR_MP3_ONLY_SIMD)
85995 #define drmp3_cpuid __cpuid
85996 #else
85997 static __inline__ __attribute__((always_inline)) void drmp3_cpuid(int CPUInfo[], const int InfoType)
85998 {
85999 #if defined(__PIC__)
86000     __asm__ __volatile__(
86001 #if defined(__x86_64__)
86002         "push %%rbx\n"
86003         "cpuid\n"
86004         "xchgl %%ebx, %1\n"
86005         "pop  %%rbx\n"
86006 #else
86007         "xchgl %%ebx, %1\n"
86008         "cpuid\n"
86009         "xchgl %%ebx, %1\n"
86010 #endif
86011         : "=a" (CPUInfo[0]), "=r" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3])
86012         : "a" (InfoType));
86013 #else
86014     __asm__ __volatile__(
86015         "cpuid"
86016         : "=a" (CPUInfo[0]), "=b" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3])
86017         : "a" (InfoType));
86018 #endif
86019 }
86020 #endif
86021 static int drmp3_have_simd(void)
86022 {
86023 #ifdef DR_MP3_ONLY_SIMD
86024     return 1;
86025 #else
86026     static int g_have_simd;
86027     int CPUInfo[4];
86028 #ifdef MINIMP3_TEST
86029     static int g_counter;
86030     if (g_counter++ > 100)
86031         return 0;
86032 #endif
86033     if (g_have_simd)
86034         goto end;
86035     drmp3_cpuid(CPUInfo, 0);
86036     if (CPUInfo[0] > 0)
86037     {
86038         drmp3_cpuid(CPUInfo, 1);
86039         g_have_simd = (CPUInfo[3] & (1 << 26)) + 1;
86040         return g_have_simd - 1;
86041     }
86042 end:
86043     return g_have_simd - 1;
86044 #endif
86045 }
86046 #elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)
86047 #include <arm_neon.h>
86048 #define DRMP3_HAVE_SSE 0
86049 #define DRMP3_HAVE_SIMD 1
86050 #define DRMP3_VSTORE vst1q_f32
86051 #define DRMP3_VLD vld1q_f32
86052 #define DRMP3_VSET vmovq_n_f32
86053 #define DRMP3_VADD vaddq_f32
86054 #define DRMP3_VSUB vsubq_f32
86055 #define DRMP3_VMUL vmulq_f32
86056 #define DRMP3_VMAC(a, x, y) vmlaq_f32(a, x, y)
86057 #define DRMP3_VMSB(a, x, y) vmlsq_f32(a, x, y)
86058 #define DRMP3_VMUL_S(x, s)  vmulq_f32(x, vmovq_n_f32(s))
86059 #define DRMP3_VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x)))
86060 typedef float32x4_t drmp3_f4;
86061 static int drmp3_have_simd(void)
86062 {
86063     return 1;
86064 }
86065 #else
86066 #define DRMP3_HAVE_SSE 0
86067 #define DRMP3_HAVE_SIMD 0
86068 #ifdef DR_MP3_ONLY_SIMD
86069 #error DR_MP3_ONLY_SIMD used, but SSE/NEON not enabled
86070 #endif
86071 #endif
86072 #else
86073 #define DRMP3_HAVE_SIMD 0
86074 #endif
86075 #if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64)
86076 #define DRMP3_HAVE_ARMV6 1
86077 static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(drmp3_int32 a)
86078 {
86079     drmp3_int32 x = 0;
86080     __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a));
86081     return x;
86082 }
86083 #else
86084 #define DRMP3_HAVE_ARMV6 0
86085 #endif
86086 #ifndef DRMP3_ASSERT
86087 #include <assert.h>
86088 #define DRMP3_ASSERT(expression) assert(expression)
86089 #endif
86090 #ifndef DRMP3_COPY_MEMORY
86091 #define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
86092 #endif
86093 #ifndef DRMP3_MOVE_MEMORY
86094 #define DRMP3_MOVE_MEMORY(dst, src, sz) memmove((dst), (src), (sz))
86095 #endif
86096 #ifndef DRMP3_ZERO_MEMORY
86097 #define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
86098 #endif
86099 #define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p)))
86100 #ifndef DRMP3_MALLOC
86101 #define DRMP3_MALLOC(sz) malloc((sz))
86102 #endif
86103 #ifndef DRMP3_REALLOC
86104 #define DRMP3_REALLOC(p, sz) realloc((p), (sz))
86105 #endif
86106 #ifndef DRMP3_FREE
86107 #define DRMP3_FREE(p) free((p))
86108 #endif
86109 typedef struct
86110 {
86111     const drmp3_uint8 *buf;
86112     int pos, limit;
86113 } drmp3_bs;
86114 typedef struct
86115 {
86116     float scf[3*64];
86117     drmp3_uint8 total_bands, stereo_bands, bitalloc[64], scfcod[64];
86118 } drmp3_L12_scale_info;
86119 typedef struct
86120 {
86121     drmp3_uint8 tab_offset, code_tab_width, band_count;
86122 } drmp3_L12_subband_alloc;
86123 typedef struct
86124 {
86125     const drmp3_uint8 *sfbtab;
86126     drmp3_uint16 part_23_length, big_values, scalefac_compress;
86127     drmp3_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb;
86128     drmp3_uint8 table_select[3], region_count[3], subblock_gain[3];
86129     drmp3_uint8 preflag, scalefac_scale, count1_table, scfsi;
86130 } drmp3_L3_gr_info;
86131 typedef struct
86132 {
86133     drmp3_bs bs;
86134     drmp3_uint8 maindata[DRMP3_MAX_BITRESERVOIR_BYTES + DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES];
86135     drmp3_L3_gr_info gr_info[4];
86136     float grbuf[2][576], scf[40], syn[18 + 15][2*32];
86137     drmp3_uint8 ist_pos[2][39];
86138 } drmp3dec_scratch;
86139 static void drmp3_bs_init(drmp3_bs *bs, const drmp3_uint8 *data, int bytes)
86140 {
86141     bs->buf   = data;
86142     bs->pos   = 0;
86143     bs->limit = bytes*8;
86144 }
86145 static drmp3_uint32 drmp3_bs_get_bits(drmp3_bs *bs, int n)
86146 {
86147     drmp3_uint32 next, cache = 0, s = bs->pos & 7;
86148     int shl = n + s;
86149     const drmp3_uint8 *p = bs->buf + (bs->pos >> 3);
86150     if ((bs->pos += n) > bs->limit)
86151         return 0;
86152     next = *p++ & (255 >> s);
86153     while ((shl -= 8) > 0)
86154     {
86155         cache |= next << shl;
86156         next = *p++;
86157     }
86158     return cache | (next >> -shl);
86159 }
86160 static int drmp3_hdr_valid(const drmp3_uint8 *h)
86161 {
86162     return h[0] == 0xff &&
86163         ((h[1] & 0xF0) == 0xf0 || (h[1] & 0xFE) == 0xe2) &&
86164         (DRMP3_HDR_GET_LAYER(h) != 0) &&
86165         (DRMP3_HDR_GET_BITRATE(h) != 15) &&
86166         (DRMP3_HDR_GET_SAMPLE_RATE(h) != 3);
86167 }
86168 static int drmp3_hdr_compare(const drmp3_uint8 *h1, const drmp3_uint8 *h2)
86169 {
86170     return drmp3_hdr_valid(h2) &&
86171         ((h1[1] ^ h2[1]) & 0xFE) == 0 &&
86172         ((h1[2] ^ h2[2]) & 0x0C) == 0 &&
86173         !(DRMP3_HDR_IS_FREE_FORMAT(h1) ^ DRMP3_HDR_IS_FREE_FORMAT(h2));
86174 }
86175 static unsigned drmp3_hdr_bitrate_kbps(const drmp3_uint8 *h)
86176 {
86177     static const drmp3_uint8 halfrate[2][3][15] = {
86178         { { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,16,24,28,32,40,48,56,64,72,80,88,96,112,128 } },
86179         { { 0,16,20,24,28,32,40,48,56,64,80,96,112,128,160 }, { 0,16,24,28,32,40,48,56,64,80,96,112,128,160,192 }, { 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224 } },
86180     };
86181     return 2*halfrate[!!DRMP3_HDR_TEST_MPEG1(h)][DRMP3_HDR_GET_LAYER(h) - 1][DRMP3_HDR_GET_BITRATE(h)];
86182 }
86183 static unsigned drmp3_hdr_sample_rate_hz(const drmp3_uint8 *h)
86184 {
86185     static const unsigned g_hz[3] = { 44100, 48000, 32000 };
86186     return g_hz[DRMP3_HDR_GET_SAMPLE_RATE(h)] >> (int)!DRMP3_HDR_TEST_MPEG1(h) >> (int)!DRMP3_HDR_TEST_NOT_MPEG25(h);
86187 }
86188 static unsigned drmp3_hdr_frame_samples(const drmp3_uint8 *h)
86189 {
86190     return DRMP3_HDR_IS_LAYER_1(h) ? 384 : (1152 >> (int)DRMP3_HDR_IS_FRAME_576(h));
86191 }
86192 static int drmp3_hdr_frame_bytes(const drmp3_uint8 *h, int free_format_size)
86193 {
86194     int frame_bytes = drmp3_hdr_frame_samples(h)*drmp3_hdr_bitrate_kbps(h)*125/drmp3_hdr_sample_rate_hz(h);
86195     if (DRMP3_HDR_IS_LAYER_1(h))
86196     {
86197         frame_bytes &= ~3;
86198     }
86199     return frame_bytes ? frame_bytes : free_format_size;
86200 }
86201 static int drmp3_hdr_padding(const drmp3_uint8 *h)
86202 {
86203     return DRMP3_HDR_TEST_PADDING(h) ? (DRMP3_HDR_IS_LAYER_1(h) ? 4 : 1) : 0;
86204 }
86205 #ifndef DR_MP3_ONLY_MP3
86206 static const drmp3_L12_subband_alloc *drmp3_L12_subband_alloc_table(const drmp3_uint8 *hdr, drmp3_L12_scale_info *sci)
86207 {
86208     const drmp3_L12_subband_alloc *alloc;
86209     int mode = DRMP3_HDR_GET_STEREO_MODE(hdr);
86210     int nbands, stereo_bands = (mode == DRMP3_MODE_MONO) ? 0 : (mode == DRMP3_MODE_JOINT_STEREO) ? (DRMP3_HDR_GET_STEREO_MODE_EXT(hdr) << 2) + 4 : 32;
86211     if (DRMP3_HDR_IS_LAYER_1(hdr))
86212     {
86213         static const drmp3_L12_subband_alloc g_alloc_L1[] = { { 76, 4, 32 } };
86214         alloc = g_alloc_L1;
86215         nbands = 32;
86216     } else if (!DRMP3_HDR_TEST_MPEG1(hdr))
86217     {
86218         static const drmp3_L12_subband_alloc g_alloc_L2M2[] = { { 60, 4, 4 }, { 44, 3, 7 }, { 44, 2, 19 } };
86219         alloc = g_alloc_L2M2;
86220         nbands = 30;
86221     } else
86222     {
86223         static const drmp3_L12_subband_alloc g_alloc_L2M1[] = { { 0, 4, 3 }, { 16, 4, 8 }, { 32, 3, 12 }, { 40, 2, 7 } };
86224         int sample_rate_idx = DRMP3_HDR_GET_SAMPLE_RATE(hdr);
86225         unsigned kbps = drmp3_hdr_bitrate_kbps(hdr) >> (int)(mode != DRMP3_MODE_MONO);
86226         if (!kbps)
86227         {
86228             kbps = 192;
86229         }
86230         alloc = g_alloc_L2M1;
86231         nbands = 27;
86232         if (kbps < 56)
86233         {
86234             static const drmp3_L12_subband_alloc g_alloc_L2M1_lowrate[] = { { 44, 4, 2 }, { 44, 3, 10 } };
86235             alloc = g_alloc_L2M1_lowrate;
86236             nbands = sample_rate_idx == 2 ? 12 : 8;
86237         } else if (kbps >= 96 && sample_rate_idx != 1)
86238         {
86239             nbands = 30;
86240         }
86241     }
86242     sci->total_bands = (drmp3_uint8)nbands;
86243     sci->stereo_bands = (drmp3_uint8)DRMP3_MIN(stereo_bands, nbands);
86244     return alloc;
86245 }
86246 static void drmp3_L12_read_scalefactors(drmp3_bs *bs, drmp3_uint8 *pba, drmp3_uint8 *scfcod, int bands, float *scf)
86247 {
86248     static const float g_deq_L12[18*3] = {
86249 #define DRMP3_DQ(x) 9.53674316e-07f/x, 7.56931807e-07f/x, 6.00777173e-07f/x
86250         DRMP3_DQ(3),DRMP3_DQ(7),DRMP3_DQ(15),DRMP3_DQ(31),DRMP3_DQ(63),DRMP3_DQ(127),DRMP3_DQ(255),DRMP3_DQ(511),DRMP3_DQ(1023),DRMP3_DQ(2047),DRMP3_DQ(4095),DRMP3_DQ(8191),DRMP3_DQ(16383),DRMP3_DQ(32767),DRMP3_DQ(65535),DRMP3_DQ(3),DRMP3_DQ(5),DRMP3_DQ(9)
86251     };
86252     int i, m;
86253     for (i = 0; i < bands; i++)
86254     {
86255         float s = 0;
86256         int ba = *pba++;
86257         int mask = ba ? 4 + ((19 >> scfcod[i]) & 3) : 0;
86258         for (m = 4; m; m >>= 1)
86259         {
86260             if (mask & m)
86261             {
86262                 int b = drmp3_bs_get_bits(bs, 6);
86263                 s = g_deq_L12[ba*3 - 6 + b % 3]*(int)(1 << 21 >> b/3);
86264             }
86265             *scf++ = s;
86266         }
86267     }
86268 }
86269 static void drmp3_L12_read_scale_info(const drmp3_uint8 *hdr, drmp3_bs *bs, drmp3_L12_scale_info *sci)
86270 {
86271     static const drmp3_uint8 g_bitalloc_code_tab[] = {
86272         0,17, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16,
86273         0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,16,
86274         0,17,18, 3,19,4,5,16,
86275         0,17,18,16,
86276         0,17,18,19, 4,5,6, 7,8, 9,10,11,12,13,14,15,
86277         0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,14,
86278         0, 2, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16
86279     };
86280     const drmp3_L12_subband_alloc *subband_alloc = drmp3_L12_subband_alloc_table(hdr, sci);
86281     int i, k = 0, ba_bits = 0;
86282     const drmp3_uint8 *ba_code_tab = g_bitalloc_code_tab;
86283     for (i = 0; i < sci->total_bands; i++)
86284     {
86285         drmp3_uint8 ba;
86286         if (i == k)
86287         {
86288             k += subband_alloc->band_count;
86289             ba_bits = subband_alloc->code_tab_width;
86290             ba_code_tab = g_bitalloc_code_tab + subband_alloc->tab_offset;
86291             subband_alloc++;
86292         }
86293         ba = ba_code_tab[drmp3_bs_get_bits(bs, ba_bits)];
86294         sci->bitalloc[2*i] = ba;
86295         if (i < sci->stereo_bands)
86296         {
86297             ba = ba_code_tab[drmp3_bs_get_bits(bs, ba_bits)];
86298         }
86299         sci->bitalloc[2*i + 1] = sci->stereo_bands ? ba : 0;
86300     }
86301     for (i = 0; i < 2*sci->total_bands; i++)
86302     {
86303         sci->scfcod[i] = (drmp3_uint8)(sci->bitalloc[i] ? DRMP3_HDR_IS_LAYER_1(hdr) ? 2 : drmp3_bs_get_bits(bs, 2) : 6);
86304     }
86305     drmp3_L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands*2, sci->scf);
86306     for (i = sci->stereo_bands; i < sci->total_bands; i++)
86307     {
86308         sci->bitalloc[2*i + 1] = 0;
86309     }
86310 }
86311 static int drmp3_L12_dequantize_granule(float *grbuf, drmp3_bs *bs, drmp3_L12_scale_info *sci, int group_size)
86312 {
86313     int i, j, k, choff = 576;
86314     for (j = 0; j < 4; j++)
86315     {
86316         float *dst = grbuf + group_size*j;
86317         for (i = 0; i < 2*sci->total_bands; i++)
86318         {
86319             int ba = sci->bitalloc[i];
86320             if (ba != 0)
86321             {
86322                 if (ba < 17)
86323                 {
86324                     int half = (1 << (ba - 1)) - 1;
86325                     for (k = 0; k < group_size; k++)
86326                     {
86327                         dst[k] = (float)((int)drmp3_bs_get_bits(bs, ba) - half);
86328                     }
86329                 } else
86330                 {
86331                     unsigned mod = (2 << (ba - 17)) + 1;
86332                     unsigned code = drmp3_bs_get_bits(bs, mod + 2 - (mod >> 3));
86333                     for (k = 0; k < group_size; k++, code /= mod)
86334                     {
86335                         dst[k] = (float)((int)(code % mod - mod/2));
86336                     }
86337                 }
86338             }
86339             dst += choff;
86340             choff = 18 - choff;
86341         }
86342     }
86343     return group_size*4;
86344 }
86345 static void drmp3_L12_apply_scf_384(drmp3_L12_scale_info *sci, const float *scf, float *dst)
86346 {
86347     int i, k;
86348     DRMP3_COPY_MEMORY(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float));
86349     for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6)
86350     {
86351         for (k = 0; k < 12; k++)
86352         {
86353             dst[k + 0]   *= scf[0];
86354             dst[k + 576] *= scf[3];
86355         }
86356     }
86357 }
86358 #endif
86359 static int drmp3_L3_read_side_info(drmp3_bs *bs, drmp3_L3_gr_info *gr, const drmp3_uint8 *hdr)
86360 {
86361     static const drmp3_uint8 g_scf_long[8][23] = {
86362         { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 },
86363         { 12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2,0 },
86364         { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 },
86365         { 6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,54,62,70,76,36,0 },
86366         { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 },
86367         { 4,4,4,4,4,4,6,6,8,8,10,12,16,20,24,28,34,42,50,54,76,158,0 },
86368         { 4,4,4,4,4,4,6,6,6,8,10,12,16,18,22,28,34,40,46,54,54,192,0 },
86369         { 4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102,26,0 }
86370     };
86371     static const drmp3_uint8 g_scf_short[8][40] = {
86372         { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 },
86373         { 8,8,8,8,8,8,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 },
86374         { 4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 },
86375         { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 },
86376         { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 },
86377         { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 },
86378         { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 },
86379         { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 }
86380     };
86381     static const drmp3_uint8 g_scf_mixed[8][40] = {
86382         { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 },
86383         { 12,12,12,4,4,4,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 },
86384         { 6,6,6,6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 },
86385         { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 },
86386         { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 },
86387         { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 },
86388         { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 },
86389         { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 }
86390     };
86391     unsigned tables, scfsi = 0;
86392     int main_data_begin, part_23_sum = 0;
86393     int gr_count = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2;
86394     int sr_idx = DRMP3_HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0);
86395     if (DRMP3_HDR_TEST_MPEG1(hdr))
86396     {
86397         gr_count *= 2;
86398         main_data_begin = drmp3_bs_get_bits(bs, 9);
86399         scfsi = drmp3_bs_get_bits(bs, 7 + gr_count);
86400     } else
86401     {
86402         main_data_begin = drmp3_bs_get_bits(bs, 8 + gr_count) >> gr_count;
86403     }
86404     do
86405     {
86406         if (DRMP3_HDR_IS_MONO(hdr))
86407         {
86408             scfsi <<= 4;
86409         }
86410         gr->part_23_length = (drmp3_uint16)drmp3_bs_get_bits(bs, 12);
86411         part_23_sum += gr->part_23_length;
86412         gr->big_values = (drmp3_uint16)drmp3_bs_get_bits(bs,  9);
86413         if (gr->big_values > 288)
86414         {
86415             return -1;
86416         }
86417         gr->global_gain = (drmp3_uint8)drmp3_bs_get_bits(bs, 8);
86418         gr->scalefac_compress = (drmp3_uint16)drmp3_bs_get_bits(bs, DRMP3_HDR_TEST_MPEG1(hdr) ? 4 : 9);
86419         gr->sfbtab = g_scf_long[sr_idx];
86420         gr->n_long_sfb  = 22;
86421         gr->n_short_sfb = 0;
86422         if (drmp3_bs_get_bits(bs, 1))
86423         {
86424             gr->block_type = (drmp3_uint8)drmp3_bs_get_bits(bs, 2);
86425             if (!gr->block_type)
86426             {
86427                 return -1;
86428             }
86429             gr->mixed_block_flag = (drmp3_uint8)drmp3_bs_get_bits(bs, 1);
86430             gr->region_count[0] = 7;
86431             gr->region_count[1] = 255;
86432             if (gr->block_type == DRMP3_SHORT_BLOCK_TYPE)
86433             {
86434                 scfsi &= 0x0F0F;
86435                 if (!gr->mixed_block_flag)
86436                 {
86437                     gr->region_count[0] = 8;
86438                     gr->sfbtab = g_scf_short[sr_idx];
86439                     gr->n_long_sfb = 0;
86440                     gr->n_short_sfb = 39;
86441                 } else
86442                 {
86443                     gr->sfbtab = g_scf_mixed[sr_idx];
86444                     gr->n_long_sfb = DRMP3_HDR_TEST_MPEG1(hdr) ? 8 : 6;
86445                     gr->n_short_sfb = 30;
86446                 }
86447             }
86448             tables = drmp3_bs_get_bits(bs, 10);
86449             tables <<= 5;
86450             gr->subblock_gain[0] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
86451             gr->subblock_gain[1] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
86452             gr->subblock_gain[2] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
86453         } else
86454         {
86455             gr->block_type = 0;
86456             gr->mixed_block_flag = 0;
86457             tables = drmp3_bs_get_bits(bs, 15);
86458             gr->region_count[0] = (drmp3_uint8)drmp3_bs_get_bits(bs, 4);
86459             gr->region_count[1] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
86460             gr->region_count[2] = 255;
86461         }
86462         gr->table_select[0] = (drmp3_uint8)(tables >> 10);
86463         gr->table_select[1] = (drmp3_uint8)((tables >> 5) & 31);
86464         gr->table_select[2] = (drmp3_uint8)((tables) & 31);
86465         gr->preflag = (drmp3_uint8)(DRMP3_HDR_TEST_MPEG1(hdr) ? drmp3_bs_get_bits(bs, 1) : (gr->scalefac_compress >= 500));
86466         gr->scalefac_scale = (drmp3_uint8)drmp3_bs_get_bits(bs, 1);
86467         gr->count1_table = (drmp3_uint8)drmp3_bs_get_bits(bs, 1);
86468         gr->scfsi = (drmp3_uint8)((scfsi >> 12) & 15);
86469         scfsi <<= 4;
86470         gr++;
86471     } while(--gr_count);
86472     if (part_23_sum + bs->pos > bs->limit + main_data_begin*8)
86473     {
86474         return -1;
86475     }
86476     return main_data_begin;
86477 }
86478 static void drmp3_L3_read_scalefactors(drmp3_uint8 *scf, drmp3_uint8 *ist_pos, const drmp3_uint8 *scf_size, const drmp3_uint8 *scf_count, drmp3_bs *bitbuf, int scfsi)
86479 {
86480     int i, k;
86481     for (i = 0; i < 4 && scf_count[i]; i++, scfsi *= 2)
86482     {
86483         int cnt = scf_count[i];
86484         if (scfsi & 8)
86485         {
86486             DRMP3_COPY_MEMORY(scf, ist_pos, cnt);
86487         } else
86488         {
86489             int bits = scf_size[i];
86490             if (!bits)
86491             {
86492                 DRMP3_ZERO_MEMORY(scf, cnt);
86493                 DRMP3_ZERO_MEMORY(ist_pos, cnt);
86494             } else
86495             {
86496                 int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1;
86497                 for (k = 0; k < cnt; k++)
86498                 {
86499                     int s = drmp3_bs_get_bits(bitbuf, bits);
86500                     ist_pos[k] = (drmp3_uint8)(s == max_scf ? -1 : s);
86501                     scf[k] = (drmp3_uint8)s;
86502                 }
86503             }
86504         }
86505         ist_pos += cnt;
86506         scf += cnt;
86507     }
86508     scf[0] = scf[1] = scf[2] = 0;
86509 }
86510 static float drmp3_L3_ldexp_q2(float y, int exp_q2)
86511 {
86512     static const float g_expfrac[4] = { 9.31322575e-10f,7.83145814e-10f,6.58544508e-10f,5.53767716e-10f };
86513     int e;
86514     do
86515     {
86516         e = DRMP3_MIN(30*4, exp_q2);
86517         y *= g_expfrac[e & 3]*(1 << 30 >> (e >> 2));
86518     } while ((exp_q2 -= e) > 0);
86519     return y;
86520 }
86521 static void drmp3_L3_decode_scalefactors(const drmp3_uint8 *hdr, drmp3_uint8 *ist_pos, drmp3_bs *bs, const drmp3_L3_gr_info *gr, float *scf, int ch)
86522 {
86523     static const drmp3_uint8 g_scf_partitions[3][28] = {
86524         { 6,5,5, 5,6,5,5,5,6,5, 7,3,11,10,0,0, 7, 7, 7,0, 6, 6,6,3, 8, 8,5,0 },
86525         { 8,9,6,12,6,9,9,9,6,9,12,6,15,18,0,0, 6,15,12,0, 6,12,9,6, 6,18,9,0 },
86526         { 9,9,6,12,9,9,9,9,9,9,12,6,18,18,0,0,12,12,12,0,12, 9,9,6,15,12,9,0 }
86527     };
86528     const drmp3_uint8 *scf_partition = g_scf_partitions[!!gr->n_short_sfb + !gr->n_long_sfb];
86529     drmp3_uint8 scf_size[4], iscf[40];
86530     int i, scf_shift = gr->scalefac_scale + 1, gain_exp, scfsi = gr->scfsi;
86531     float gain;
86532     if (DRMP3_HDR_TEST_MPEG1(hdr))
86533     {
86534         static const drmp3_uint8 g_scfc_decode[16] = { 0,1,2,3, 12,5,6,7, 9,10,11,13, 14,15,18,19 };
86535         int part = g_scfc_decode[gr->scalefac_compress];
86536         scf_size[1] = scf_size[0] = (drmp3_uint8)(part >> 2);
86537         scf_size[3] = scf_size[2] = (drmp3_uint8)(part & 3);
86538     } else
86539     {
86540         static const drmp3_uint8 g_mod[6*4] = { 5,5,4,4,5,5,4,1,4,3,1,1,5,6,6,1,4,4,4,1,4,3,1,1 };
86541         int k, modprod, sfc, ist = DRMP3_HDR_TEST_I_STEREO(hdr) && ch;
86542         sfc = gr->scalefac_compress >> ist;
86543         for (k = ist*3*4; sfc >= 0; sfc -= modprod, k += 4)
86544         {
86545             for (modprod = 1, i = 3; i >= 0; i--)
86546             {
86547                 scf_size[i] = (drmp3_uint8)(sfc / modprod % g_mod[k + i]);
86548                 modprod *= g_mod[k + i];
86549             }
86550         }
86551         scf_partition += k;
86552         scfsi = -16;
86553     }
86554     drmp3_L3_read_scalefactors(iscf, ist_pos, scf_size, scf_partition, bs, scfsi);
86555     if (gr->n_short_sfb)
86556     {
86557         int sh = 3 - scf_shift;
86558         for (i = 0; i < gr->n_short_sfb; i += 3)
86559         {
86560             iscf[gr->n_long_sfb + i + 0] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 0] + (gr->subblock_gain[0] << sh));
86561             iscf[gr->n_long_sfb + i + 1] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 1] + (gr->subblock_gain[1] << sh));
86562             iscf[gr->n_long_sfb + i + 2] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 2] + (gr->subblock_gain[2] << sh));
86563         }
86564     } else if (gr->preflag)
86565     {
86566         static const drmp3_uint8 g_preamp[10] = { 1,1,1,1,2,2,3,3,3,2 };
86567         for (i = 0; i < 10; i++)
86568         {
86569             iscf[11 + i] = (drmp3_uint8)(iscf[11 + i] + g_preamp[i]);
86570         }
86571     }
86572     gain_exp = gr->global_gain + DRMP3_BITS_DEQUANTIZER_OUT*4 - 210 - (DRMP3_HDR_IS_MS_STEREO(hdr) ? 2 : 0);
86573     gain = drmp3_L3_ldexp_q2(1 << (DRMP3_MAX_SCFI/4),  DRMP3_MAX_SCFI - gain_exp);
86574     for (i = 0; i < (int)(gr->n_long_sfb + gr->n_short_sfb); i++)
86575     {
86576         scf[i] = drmp3_L3_ldexp_q2(gain, iscf[i] << scf_shift);
86577     }
86578 }
86579 static const float g_drmp3_pow43[129 + 16] = {
86580     0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f,
86581     0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f
86582 };
86583 static float drmp3_L3_pow_43(int x)
86584 {
86585     float frac;
86586     int sign, mult = 256;
86587     if (x < 129)
86588     {
86589         return g_drmp3_pow43[16 + x];
86590     }
86591     if (x < 1024)
86592     {
86593         mult = 16;
86594         x <<= 3;
86595     }
86596     sign = 2*x & 64;
86597     frac = (float)((x & 63) - sign) / ((x & ~63) + sign);
86598     return g_drmp3_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult;
86599 }
86600 static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit)
86601 {
86602     static const drmp3_int16 tabs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86603         785,785,785,785,784,784,784,784,513,513,513,513,513,513,513,513,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,
86604         -255,1313,1298,1282,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,290,288,
86605         -255,1313,1298,1282,769,769,769,769,529,529,529,529,529,529,529,529,528,528,528,528,528,528,528,528,512,512,512,512,512,512,512,512,290,288,
86606         -253,-318,-351,-367,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,819,818,547,547,275,275,275,275,561,560,515,546,289,274,288,258,
86607         -254,-287,1329,1299,1314,1312,1057,1057,1042,1042,1026,1026,784,784,784,784,529,529,529,529,529,529,529,529,769,769,769,769,768,768,768,768,563,560,306,306,291,259,
86608         -252,-413,-477,-542,1298,-575,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-383,-399,1107,1092,1106,1061,849,849,789,789,1104,1091,773,773,1076,1075,341,340,325,309,834,804,577,577,532,532,516,516,832,818,803,816,561,561,531,531,515,546,289,289,288,258,
86609         -252,-429,-493,-559,1057,1057,1042,1042,529,529,529,529,529,529,529,529,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,-382,1077,-415,1106,1061,1104,849,849,789,789,1091,1076,1029,1075,834,834,597,581,340,340,339,324,804,833,532,532,832,772,818,803,817,787,816,771,290,290,290,290,288,258,
86610         -253,-349,-414,-447,-463,1329,1299,-479,1314,1312,1057,1057,1042,1042,1026,1026,785,785,785,785,784,784,784,784,769,769,769,769,768,768,768,768,-319,851,821,-335,836,850,805,849,341,340,325,336,533,533,579,579,564,564,773,832,578,548,563,516,321,276,306,291,304,259,
86611         -251,-572,-733,-830,-863,-879,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,1396,1351,1381,1366,1395,1335,1380,-559,1334,1138,1138,1063,1063,1350,1392,1031,1031,1062,1062,1364,1363,1120,1120,1333,1348,881,881,881,881,375,374,359,373,343,358,341,325,791,791,1123,1122,-703,1105,1045,-719,865,865,790,790,774,774,1104,1029,338,293,323,308,-799,-815,833,788,772,818,803,816,322,292,307,320,561,531,515,546,289,274,288,258,
86612         -251,-525,-605,-685,-765,-831,-846,1298,1057,1057,1312,1282,785,785,785,785,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,1399,1398,1383,1367,1382,1396,1351,-511,1381,1366,1139,1139,1079,1079,1124,1124,1364,1349,1363,1333,882,882,882,882,807,807,807,807,1094,1094,1136,1136,373,341,535,535,881,775,867,822,774,-591,324,338,-671,849,550,550,866,864,609,609,293,336,534,534,789,835,773,-751,834,804,308,307,833,788,832,772,562,562,547,547,305,275,560,515,290,290,
86613         -252,-397,-477,-557,-622,-653,-719,-735,-750,1329,1299,1314,1057,1057,1042,1042,1312,1282,1024,1024,785,785,785,785,784,784,784,784,769,769,769,769,-383,1127,1141,1111,1126,1140,1095,1110,869,869,883,883,1079,1109,882,882,375,374,807,868,838,881,791,-463,867,822,368,263,852,837,836,-543,610,610,550,550,352,336,534,534,865,774,851,821,850,805,593,533,579,564,773,832,578,578,548,548,577,577,307,276,306,291,516,560,259,259,
86614         -250,-2107,-2507,-2764,-2909,-2974,-3007,-3023,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-767,-1052,-1213,-1277,-1358,-1405,-1469,-1535,-1550,-1582,-1614,-1647,-1662,-1694,-1726,-1759,-1774,-1807,-1822,-1854,-1886,1565,-1919,-1935,-1951,-1967,1731,1730,1580,1717,-1983,1729,1564,-1999,1548,-2015,-2031,1715,1595,-2047,1714,-2063,1610,-2079,1609,-2095,1323,1323,1457,1457,1307,1307,1712,1547,1641,1700,1699,1594,1685,1625,1442,1442,1322,1322,-780,-973,-910,1279,1278,1277,1262,1276,1261,1275,1215,1260,1229,-959,974,974,989,989,-943,735,478,478,495,463,506,414,-1039,1003,958,1017,927,942,987,957,431,476,1272,1167,1228,-1183,1256,-1199,895,895,941,941,1242,1227,1212,1135,1014,1014,490,489,503,487,910,1013,985,925,863,894,970,955,1012,847,-1343,831,755,755,984,909,428,366,754,559,-1391,752,486,457,924,997,698,698,983,893,740,740,908,877,739,739,667,667,953,938,497,287,271,271,683,606,590,712,726,574,302,302,738,736,481,286,526,725,605,711,636,724,696,651,589,681,666,710,364,467,573,695,466,466,301,465,379,379,709,604,665,679,316,316,634,633,436,436,464,269,424,394,452,332,438,363,347,408,393,448,331,422,362,407,392,421,346,406,391,376,375,359,1441,1306,-2367,1290,-2383,1337,-2399,-2415,1426,1321,-2431,1411,1336,-2447,-2463,-2479,1169,1169,1049,1049,1424,1289,1412,1352,1319,-2495,1154,1154,1064,1064,1153,1153,416,390,360,404,403,389,344,374,373,343,358,372,327,357,342,311,356,326,1395,1394,1137,1137,1047,1047,1365,1392,1287,1379,1334,1364,1349,1378,1318,1363,792,792,792,792,1152,1152,1032,1032,1121,1121,1046,1046,1120,1120,1030,1030,-2895,1106,1061,1104,849,849,789,789,1091,1076,1029,1090,1060,1075,833,833,309,324,532,532,832,772,818,803,561,561,531,560,515,546,289,274,288,258,
86615         -250,-1179,-1579,-1836,-1996,-2124,-2253,-2333,-2413,-2477,-2542,-2574,-2607,-2622,-2655,1314,1313,1298,1312,1282,785,785,785,785,1040,1040,1025,1025,768,768,768,768,-766,-798,-830,-862,-895,-911,-927,-943,-959,-975,-991,-1007,-1023,-1039,-1055,-1070,1724,1647,-1103,-1119,1631,1767,1662,1738,1708,1723,-1135,1780,1615,1779,1599,1677,1646,1778,1583,-1151,1777,1567,1737,1692,1765,1722,1707,1630,1751,1661,1764,1614,1736,1676,1763,1750,1645,1598,1721,1691,1762,1706,1582,1761,1566,-1167,1749,1629,767,766,751,765,494,494,735,764,719,749,734,763,447,447,748,718,477,506,431,491,446,476,461,505,415,430,475,445,504,399,460,489,414,503,383,474,429,459,502,502,746,752,488,398,501,473,413,472,486,271,480,270,-1439,-1455,1357,-1471,-1487,-1503,1341,1325,-1519,1489,1463,1403,1309,-1535,1372,1448,1418,1476,1356,1462,1387,-1551,1475,1340,1447,1402,1386,-1567,1068,1068,1474,1461,455,380,468,440,395,425,410,454,364,467,466,464,453,269,409,448,268,432,1371,1473,1432,1417,1308,1460,1355,1446,1459,1431,1083,1083,1401,1416,1458,1445,1067,1067,1370,1457,1051,1051,1291,1430,1385,1444,1354,1415,1400,1443,1082,1082,1173,1113,1186,1066,1185,1050,-1967,1158,1128,1172,1097,1171,1081,-1983,1157,1112,416,266,375,400,1170,1142,1127,1065,793,793,1169,1033,1156,1096,1141,1111,1155,1080,1126,1140,898,898,808,808,897,897,792,792,1095,1152,1032,1125,1110,1139,1079,1124,882,807,838,881,853,791,-2319,867,368,263,822,852,837,866,806,865,-2399,851,352,262,534,534,821,836,594,594,549,549,593,593,533,533,848,773,579,579,564,578,548,563,276,276,577,576,306,291,516,560,305,305,275,259,
86616         -251,-892,-2058,-2620,-2828,-2957,-3023,-3039,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,-559,1530,-575,-591,1528,1527,1407,1526,1391,1023,1023,1023,1023,1525,1375,1268,1268,1103,1103,1087,1087,1039,1039,1523,-604,815,815,815,815,510,495,509,479,508,463,507,447,431,505,415,399,-734,-782,1262,-815,1259,1244,-831,1258,1228,-847,-863,1196,-879,1253,987,987,748,-767,493,493,462,477,414,414,686,669,478,446,461,445,474,429,487,458,412,471,1266,1264,1009,1009,799,799,-1019,-1276,-1452,-1581,-1677,-1757,-1821,-1886,-1933,-1997,1257,1257,1483,1468,1512,1422,1497,1406,1467,1496,1421,1510,1134,1134,1225,1225,1466,1451,1374,1405,1252,1252,1358,1480,1164,1164,1251,1251,1238,1238,1389,1465,-1407,1054,1101,-1423,1207,-1439,830,830,1248,1038,1237,1117,1223,1148,1236,1208,411,426,395,410,379,269,1193,1222,1132,1235,1221,1116,976,976,1192,1162,1177,1220,1131,1191,963,963,-1647,961,780,-1663,558,558,994,993,437,408,393,407,829,978,813,797,947,-1743,721,721,377,392,844,950,828,890,706,706,812,859,796,960,948,843,934,874,571,571,-1919,690,555,689,421,346,539,539,944,779,918,873,932,842,903,888,570,570,931,917,674,674,-2575,1562,-2591,1609,-2607,1654,1322,1322,1441,1441,1696,1546,1683,1593,1669,1624,1426,1426,1321,1321,1639,1680,1425,1425,1305,1305,1545,1668,1608,1623,1667,1592,1638,1666,1320,1320,1652,1607,1409,1409,1304,1304,1288,1288,1664,1637,1395,1395,1335,1335,1622,1636,1394,1394,1319,1319,1606,1621,1392,1392,1137,1137,1137,1137,345,390,360,375,404,373,1047,-2751,-2767,-2783,1062,1121,1046,-2799,1077,-2815,1106,1061,789,789,1105,1104,263,355,310,340,325,354,352,262,339,324,1091,1076,1029,1090,1060,1075,833,833,788,788,1088,1028,818,818,803,803,561,561,531,531,816,771,546,546,289,274,288,258,
86617         -253,-317,-381,-446,-478,-509,1279,1279,-811,-1179,-1451,-1756,-1900,-2028,-2189,-2253,-2333,-2414,-2445,-2511,-2526,1313,1298,-2559,1041,1041,1040,1040,1025,1025,1024,1024,1022,1007,1021,991,1020,975,1019,959,687,687,1018,1017,671,671,655,655,1016,1015,639,639,758,758,623,623,757,607,756,591,755,575,754,559,543,543,1009,783,-575,-621,-685,-749,496,-590,750,749,734,748,974,989,1003,958,988,973,1002,942,987,957,972,1001,926,986,941,971,956,1000,910,985,925,999,894,970,-1071,-1087,-1102,1390,-1135,1436,1509,1451,1374,-1151,1405,1358,1480,1420,-1167,1507,1494,1389,1342,1465,1435,1450,1326,1505,1310,1493,1373,1479,1404,1492,1464,1419,428,443,472,397,736,526,464,464,486,457,442,471,484,482,1357,1449,1434,1478,1388,1491,1341,1490,1325,1489,1463,1403,1309,1477,1372,1448,1418,1433,1476,1356,1462,1387,-1439,1475,1340,1447,1402,1474,1324,1461,1371,1473,269,448,1432,1417,1308,1460,-1711,1459,-1727,1441,1099,1099,1446,1386,1431,1401,-1743,1289,1083,1083,1160,1160,1458,1445,1067,1067,1370,1457,1307,1430,1129,1129,1098,1098,268,432,267,416,266,400,-1887,1144,1187,1082,1173,1113,1186,1066,1050,1158,1128,1143,1172,1097,1171,1081,420,391,1157,1112,1170,1142,1127,1065,1169,1049,1156,1096,1141,1111,1155,1080,1126,1154,1064,1153,1140,1095,1048,-2159,1125,1110,1137,-2175,823,823,1139,1138,807,807,384,264,368,263,868,838,853,791,867,822,852,837,866,806,865,790,-2319,851,821,836,352,262,850,805,849,-2399,533,533,835,820,336,261,578,548,563,577,532,532,832,772,562,562,547,547,305,275,560,515,290,290,288,258 };
86618     static const drmp3_uint8 tab32[] = { 130,162,193,209,44,28,76,140,9,9,9,9,9,9,9,9,190,254,222,238,126,94,157,157,109,61,173,205};
86619     static const drmp3_uint8 tab33[] = { 252,236,220,204,188,172,156,140,124,108,92,76,60,44,28,12 };
86620     static const drmp3_int16 tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 };
86621     static const drmp3_uint8 g_linbits[] =  { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 };
86622 #define DRMP3_PEEK_BITS(n)    (bs_cache >> (32 - n))
86623 #define DRMP3_FLUSH_BITS(n)   { bs_cache <<= (n); bs_sh += (n); }
86624 #define DRMP3_CHECK_BITS      while (bs_sh >= 0) { bs_cache |= (drmp3_uint32)*bs_next_ptr++ << bs_sh; bs_sh -= 8; }
86625 #define DRMP3_BSPOS           ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh)
86626     float one = 0.0f;
86627     int ireg = 0, big_val_cnt = gr_info->big_values;
86628     const drmp3_uint8 *sfb = gr_info->sfbtab;
86629     const drmp3_uint8 *bs_next_ptr = bs->buf + bs->pos/8;
86630     drmp3_uint32 bs_cache = (((bs_next_ptr[0]*256u + bs_next_ptr[1])*256u + bs_next_ptr[2])*256u + bs_next_ptr[3]) << (bs->pos & 7);
86631     int pairs_to_decode, np, bs_sh = (bs->pos & 7) - 8;
86632     bs_next_ptr += 4;
86633     while (big_val_cnt > 0)
86634     {
86635         int tab_num = gr_info->table_select[ireg];
86636         int sfb_cnt = gr_info->region_count[ireg++];
86637         const drmp3_int16 *codebook = tabs + tabindex[tab_num];
86638         int linbits = g_linbits[tab_num];
86639         if (linbits)
86640         {
86641             do
86642             {
86643                 np = *sfb++ / 2;
86644                 pairs_to_decode = DRMP3_MIN(big_val_cnt, np);
86645                 one = *scf++;
86646                 do
86647                 {
86648                     int j, w = 5;
86649                     int leaf = codebook[DRMP3_PEEK_BITS(w)];
86650                     while (leaf < 0)
86651                     {
86652                         DRMP3_FLUSH_BITS(w);
86653                         w = leaf & 7;
86654                         leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)];
86655                     }
86656                     DRMP3_FLUSH_BITS(leaf >> 8);
86657                     for (j = 0; j < 2; j++, dst++, leaf >>= 4)
86658                     {
86659                         int lsb = leaf & 0x0F;
86660                         if (lsb == 15)
86661                         {
86662                             lsb += DRMP3_PEEK_BITS(linbits);
86663                             DRMP3_FLUSH_BITS(linbits);
86664                             DRMP3_CHECK_BITS;
86665                             *dst = one*drmp3_L3_pow_43(lsb)*((drmp3_int32)bs_cache < 0 ? -1: 1);
86666                         } else
86667                         {
86668                             *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one;
86669                         }
86670                         DRMP3_FLUSH_BITS(lsb ? 1 : 0);
86671                     }
86672                     DRMP3_CHECK_BITS;
86673                 } while (--pairs_to_decode);
86674             } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0);
86675         } else
86676         {
86677             do
86678             {
86679                 np = *sfb++ / 2;
86680                 pairs_to_decode = DRMP3_MIN(big_val_cnt, np);
86681                 one = *scf++;
86682                 do
86683                 {
86684                     int j, w = 5;
86685                     int leaf = codebook[DRMP3_PEEK_BITS(w)];
86686                     while (leaf < 0)
86687                     {
86688                         DRMP3_FLUSH_BITS(w);
86689                         w = leaf & 7;
86690                         leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)];
86691                     }
86692                     DRMP3_FLUSH_BITS(leaf >> 8);
86693                     for (j = 0; j < 2; j++, dst++, leaf >>= 4)
86694                     {
86695                         int lsb = leaf & 0x0F;
86696                         *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one;
86697                         DRMP3_FLUSH_BITS(lsb ? 1 : 0);
86698                     }
86699                     DRMP3_CHECK_BITS;
86700                 } while (--pairs_to_decode);
86701             } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0);
86702         }
86703     }
86704     for (np = 1 - big_val_cnt;; dst += 4)
86705     {
86706         const drmp3_uint8 *codebook_count1 = (gr_info->count1_table) ? tab33 : tab32;
86707         int leaf = codebook_count1[DRMP3_PEEK_BITS(4)];
86708         if (!(leaf & 8))
86709         {
86710             leaf = codebook_count1[(leaf >> 3) + (bs_cache << 4 >> (32 - (leaf & 3)))];
86711         }
86712         DRMP3_FLUSH_BITS(leaf & 7);
86713         if (DRMP3_BSPOS > layer3gr_limit)
86714         {
86715             break;
86716         }
86717 #define DRMP3_RELOAD_SCALEFACTOR  if (!--np) { np = *sfb++/2; if (!np) break; one = *scf++; }
86718 #define DRMP3_DEQ_COUNT1(s) if (leaf & (128 >> s)) { dst[s] = ((drmp3_int32)bs_cache < 0) ? -one : one; DRMP3_FLUSH_BITS(1) }
86719         DRMP3_RELOAD_SCALEFACTOR;
86720         DRMP3_DEQ_COUNT1(0);
86721         DRMP3_DEQ_COUNT1(1);
86722         DRMP3_RELOAD_SCALEFACTOR;
86723         DRMP3_DEQ_COUNT1(2);
86724         DRMP3_DEQ_COUNT1(3);
86725         DRMP3_CHECK_BITS;
86726     }
86727     bs->pos = layer3gr_limit;
86728 }
86729 static void drmp3_L3_midside_stereo(float *left, int n)
86730 {
86731     int i = 0;
86732     float *right = left + 576;
86733 #if DRMP3_HAVE_SIMD
86734     if (drmp3_have_simd())
86735     {
86736         for (; i < n - 3; i += 4)
86737         {
86738             drmp3_f4 vl = DRMP3_VLD(left + i);
86739             drmp3_f4 vr = DRMP3_VLD(right + i);
86740             DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr));
86741             DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr));
86742         }
86743 #ifdef __GNUC__
86744         if (__builtin_constant_p(n % 4 == 0) && n % 4 == 0)
86745             return;
86746 #endif
86747     }
86748 #endif
86749     for (; i < n; i++)
86750     {
86751         float a = left[i];
86752         float b = right[i];
86753         left[i] = a + b;
86754         right[i] = a - b;
86755     }
86756 }
86757 static void drmp3_L3_intensity_stereo_band(float *left, int n, float kl, float kr)
86758 {
86759     int i;
86760     for (i = 0; i < n; i++)
86761     {
86762         left[i + 576] = left[i]*kr;
86763         left[i] = left[i]*kl;
86764     }
86765 }
86766 static void drmp3_L3_stereo_top_band(const float *right, const drmp3_uint8 *sfb, int nbands, int max_band[3])
86767 {
86768     int i, k;
86769     max_band[0] = max_band[1] = max_band[2] = -1;
86770     for (i = 0; i < nbands; i++)
86771     {
86772         for (k = 0; k < sfb[i]; k += 2)
86773         {
86774             if (right[k] != 0 || right[k + 1] != 0)
86775             {
86776                 max_band[i % 3] = i;
86777                 break;
86778             }
86779         }
86780         right += sfb[i];
86781     }
86782 }
86783 static void drmp3_L3_stereo_process(float *left, const drmp3_uint8 *ist_pos, const drmp3_uint8 *sfb, const drmp3_uint8 *hdr, int max_band[3], int mpeg2_sh)
86784 {
86785     static const float g_pan[7*2] = { 0,1,0.21132487f,0.78867513f,0.36602540f,0.63397460f,0.5f,0.5f,0.63397460f,0.36602540f,0.78867513f,0.21132487f,1,0 };
86786     unsigned i, max_pos = DRMP3_HDR_TEST_MPEG1(hdr) ? 7 : 64;
86787     for (i = 0; sfb[i]; i++)
86788     {
86789         unsigned ipos = ist_pos[i];
86790         if ((int)i > max_band[i % 3] && ipos < max_pos)
86791         {
86792             float kl, kr, s = DRMP3_HDR_TEST_MS_STEREO(hdr) ? 1.41421356f : 1;
86793             if (DRMP3_HDR_TEST_MPEG1(hdr))
86794             {
86795                 kl = g_pan[2*ipos];
86796                 kr = g_pan[2*ipos + 1];
86797             } else
86798             {
86799                 kl = 1;
86800                 kr = drmp3_L3_ldexp_q2(1, (ipos + 1) >> 1 << mpeg2_sh);
86801                 if (ipos & 1)
86802                 {
86803                     kl = kr;
86804                     kr = 1;
86805                 }
86806             }
86807             drmp3_L3_intensity_stereo_band(left, sfb[i], kl*s, kr*s);
86808         } else if (DRMP3_HDR_TEST_MS_STEREO(hdr))
86809         {
86810             drmp3_L3_midside_stereo(left, sfb[i]);
86811         }
86812         left += sfb[i];
86813     }
86814 }
86815 static void drmp3_L3_intensity_stereo(float *left, drmp3_uint8 *ist_pos, const drmp3_L3_gr_info *gr, const drmp3_uint8 *hdr)
86816 {
86817     int max_band[3], n_sfb = gr->n_long_sfb + gr->n_short_sfb;
86818     int i, max_blocks = gr->n_short_sfb ? 3 : 1;
86819     drmp3_L3_stereo_top_band(left + 576, gr->sfbtab, n_sfb, max_band);
86820     if (gr->n_long_sfb)
86821     {
86822         max_band[0] = max_band[1] = max_band[2] = DRMP3_MAX(DRMP3_MAX(max_band[0], max_band[1]), max_band[2]);
86823     }
86824     for (i = 0; i < max_blocks; i++)
86825     {
86826         int default_pos = DRMP3_HDR_TEST_MPEG1(hdr) ? 3 : 0;
86827         int itop = n_sfb - max_blocks + i;
86828         int prev = itop - max_blocks;
86829         ist_pos[itop] = (drmp3_uint8)(max_band[i] >= prev ? default_pos : ist_pos[prev]);
86830     }
86831     drmp3_L3_stereo_process(left, ist_pos, gr->sfbtab, hdr, max_band, gr[1].scalefac_compress & 1);
86832 }
86833 static void drmp3_L3_reorder(float *grbuf, float *scratch, const drmp3_uint8 *sfb)
86834 {
86835     int i, len;
86836     float *src = grbuf, *dst = scratch;
86837     for (;0 != (len = *sfb); sfb += 3, src += 2*len)
86838     {
86839         for (i = 0; i < len; i++, src++)
86840         {
86841             *dst++ = src[0*len];
86842             *dst++ = src[1*len];
86843             *dst++ = src[2*len];
86844         }
86845     }
86846     DRMP3_COPY_MEMORY(grbuf, scratch, (dst - scratch)*sizeof(float));
86847 }
86848 static void drmp3_L3_antialias(float *grbuf, int nbands)
86849 {
86850     static const float g_aa[2][8] = {
86851         {0.85749293f,0.88174200f,0.94962865f,0.98331459f,0.99551782f,0.99916056f,0.99989920f,0.99999316f},
86852         {0.51449576f,0.47173197f,0.31337745f,0.18191320f,0.09457419f,0.04096558f,0.01419856f,0.00369997f}
86853     };
86854     for (; nbands > 0; nbands--, grbuf += 18)
86855     {
86856         int i = 0;
86857 #if DRMP3_HAVE_SIMD
86858         if (drmp3_have_simd()) for (; i < 8; i += 4)
86859         {
86860             drmp3_f4 vu = DRMP3_VLD(grbuf + 18 + i);
86861             drmp3_f4 vd = DRMP3_VLD(grbuf + 14 - i);
86862             drmp3_f4 vc0 = DRMP3_VLD(g_aa[0] + i);
86863             drmp3_f4 vc1 = DRMP3_VLD(g_aa[1] + i);
86864             vd = DRMP3_VREV(vd);
86865             DRMP3_VSTORE(grbuf + 18 + i, DRMP3_VSUB(DRMP3_VMUL(vu, vc0), DRMP3_VMUL(vd, vc1)));
86866             vd = DRMP3_VADD(DRMP3_VMUL(vu, vc1), DRMP3_VMUL(vd, vc0));
86867             DRMP3_VSTORE(grbuf + 14 - i, DRMP3_VREV(vd));
86868         }
86869 #endif
86870 #ifndef DR_MP3_ONLY_SIMD
86871         for(; i < 8; i++)
86872         {
86873             float u = grbuf[18 + i];
86874             float d = grbuf[17 - i];
86875             grbuf[18 + i] = u*g_aa[0][i] - d*g_aa[1][i];
86876             grbuf[17 - i] = u*g_aa[1][i] + d*g_aa[0][i];
86877         }
86878 #endif
86879     }
86880 }
86881 static void drmp3_L3_dct3_9(float *y)
86882 {
86883     float s0, s1, s2, s3, s4, s5, s6, s7, s8, t0, t2, t4;
86884     s0 = y[0]; s2 = y[2]; s4 = y[4]; s6 = y[6]; s8 = y[8];
86885     t0 = s0 + s6*0.5f;
86886     s0 -= s6;
86887     t4 = (s4 + s2)*0.93969262f;
86888     t2 = (s8 + s2)*0.76604444f;
86889     s6 = (s4 - s8)*0.17364818f;
86890     s4 += s8 - s2;
86891     s2 = s0 - s4*0.5f;
86892     y[4] = s4 + s0;
86893     s8 = t0 - t2 + s6;
86894     s0 = t0 - t4 + t2;
86895     s4 = t0 + t4 - s6;
86896     s1 = y[1]; s3 = y[3]; s5 = y[5]; s7 = y[7];
86897     s3 *= 0.86602540f;
86898     t0 = (s5 + s1)*0.98480775f;
86899     t4 = (s5 - s7)*0.34202014f;
86900     t2 = (s1 + s7)*0.64278761f;
86901     s1 = (s1 - s5 - s7)*0.86602540f;
86902     s5 = t0 - s3 - t2;
86903     s7 = t4 - s3 - t0;
86904     s3 = t4 + s3 - t2;
86905     y[0] = s4 - s7;
86906     y[1] = s2 + s1;
86907     y[2] = s0 - s3;
86908     y[3] = s8 + s5;
86909     y[5] = s8 - s5;
86910     y[6] = s0 + s3;
86911     y[7] = s2 - s1;
86912     y[8] = s4 + s7;
86913 }
86914 static void drmp3_L3_imdct36(float *grbuf, float *overlap, const float *window, int nbands)
86915 {
86916     int i, j;
86917     static const float g_twid9[18] = {
86918         0.73727734f,0.79335334f,0.84339145f,0.88701083f,0.92387953f,0.95371695f,0.97629601f,0.99144486f,0.99904822f,0.67559021f,0.60876143f,0.53729961f,0.46174861f,0.38268343f,0.30070580f,0.21643961f,0.13052619f,0.04361938f
86919     };
86920     for (j = 0; j < nbands; j++, grbuf += 18, overlap += 9)
86921     {
86922         float co[9], si[9];
86923         co[0] = -grbuf[0];
86924         si[0] = grbuf[17];
86925         for (i = 0; i < 4; i++)
86926         {
86927             si[8 - 2*i] =   grbuf[4*i + 1] - grbuf[4*i + 2];
86928             co[1 + 2*i] =   grbuf[4*i + 1] + grbuf[4*i + 2];
86929             si[7 - 2*i] =   grbuf[4*i + 4] - grbuf[4*i + 3];
86930             co[2 + 2*i] = -(grbuf[4*i + 3] + grbuf[4*i + 4]);
86931         }
86932         drmp3_L3_dct3_9(co);
86933         drmp3_L3_dct3_9(si);
86934         si[1] = -si[1];
86935         si[3] = -si[3];
86936         si[5] = -si[5];
86937         si[7] = -si[7];
86938         i = 0;
86939 #if DRMP3_HAVE_SIMD
86940         if (drmp3_have_simd()) for (; i < 8; i += 4)
86941         {
86942             drmp3_f4 vovl = DRMP3_VLD(overlap + i);
86943             drmp3_f4 vc = DRMP3_VLD(co + i);
86944             drmp3_f4 vs = DRMP3_VLD(si + i);
86945             drmp3_f4 vr0 = DRMP3_VLD(g_twid9 + i);
86946             drmp3_f4 vr1 = DRMP3_VLD(g_twid9 + 9 + i);
86947             drmp3_f4 vw0 = DRMP3_VLD(window + i);
86948             drmp3_f4 vw1 = DRMP3_VLD(window + 9 + i);
86949             drmp3_f4 vsum = DRMP3_VADD(DRMP3_VMUL(vc, vr1), DRMP3_VMUL(vs, vr0));
86950             DRMP3_VSTORE(overlap + i, DRMP3_VSUB(DRMP3_VMUL(vc, vr0), DRMP3_VMUL(vs, vr1)));
86951             DRMP3_VSTORE(grbuf + i, DRMP3_VSUB(DRMP3_VMUL(vovl, vw0), DRMP3_VMUL(vsum, vw1)));
86952             vsum = DRMP3_VADD(DRMP3_VMUL(vovl, vw1), DRMP3_VMUL(vsum, vw0));
86953             DRMP3_VSTORE(grbuf + 14 - i, DRMP3_VREV(vsum));
86954         }
86955 #endif
86956         for (; i < 9; i++)
86957         {
86958             float ovl  = overlap[i];
86959             float sum  = co[i]*g_twid9[9 + i] + si[i]*g_twid9[0 + i];
86960             overlap[i] = co[i]*g_twid9[0 + i] - si[i]*g_twid9[9 + i];
86961             grbuf[i]      = ovl*window[0 + i] - sum*window[9 + i];
86962             grbuf[17 - i] = ovl*window[9 + i] + sum*window[0 + i];
86963         }
86964     }
86965 }
86966 static void drmp3_L3_idct3(float x0, float x1, float x2, float *dst)
86967 {
86968     float m1 = x1*0.86602540f;
86969     float a1 = x0 - x2*0.5f;
86970     dst[1] = x0 + x2;
86971     dst[0] = a1 + m1;
86972     dst[2] = a1 - m1;
86973 }
86974 static void drmp3_L3_imdct12(float *x, float *dst, float *overlap)
86975 {
86976     static const float g_twid3[6] = { 0.79335334f,0.92387953f,0.99144486f, 0.60876143f,0.38268343f,0.13052619f };
86977     float co[3], si[3];
86978     int i;
86979     drmp3_L3_idct3(-x[0], x[6] + x[3], x[12] + x[9], co);
86980     drmp3_L3_idct3(x[15], x[12] - x[9], x[6] - x[3], si);
86981     si[1] = -si[1];
86982     for (i = 0; i < 3; i++)
86983     {
86984         float ovl  = overlap[i];
86985         float sum  = co[i]*g_twid3[3 + i] + si[i]*g_twid3[0 + i];
86986         overlap[i] = co[i]*g_twid3[0 + i] - si[i]*g_twid3[3 + i];
86987         dst[i]     = ovl*g_twid3[2 - i] - sum*g_twid3[5 - i];
86988         dst[5 - i] = ovl*g_twid3[5 - i] + sum*g_twid3[2 - i];
86989     }
86990 }
86991 static void drmp3_L3_imdct_short(float *grbuf, float *overlap, int nbands)
86992 {
86993     for (;nbands > 0; nbands--, overlap += 9, grbuf += 18)
86994     {
86995         float tmp[18];
86996         DRMP3_COPY_MEMORY(tmp, grbuf, sizeof(tmp));
86997         DRMP3_COPY_MEMORY(grbuf, overlap, 6*sizeof(float));
86998         drmp3_L3_imdct12(tmp, grbuf + 6, overlap + 6);
86999         drmp3_L3_imdct12(tmp + 1, grbuf + 12, overlap + 6);
87000         drmp3_L3_imdct12(tmp + 2, overlap, overlap + 6);
87001     }
87002 }
87003 static void drmp3_L3_change_sign(float *grbuf)
87004 {
87005     int b, i;
87006     for (b = 0, grbuf += 18; b < 32; b += 2, grbuf += 36)
87007         for (i = 1; i < 18; i += 2)
87008             grbuf[i] = -grbuf[i];
87009 }
87010 static void drmp3_L3_imdct_gr(float *grbuf, float *overlap, unsigned block_type, unsigned n_long_bands)
87011 {
87012     static const float g_mdct_window[2][18] = {
87013         { 0.99904822f,0.99144486f,0.97629601f,0.95371695f,0.92387953f,0.88701083f,0.84339145f,0.79335334f,0.73727734f,0.04361938f,0.13052619f,0.21643961f,0.30070580f,0.38268343f,0.46174861f,0.53729961f,0.60876143f,0.67559021f },
87014         { 1,1,1,1,1,1,0.99144486f,0.92387953f,0.79335334f,0,0,0,0,0,0,0.13052619f,0.38268343f,0.60876143f }
87015     };
87016     if (n_long_bands)
87017     {
87018         drmp3_L3_imdct36(grbuf, overlap, g_mdct_window[0], n_long_bands);
87019         grbuf += 18*n_long_bands;
87020         overlap += 9*n_long_bands;
87021     }
87022     if (block_type == DRMP3_SHORT_BLOCK_TYPE)
87023         drmp3_L3_imdct_short(grbuf, overlap, 32 - n_long_bands);
87024     else
87025         drmp3_L3_imdct36(grbuf, overlap, g_mdct_window[block_type == DRMP3_STOP_BLOCK_TYPE], 32 - n_long_bands);
87026 }
87027 static void drmp3_L3_save_reservoir(drmp3dec *h, drmp3dec_scratch *s)
87028 {
87029     int pos = (s->bs.pos + 7)/8u;
87030     int remains = s->bs.limit/8u - pos;
87031     if (remains > DRMP3_MAX_BITRESERVOIR_BYTES)
87032     {
87033         pos += remains - DRMP3_MAX_BITRESERVOIR_BYTES;
87034         remains = DRMP3_MAX_BITRESERVOIR_BYTES;
87035     }
87036     if (remains > 0)
87037     {
87038         DRMP3_MOVE_MEMORY(h->reserv_buf, s->maindata + pos, remains);
87039     }
87040     h->reserv = remains;
87041 }
87042 static int drmp3_L3_restore_reservoir(drmp3dec *h, drmp3_bs *bs, drmp3dec_scratch *s, int main_data_begin)
87043 {
87044     int frame_bytes = (bs->limit - bs->pos)/8;
87045     int bytes_have = DRMP3_MIN(h->reserv, main_data_begin);
87046     DRMP3_COPY_MEMORY(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin));
87047     DRMP3_COPY_MEMORY(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes);
87048     drmp3_bs_init(&s->bs, s->maindata, bytes_have + frame_bytes);
87049     return h->reserv >= main_data_begin;
87050 }
87051 static void drmp3_L3_decode(drmp3dec *h, drmp3dec_scratch *s, drmp3_L3_gr_info *gr_info, int nch)
87052 {
87053     int ch;
87054     for (ch = 0; ch < nch; ch++)
87055     {
87056         int layer3gr_limit = s->bs.pos + gr_info[ch].part_23_length;
87057         drmp3_L3_decode_scalefactors(h->header, s->ist_pos[ch], &s->bs, gr_info + ch, s->scf, ch);
87058         drmp3_L3_huffman(s->grbuf[ch], &s->bs, gr_info + ch, s->scf, layer3gr_limit);
87059     }
87060     if (DRMP3_HDR_TEST_I_STEREO(h->header))
87061     {
87062         drmp3_L3_intensity_stereo(s->grbuf[0], s->ist_pos[1], gr_info, h->header);
87063     } else if (DRMP3_HDR_IS_MS_STEREO(h->header))
87064     {
87065         drmp3_L3_midside_stereo(s->grbuf[0], 576);
87066     }
87067     for (ch = 0; ch < nch; ch++, gr_info++)
87068     {
87069         int aa_bands = 31;
87070         int n_long_bands = (gr_info->mixed_block_flag ? 2 : 0) << (int)(DRMP3_HDR_GET_MY_SAMPLE_RATE(h->header) == 2);
87071         if (gr_info->n_short_sfb)
87072         {
87073             aa_bands = n_long_bands - 1;
87074             drmp3_L3_reorder(s->grbuf[ch] + n_long_bands*18, s->syn[0], gr_info->sfbtab + gr_info->n_long_sfb);
87075         }
87076         drmp3_L3_antialias(s->grbuf[ch], aa_bands);
87077         drmp3_L3_imdct_gr(s->grbuf[ch], h->mdct_overlap[ch], gr_info->block_type, n_long_bands);
87078         drmp3_L3_change_sign(s->grbuf[ch]);
87079     }
87080 }
87081 static void drmp3d_DCT_II(float *grbuf, int n)
87082 {
87083     static const float g_sec[24] = {
87084         10.19000816f,0.50060302f,0.50241929f,3.40760851f,0.50547093f,0.52249861f,2.05778098f,0.51544732f,0.56694406f,1.48416460f,0.53104258f,0.64682180f,1.16943991f,0.55310392f,0.78815460f,0.97256821f,0.58293498f,1.06067765f,0.83934963f,0.62250412f,1.72244716f,0.74453628f,0.67480832f,5.10114861f
87085     };
87086     int i, k = 0;
87087 #if DRMP3_HAVE_SIMD
87088     if (drmp3_have_simd()) for (; k < n; k += 4)
87089     {
87090         drmp3_f4 t[4][8], *x;
87091         float *y = grbuf + k;
87092         for (x = t[0], i = 0; i < 8; i++, x++)
87093         {
87094             drmp3_f4 x0 = DRMP3_VLD(&y[i*18]);
87095             drmp3_f4 x1 = DRMP3_VLD(&y[(15 - i)*18]);
87096             drmp3_f4 x2 = DRMP3_VLD(&y[(16 + i)*18]);
87097             drmp3_f4 x3 = DRMP3_VLD(&y[(31 - i)*18]);
87098             drmp3_f4 t0 = DRMP3_VADD(x0, x3);
87099             drmp3_f4 t1 = DRMP3_VADD(x1, x2);
87100             drmp3_f4 t2 = DRMP3_VMUL_S(DRMP3_VSUB(x1, x2), g_sec[3*i + 0]);
87101             drmp3_f4 t3 = DRMP3_VMUL_S(DRMP3_VSUB(x0, x3), g_sec[3*i + 1]);
87102             x[0] = DRMP3_VADD(t0, t1);
87103             x[8] = DRMP3_VMUL_S(DRMP3_VSUB(t0, t1), g_sec[3*i + 2]);
87104             x[16] = DRMP3_VADD(t3, t2);
87105             x[24] = DRMP3_VMUL_S(DRMP3_VSUB(t3, t2), g_sec[3*i + 2]);
87106         }
87107         for (x = t[0], i = 0; i < 4; i++, x += 8)
87108         {
87109             drmp3_f4 x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt;
87110             xt = DRMP3_VSUB(x0, x7); x0 = DRMP3_VADD(x0, x7);
87111             x7 = DRMP3_VSUB(x1, x6); x1 = DRMP3_VADD(x1, x6);
87112             x6 = DRMP3_VSUB(x2, x5); x2 = DRMP3_VADD(x2, x5);
87113             x5 = DRMP3_VSUB(x3, x4); x3 = DRMP3_VADD(x3, x4);
87114             x4 = DRMP3_VSUB(x0, x3); x0 = DRMP3_VADD(x0, x3);
87115             x3 = DRMP3_VSUB(x1, x2); x1 = DRMP3_VADD(x1, x2);
87116             x[0] = DRMP3_VADD(x0, x1);
87117             x[4] = DRMP3_VMUL_S(DRMP3_VSUB(x0, x1), 0.70710677f);
87118             x5 = DRMP3_VADD(x5, x6);
87119             x6 = DRMP3_VMUL_S(DRMP3_VADD(x6, x7), 0.70710677f);
87120             x7 = DRMP3_VADD(x7, xt);
87121             x3 = DRMP3_VMUL_S(DRMP3_VADD(x3, x4), 0.70710677f);
87122             x5 = DRMP3_VSUB(x5, DRMP3_VMUL_S(x7, 0.198912367f));
87123             x7 = DRMP3_VADD(x7, DRMP3_VMUL_S(x5, 0.382683432f));
87124             x5 = DRMP3_VSUB(x5, DRMP3_VMUL_S(x7, 0.198912367f));
87125             x0 = DRMP3_VSUB(xt, x6); xt = DRMP3_VADD(xt, x6);
87126             x[1] = DRMP3_VMUL_S(DRMP3_VADD(xt, x7), 0.50979561f);
87127             x[2] = DRMP3_VMUL_S(DRMP3_VADD(x4, x3), 0.54119611f);
87128             x[3] = DRMP3_VMUL_S(DRMP3_VSUB(x0, x5), 0.60134488f);
87129             x[5] = DRMP3_VMUL_S(DRMP3_VADD(x0, x5), 0.89997619f);
87130             x[6] = DRMP3_VMUL_S(DRMP3_VSUB(x4, x3), 1.30656302f);
87131             x[7] = DRMP3_VMUL_S(DRMP3_VSUB(xt, x7), 2.56291556f);
87132         }
87133         if (k > n - 3)
87134         {
87135 #if DRMP3_HAVE_SSE
87136 #define DRMP3_VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v)
87137 #else
87138 #define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18],  vget_low_f32(v))
87139 #endif
87140             for (i = 0; i < 7; i++, y += 4*18)
87141             {
87142                 drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]);
87143                 DRMP3_VSAVE2(0, t[0][i]);
87144                 DRMP3_VSAVE2(1, DRMP3_VADD(t[2][i], s));
87145                 DRMP3_VSAVE2(2, DRMP3_VADD(t[1][i], t[1][i + 1]));
87146                 DRMP3_VSAVE2(3, DRMP3_VADD(t[2][1 + i], s));
87147             }
87148             DRMP3_VSAVE2(0, t[0][7]);
87149             DRMP3_VSAVE2(1, DRMP3_VADD(t[2][7], t[3][7]));
87150             DRMP3_VSAVE2(2, t[1][7]);
87151             DRMP3_VSAVE2(3, t[3][7]);
87152         } else
87153         {
87154 #define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[i*18], v)
87155             for (i = 0; i < 7; i++, y += 4*18)
87156             {
87157                 drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]);
87158                 DRMP3_VSAVE4(0, t[0][i]);
87159                 DRMP3_VSAVE4(1, DRMP3_VADD(t[2][i], s));
87160                 DRMP3_VSAVE4(2, DRMP3_VADD(t[1][i], t[1][i + 1]));
87161                 DRMP3_VSAVE4(3, DRMP3_VADD(t[2][1 + i], s));
87162             }
87163             DRMP3_VSAVE4(0, t[0][7]);
87164             DRMP3_VSAVE4(1, DRMP3_VADD(t[2][7], t[3][7]));
87165             DRMP3_VSAVE4(2, t[1][7]);
87166             DRMP3_VSAVE4(3, t[3][7]);
87167         }
87168     } else
87169 #endif
87170 #ifdef DR_MP3_ONLY_SIMD
87171     {}
87172 #else
87173     for (; k < n; k++)
87174     {
87175         float t[4][8], *x, *y = grbuf + k;
87176         for (x = t[0], i = 0; i < 8; i++, x++)
87177         {
87178             float x0 = y[i*18];
87179             float x1 = y[(15 - i)*18];
87180             float x2 = y[(16 + i)*18];
87181             float x3 = y[(31 - i)*18];
87182             float t0 = x0 + x3;
87183             float t1 = x1 + x2;
87184             float t2 = (x1 - x2)*g_sec[3*i + 0];
87185             float t3 = (x0 - x3)*g_sec[3*i + 1];
87186             x[0] = t0 + t1;
87187             x[8] = (t0 - t1)*g_sec[3*i + 2];
87188             x[16] = t3 + t2;
87189             x[24] = (t3 - t2)*g_sec[3*i + 2];
87190         }
87191         for (x = t[0], i = 0; i < 4; i++, x += 8)
87192         {
87193             float x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt;
87194             xt = x0 - x7; x0 += x7;
87195             x7 = x1 - x6; x1 += x6;
87196             x6 = x2 - x5; x2 += x5;
87197             x5 = x3 - x4; x3 += x4;
87198             x4 = x0 - x3; x0 += x3;
87199             x3 = x1 - x2; x1 += x2;
87200             x[0] = x0 + x1;
87201             x[4] = (x0 - x1)*0.70710677f;
87202             x5 =  x5 + x6;
87203             x6 = (x6 + x7)*0.70710677f;
87204             x7 =  x7 + xt;
87205             x3 = (x3 + x4)*0.70710677f;
87206             x5 -= x7*0.198912367f;
87207             x7 += x5*0.382683432f;
87208             x5 -= x7*0.198912367f;
87209             x0 = xt - x6; xt += x6;
87210             x[1] = (xt + x7)*0.50979561f;
87211             x[2] = (x4 + x3)*0.54119611f;
87212             x[3] = (x0 - x5)*0.60134488f;
87213             x[5] = (x0 + x5)*0.89997619f;
87214             x[6] = (x4 - x3)*1.30656302f;
87215             x[7] = (xt - x7)*2.56291556f;
87216         }
87217         for (i = 0; i < 7; i++, y += 4*18)
87218         {
87219             y[0*18] = t[0][i];
87220             y[1*18] = t[2][i] + t[3][i] + t[3][i + 1];
87221             y[2*18] = t[1][i] + t[1][i + 1];
87222             y[3*18] = t[2][i + 1] + t[3][i] + t[3][i + 1];
87223         }
87224         y[0*18] = t[0][7];
87225         y[1*18] = t[2][7] + t[3][7];
87226         y[2*18] = t[1][7];
87227         y[3*18] = t[3][7];
87228     }
87229 #endif
87230 }
87231 #ifndef DR_MP3_FLOAT_OUTPUT
87232 typedef drmp3_int16 drmp3d_sample_t;
87233 static drmp3_int16 drmp3d_scale_pcm(float sample)
87234 {
87235     drmp3_int16 s;
87236 #if DRMP3_HAVE_ARMV6
87237     drmp3_int32 s32 = (drmp3_int32)(sample + .5f);
87238     s32 -= (s32 < 0);
87239     s = (drmp3_int16)drmp3_clip_int16_arm(s32);
87240 #else
87241     if (sample >=  32766.5) return (drmp3_int16) 32767;
87242     if (sample <= -32767.5) return (drmp3_int16)-32768;
87243     s = (drmp3_int16)(sample + .5f);
87244     s -= (s < 0);
87245 #endif
87246     return s;
87247 }
87248 #else
87249 typedef float drmp3d_sample_t;
87250 static float drmp3d_scale_pcm(float sample)
87251 {
87252     return sample*(1.f/32768.f);
87253 }
87254 #endif
87255 static void drmp3d_synth_pair(drmp3d_sample_t *pcm, int nch, const float *z)
87256 {
87257     float a;
87258     a  = (z[14*64] - z[    0]) * 29;
87259     a += (z[ 1*64] + z[13*64]) * 213;
87260     a += (z[12*64] - z[ 2*64]) * 459;
87261     a += (z[ 3*64] + z[11*64]) * 2037;
87262     a += (z[10*64] - z[ 4*64]) * 5153;
87263     a += (z[ 5*64] + z[ 9*64]) * 6574;
87264     a += (z[ 8*64] - z[ 6*64]) * 37489;
87265     a +=  z[ 7*64]             * 75038;
87266     pcm[0] = drmp3d_scale_pcm(a);
87267     z += 2;
87268     a  = z[14*64] * 104;
87269     a += z[12*64] * 1567;
87270     a += z[10*64] * 9727;
87271     a += z[ 8*64] * 64019;
87272     a += z[ 6*64] * -9975;
87273     a += z[ 4*64] * -45;
87274     a += z[ 2*64] * 146;
87275     a += z[ 0*64] * -5;
87276     pcm[16*nch] = drmp3d_scale_pcm(a);
87277 }
87278 static void drmp3d_synth(float *xl, drmp3d_sample_t *dstl, int nch, float *lins)
87279 {
87280     int i;
87281     float *xr = xl + 576*(nch - 1);
87282     drmp3d_sample_t *dstr = dstl + (nch - 1);
87283     static const float g_win[] = {
87284         -1,26,-31,208,218,401,-519,2063,2000,4788,-5517,7134,5959,35640,-39336,74992,
87285         -1,24,-35,202,222,347,-581,2080,1952,4425,-5879,7640,5288,33791,-41176,74856,
87286         -1,21,-38,196,225,294,-645,2087,1893,4063,-6237,8092,4561,31947,-43006,74630,
87287         -1,19,-41,190,227,244,-711,2085,1822,3705,-6589,8492,3776,30112,-44821,74313,
87288         -1,17,-45,183,228,197,-779,2075,1739,3351,-6935,8840,2935,28289,-46617,73908,
87289         -1,16,-49,176,228,153,-848,2057,1644,3004,-7271,9139,2037,26482,-48390,73415,
87290         -2,14,-53,169,227,111,-919,2032,1535,2663,-7597,9389,1082,24694,-50137,72835,
87291         -2,13,-58,161,224,72,-991,2001,1414,2330,-7910,9592,70,22929,-51853,72169,
87292         -2,11,-63,154,221,36,-1064,1962,1280,2006,-8209,9750,-998,21189,-53534,71420,
87293         -2,10,-68,147,215,2,-1137,1919,1131,1692,-8491,9863,-2122,19478,-55178,70590,
87294         -3,9,-73,139,208,-29,-1210,1870,970,1388,-8755,9935,-3300,17799,-56778,69679,
87295         -3,8,-79,132,200,-57,-1283,1817,794,1095,-8998,9966,-4533,16155,-58333,68692,
87296         -4,7,-85,125,189,-83,-1356,1759,605,814,-9219,9959,-5818,14548,-59838,67629,
87297         -4,7,-91,117,177,-106,-1428,1698,402,545,-9416,9916,-7154,12980,-61289,66494,
87298         -5,6,-97,111,163,-127,-1498,1634,185,288,-9585,9838,-8540,11455,-62684,65290
87299     };
87300     float *zlin = lins + 15*64;
87301     const float *w = g_win;
87302     zlin[4*15]     = xl[18*16];
87303     zlin[4*15 + 1] = xr[18*16];
87304     zlin[4*15 + 2] = xl[0];
87305     zlin[4*15 + 3] = xr[0];
87306     zlin[4*31]     = xl[1 + 18*16];
87307     zlin[4*31 + 1] = xr[1 + 18*16];
87308     zlin[4*31 + 2] = xl[1];
87309     zlin[4*31 + 3] = xr[1];
87310     drmp3d_synth_pair(dstr, nch, lins + 4*15 + 1);
87311     drmp3d_synth_pair(dstr + 32*nch, nch, lins + 4*15 + 64 + 1);
87312     drmp3d_synth_pair(dstl, nch, lins + 4*15);
87313     drmp3d_synth_pair(dstl + 32*nch, nch, lins + 4*15 + 64);
87314 #if DRMP3_HAVE_SIMD
87315     if (drmp3_have_simd()) for (i = 14; i >= 0; i--)
87316     {
87317 #define DRMP3_VLOAD(k) drmp3_f4 w0 = DRMP3_VSET(*w++); drmp3_f4 w1 = DRMP3_VSET(*w++); drmp3_f4 vz = DRMP3_VLD(&zlin[4*i - 64*k]); drmp3_f4 vy = DRMP3_VLD(&zlin[4*i - 64*(15 - k)]);
87318 #define DRMP3_V0(k) { DRMP3_VLOAD(k) b =               DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0)) ; a =               DRMP3_VSUB(DRMP3_VMUL(vz, w0), DRMP3_VMUL(vy, w1));  }
87319 #define DRMP3_V1(k) { DRMP3_VLOAD(k) b = DRMP3_VADD(b, DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0))); a = DRMP3_VADD(a, DRMP3_VSUB(DRMP3_VMUL(vz, w0), DRMP3_VMUL(vy, w1))); }
87320 #define DRMP3_V2(k) { DRMP3_VLOAD(k) b = DRMP3_VADD(b, DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0))); a = DRMP3_VADD(a, DRMP3_VSUB(DRMP3_VMUL(vy, w1), DRMP3_VMUL(vz, w0))); }
87321         drmp3_f4 a, b;
87322         zlin[4*i]     = xl[18*(31 - i)];
87323         zlin[4*i + 1] = xr[18*(31 - i)];
87324         zlin[4*i + 2] = xl[1 + 18*(31 - i)];
87325         zlin[4*i + 3] = xr[1 + 18*(31 - i)];
87326         zlin[4*i + 64] = xl[1 + 18*(1 + i)];
87327         zlin[4*i + 64 + 1] = xr[1 + 18*(1 + i)];
87328         zlin[4*i - 64 + 2] = xl[18*(1 + i)];
87329         zlin[4*i - 64 + 3] = xr[18*(1 + i)];
87330         DRMP3_V0(0) DRMP3_V2(1) DRMP3_V1(2) DRMP3_V2(3) DRMP3_V1(4) DRMP3_V2(5) DRMP3_V1(6) DRMP3_V2(7)
87331         {
87332 #ifndef DR_MP3_FLOAT_OUTPUT
87333 #if DRMP3_HAVE_SSE
87334             static const drmp3_f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f };
87335             static const drmp3_f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f };
87336             __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)),
87337                                            _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min)));
87338             dstr[(15 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 1);
87339             dstr[(17 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 5);
87340             dstl[(15 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 0);
87341             dstl[(17 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 4);
87342             dstr[(47 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 3);
87343             dstr[(49 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 7);
87344             dstl[(47 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 2);
87345             dstl[(49 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 6);
87346 #else
87347             int16x4_t pcma, pcmb;
87348             a = DRMP3_VADD(a, DRMP3_VSET(0.5f));
87349             b = DRMP3_VADD(b, DRMP3_VSET(0.5f));
87350             pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, DRMP3_VSET(0)))));
87351             pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, DRMP3_VSET(0)))));
87352             vst1_lane_s16(dstr + (15 - i)*nch, pcma, 1);
87353             vst1_lane_s16(dstr + (17 + i)*nch, pcmb, 1);
87354             vst1_lane_s16(dstl + (15 - i)*nch, pcma, 0);
87355             vst1_lane_s16(dstl + (17 + i)*nch, pcmb, 0);
87356             vst1_lane_s16(dstr + (47 - i)*nch, pcma, 3);
87357             vst1_lane_s16(dstr + (49 + i)*nch, pcmb, 3);
87358             vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2);
87359             vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2);
87360 #endif
87361 #else
87362             static const drmp3_f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f };
87363             a = DRMP3_VMUL(a, g_scale);
87364             b = DRMP3_VMUL(b, g_scale);
87365 #if DRMP3_HAVE_SSE
87366             _mm_store_ss(dstr + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)));
87367             _mm_store_ss(dstr + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1)));
87368             _mm_store_ss(dstl + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)));
87369             _mm_store_ss(dstl + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 0, 0)));
87370             _mm_store_ss(dstr + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3)));
87371             _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3)));
87372             _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)));
87373             _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2)));
87374 #else
87375             vst1q_lane_f32(dstr + (15 - i)*nch, a, 1);
87376             vst1q_lane_f32(dstr + (17 + i)*nch, b, 1);
87377             vst1q_lane_f32(dstl + (15 - i)*nch, a, 0);
87378             vst1q_lane_f32(dstl + (17 + i)*nch, b, 0);
87379             vst1q_lane_f32(dstr + (47 - i)*nch, a, 3);
87380             vst1q_lane_f32(dstr + (49 + i)*nch, b, 3);
87381             vst1q_lane_f32(dstl + (47 - i)*nch, a, 2);
87382             vst1q_lane_f32(dstl + (49 + i)*nch, b, 2);
87383 #endif
87384 #endif
87385         }
87386     } else
87387 #endif
87388 #ifdef DR_MP3_ONLY_SIMD
87389     {}
87390 #else
87391     for (i = 14; i >= 0; i--)
87392     {
87393 #define DRMP3_LOAD(k) float w0 = *w++; float w1 = *w++; float *vz = &zlin[4*i - k*64]; float *vy = &zlin[4*i - (15 - k)*64];
87394 #define DRMP3_S0(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j]  = vz[j]*w1 + vy[j]*w0, a[j]  = vz[j]*w0 - vy[j]*w1; }
87395 #define DRMP3_S1(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vz[j]*w0 - vy[j]*w1; }
87396 #define DRMP3_S2(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vy[j]*w1 - vz[j]*w0; }
87397         float a[4], b[4];
87398         zlin[4*i]     = xl[18*(31 - i)];
87399         zlin[4*i + 1] = xr[18*(31 - i)];
87400         zlin[4*i + 2] = xl[1 + 18*(31 - i)];
87401         zlin[4*i + 3] = xr[1 + 18*(31 - i)];
87402         zlin[4*(i + 16)]   = xl[1 + 18*(1 + i)];
87403         zlin[4*(i + 16) + 1] = xr[1 + 18*(1 + i)];
87404         zlin[4*(i - 16) + 2] = xl[18*(1 + i)];
87405         zlin[4*(i - 16) + 3] = xr[18*(1 + i)];
87406         DRMP3_S0(0) DRMP3_S2(1) DRMP3_S1(2) DRMP3_S2(3) DRMP3_S1(4) DRMP3_S2(5) DRMP3_S1(6) DRMP3_S2(7)
87407         dstr[(15 - i)*nch] = drmp3d_scale_pcm(a[1]);
87408         dstr[(17 + i)*nch] = drmp3d_scale_pcm(b[1]);
87409         dstl[(15 - i)*nch] = drmp3d_scale_pcm(a[0]);
87410         dstl[(17 + i)*nch] = drmp3d_scale_pcm(b[0]);
87411         dstr[(47 - i)*nch] = drmp3d_scale_pcm(a[3]);
87412         dstr[(49 + i)*nch] = drmp3d_scale_pcm(b[3]);
87413         dstl[(47 - i)*nch] = drmp3d_scale_pcm(a[2]);
87414         dstl[(49 + i)*nch] = drmp3d_scale_pcm(b[2]);
87415     }
87416 #endif
87417 }
87418 static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, drmp3d_sample_t *pcm, float *lins)
87419 {
87420     int i;
87421     for (i = 0; i < nch; i++)
87422     {
87423         drmp3d_DCT_II(grbuf + 576*i, nbands);
87424     }
87425     DRMP3_COPY_MEMORY(lins, qmf_state, sizeof(float)*15*64);
87426     for (i = 0; i < nbands; i += 2)
87427     {
87428         drmp3d_synth(grbuf + i, pcm + 32*nch*i, nch, lins + i*64);
87429     }
87430 #ifndef DR_MP3_NONSTANDARD_BUT_LOGICAL
87431     if (nch == 1)
87432     {
87433         for (i = 0; i < 15*64; i += 2)
87434         {
87435             qmf_state[i] = lins[nbands*64 + i];
87436         }
87437     } else
87438 #endif
87439     {
87440         DRMP3_COPY_MEMORY(qmf_state, lins + nbands*64, sizeof(float)*15*64);
87441     }
87442 }
87443 static int drmp3d_match_frame(const drmp3_uint8 *hdr, int mp3_bytes, int frame_bytes)
87444 {
87445     int i, nmatch;
87446     for (i = 0, nmatch = 0; nmatch < DRMP3_MAX_FRAME_SYNC_MATCHES; nmatch++)
87447     {
87448         i += drmp3_hdr_frame_bytes(hdr + i, frame_bytes) + drmp3_hdr_padding(hdr + i);
87449         if (i + DRMP3_HDR_SIZE > mp3_bytes)
87450             return nmatch > 0;
87451         if (!drmp3_hdr_compare(hdr, hdr + i))
87452             return 0;
87453     }
87454     return 1;
87455 }
87456 static int drmp3d_find_frame(const drmp3_uint8 *mp3, int mp3_bytes, int *free_format_bytes, int *ptr_frame_bytes)
87457 {
87458     int i, k;
87459     for (i = 0; i < mp3_bytes - DRMP3_HDR_SIZE; i++, mp3++)
87460     {
87461         if (drmp3_hdr_valid(mp3))
87462         {
87463             int frame_bytes = drmp3_hdr_frame_bytes(mp3, *free_format_bytes);
87464             int frame_and_padding = frame_bytes + drmp3_hdr_padding(mp3);
87465             for (k = DRMP3_HDR_SIZE; !frame_bytes && k < DRMP3_MAX_FREE_FORMAT_FRAME_SIZE && i + 2*k < mp3_bytes - DRMP3_HDR_SIZE; k++)
87466             {
87467                 if (drmp3_hdr_compare(mp3, mp3 + k))
87468                 {
87469                     int fb = k - drmp3_hdr_padding(mp3);
87470                     int nextfb = fb + drmp3_hdr_padding(mp3 + k);
87471                     if (i + k + nextfb + DRMP3_HDR_SIZE > mp3_bytes || !drmp3_hdr_compare(mp3, mp3 + k + nextfb))
87472                         continue;
87473                     frame_and_padding = k;
87474                     frame_bytes = fb;
87475                     *free_format_bytes = fb;
87476                 }
87477             }
87478             if ((frame_bytes && i + frame_and_padding <= mp3_bytes &&
87479                 drmp3d_match_frame(mp3, mp3_bytes - i, frame_bytes)) ||
87480                 (!i && frame_and_padding == mp3_bytes))
87481             {
87482                 *ptr_frame_bytes = frame_and_padding;
87483                 return i;
87484             }
87485             *free_format_bytes = 0;
87486         }
87487     }
87488     *ptr_frame_bytes = 0;
87489     return mp3_bytes;
87490 }
87491 DRMP3_API void drmp3dec_init(drmp3dec *dec)
87492 {
87493     dec->header[0] = 0;
87494 }
87495 DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info)
87496 {
87497     int i = 0, igr, frame_size = 0, success = 1;
87498     const drmp3_uint8 *hdr;
87499     drmp3_bs bs_frame[1];
87500     drmp3dec_scratch scratch;
87501     if (mp3_bytes > 4 && dec->header[0] == 0xff && drmp3_hdr_compare(dec->header, mp3))
87502     {
87503         frame_size = drmp3_hdr_frame_bytes(mp3, dec->free_format_bytes) + drmp3_hdr_padding(mp3);
87504         if (frame_size != mp3_bytes && (frame_size + DRMP3_HDR_SIZE > mp3_bytes || !drmp3_hdr_compare(mp3, mp3 + frame_size)))
87505         {
87506             frame_size = 0;
87507         }
87508     }
87509     if (!frame_size)
87510     {
87511         DRMP3_ZERO_MEMORY(dec, sizeof(drmp3dec));
87512         i = drmp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size);
87513         if (!frame_size || i + frame_size > mp3_bytes)
87514         {
87515             info->frame_bytes = i;
87516             return 0;
87517         }
87518     }
87519     hdr = mp3 + i;
87520     DRMP3_COPY_MEMORY(dec->header, hdr, DRMP3_HDR_SIZE);
87521     info->frame_bytes = i + frame_size;
87522     info->channels = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2;
87523     info->hz = drmp3_hdr_sample_rate_hz(hdr);
87524     info->layer = 4 - DRMP3_HDR_GET_LAYER(hdr);
87525     info->bitrate_kbps = drmp3_hdr_bitrate_kbps(hdr);
87526     drmp3_bs_init(bs_frame, hdr + DRMP3_HDR_SIZE, frame_size - DRMP3_HDR_SIZE);
87527     if (DRMP3_HDR_IS_CRC(hdr))
87528     {
87529         drmp3_bs_get_bits(bs_frame, 16);
87530     }
87531     if (info->layer == 3)
87532     {
87533         int main_data_begin = drmp3_L3_read_side_info(bs_frame, scratch.gr_info, hdr);
87534         if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit)
87535         {
87536             drmp3dec_init(dec);
87537             return 0;
87538         }
87539         success = drmp3_L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin);
87540         if (success && pcm != NULL)
87541         {
87542             for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*576*info->channels))
87543             {
87544                 DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
87545                 drmp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels);
87546                 drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
87547             }
87548         }
87549         drmp3_L3_save_reservoir(dec, &scratch);
87550     } else
87551     {
87552 #ifdef DR_MP3_ONLY_MP3
87553         return 0;
87554 #else
87555         drmp3_L12_scale_info sci[1];
87556         if (pcm == NULL) {
87557             return drmp3_hdr_frame_samples(hdr);
87558         }
87559         drmp3_L12_read_scale_info(hdr, bs_frame, sci);
87560         DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
87561         for (i = 0, igr = 0; igr < 3; igr++)
87562         {
87563             if (12 == (i += drmp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1)))
87564             {
87565                 i = 0;
87566                 drmp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]);
87567                 drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
87568                 DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
87569                 pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels);
87570             }
87571             if (bs_frame->pos > bs_frame->limit)
87572             {
87573                 drmp3dec_init(dec);
87574                 return 0;
87575             }
87576         }
87577 #endif
87578     }
87579     return success*drmp3_hdr_frame_samples(dec->header);
87580 }
87581 DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num_samples)
87582 {
87583     size_t i = 0;
87584 #if DRMP3_HAVE_SIMD
87585     size_t aligned_count = num_samples & ~7;
87586     for(; i < aligned_count; i+=8)
87587     {
87588         drmp3_f4 scale = DRMP3_VSET(32768.0f);
87589         drmp3_f4 a = DRMP3_VMUL(DRMP3_VLD(&in[i  ]), scale);
87590         drmp3_f4 b = DRMP3_VMUL(DRMP3_VLD(&in[i+4]), scale);
87591 #if DRMP3_HAVE_SSE
87592         drmp3_f4 s16max = DRMP3_VSET( 32767.0f);
87593         drmp3_f4 s16min = DRMP3_VSET(-32768.0f);
87594         __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, s16max), s16min)),
87595                                         _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, s16max), s16min)));
87596         out[i  ] = (drmp3_int16)_mm_extract_epi16(pcm8, 0);
87597         out[i+1] = (drmp3_int16)_mm_extract_epi16(pcm8, 1);
87598         out[i+2] = (drmp3_int16)_mm_extract_epi16(pcm8, 2);
87599         out[i+3] = (drmp3_int16)_mm_extract_epi16(pcm8, 3);
87600         out[i+4] = (drmp3_int16)_mm_extract_epi16(pcm8, 4);
87601         out[i+5] = (drmp3_int16)_mm_extract_epi16(pcm8, 5);
87602         out[i+6] = (drmp3_int16)_mm_extract_epi16(pcm8, 6);
87603         out[i+7] = (drmp3_int16)_mm_extract_epi16(pcm8, 7);
87604 #else
87605         int16x4_t pcma, pcmb;
87606         a = DRMP3_VADD(a, DRMP3_VSET(0.5f));
87607         b = DRMP3_VADD(b, DRMP3_VSET(0.5f));
87608         pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, DRMP3_VSET(0)))));
87609         pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, DRMP3_VSET(0)))));
87610         vst1_lane_s16(out+i  , pcma, 0);
87611         vst1_lane_s16(out+i+1, pcma, 1);
87612         vst1_lane_s16(out+i+2, pcma, 2);
87613         vst1_lane_s16(out+i+3, pcma, 3);
87614         vst1_lane_s16(out+i+4, pcmb, 0);
87615         vst1_lane_s16(out+i+5, pcmb, 1);
87616         vst1_lane_s16(out+i+6, pcmb, 2);
87617         vst1_lane_s16(out+i+7, pcmb, 3);
87618 #endif
87619     }
87620 #endif
87621     for(; i < num_samples; i++)
87622     {
87623         float sample = in[i] * 32768.0f;
87624         if (sample >=  32766.5)
87625             out[i] = (drmp3_int16) 32767;
87626         else if (sample <= -32767.5)
87627             out[i] = (drmp3_int16)-32768;
87628         else
87629         {
87630             short s = (drmp3_int16)(sample + .5f);
87631             s -= (s < 0);
87632             out[i] = s;
87633         }
87634     }
87635 }
87636 #include <math.h>
87637 #if defined(SIZE_MAX)
87638     #define DRMP3_SIZE_MAX  SIZE_MAX
87639 #else
87640     #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
87641         #define DRMP3_SIZE_MAX  ((drmp3_uint64)0xFFFFFFFFFFFFFFFF)
87642     #else
87643         #define DRMP3_SIZE_MAX  0xFFFFFFFF
87644     #endif
87645 #endif
87646 #ifndef DRMP3_SEEK_LEADING_MP3_FRAMES
87647 #define DRMP3_SEEK_LEADING_MP3_FRAMES   2
87648 #endif
87649 #define DRMP3_MIN_DATA_CHUNK_SIZE   16384
87650 #ifndef DRMP3_DATA_CHUNK_SIZE
87651 #define DRMP3_DATA_CHUNK_SIZE  DRMP3_MIN_DATA_CHUNK_SIZE*4
87652 #endif
87653 #define DRMP3_COUNTOF(x)        (sizeof(x) / sizeof(x[0]))
87654 #define DRMP3_CLAMP(x, lo, hi)  (DRMP3_MAX(lo, DRMP3_MIN(x, hi)))
87655 #ifndef DRMP3_PI_D
87656 #define DRMP3_PI_D    3.14159265358979323846264
87657 #endif
87658 #define DRMP3_DEFAULT_RESAMPLER_LPF_ORDER   2
87659 static DRMP3_INLINE float drmp3_mix_f32(float x, float y, float a)
87660 {
87661     return x*(1-a) + y*a;
87662 }
87663 static DRMP3_INLINE float drmp3_mix_f32_fast(float x, float y, float a)
87664 {
87665     float r0 = (y - x);
87666     float r1 = r0*a;
87667     return x + r1;
87668 }
87669 static DRMP3_INLINE drmp3_uint32 drmp3_gcf_u32(drmp3_uint32 a, drmp3_uint32 b)
87670 {
87671     for (;;) {
87672         if (b == 0) {
87673             break;
87674         } else {
87675             drmp3_uint32 t = a;
87676             a = b;
87677             b = t % a;
87678         }
87679     }
87680     return a;
87681 }
87682 static DRMP3_INLINE double drmp3_sin(double x)
87683 {
87684     return sin(x);
87685 }
87686 static DRMP3_INLINE double drmp3_exp(double x)
87687 {
87688     return exp(x);
87689 }
87690 static DRMP3_INLINE double drmp3_cos(double x)
87691 {
87692     return drmp3_sin((DRMP3_PI_D*0.5) - x);
87693 }
87694 static void* drmp3__malloc_default(size_t sz, void* pUserData)
87695 {
87696     (void)pUserData;
87697     return DRMP3_MALLOC(sz);
87698 }
87699 static void* drmp3__realloc_default(void* p, size_t sz, void* pUserData)
87700 {
87701     (void)pUserData;
87702     return DRMP3_REALLOC(p, sz);
87703 }
87704 static void drmp3__free_default(void* p, void* pUserData)
87705 {
87706     (void)pUserData;
87707     DRMP3_FREE(p);
87708 }
87709 static void* drmp3__malloc_from_callbacks(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks)
87710 {
87711     if (pAllocationCallbacks == NULL) {
87712         return NULL;
87713     }
87714     if (pAllocationCallbacks->onMalloc != NULL) {
87715         return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
87716     }
87717     if (pAllocationCallbacks->onRealloc != NULL) {
87718         return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
87719     }
87720     return NULL;
87721 }
87722 static void* drmp3__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drmp3_allocation_callbacks* pAllocationCallbacks)
87723 {
87724     if (pAllocationCallbacks == NULL) {
87725         return NULL;
87726     }
87727     if (pAllocationCallbacks->onRealloc != NULL) {
87728         return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
87729     }
87730     if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
87731         void* p2;
87732         p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
87733         if (p2 == NULL) {
87734             return NULL;
87735         }
87736         if (p != NULL) {
87737             DRMP3_COPY_MEMORY(p2, p, szOld);
87738             pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
87739         }
87740         return p2;
87741     }
87742     return NULL;
87743 }
87744 static void drmp3__free_from_callbacks(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks)
87745 {
87746     if (p == NULL || pAllocationCallbacks == NULL) {
87747         return;
87748     }
87749     if (pAllocationCallbacks->onFree != NULL) {
87750         pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
87751     }
87752 }
87753 static drmp3_allocation_callbacks drmp3_copy_allocation_callbacks_or_defaults(const drmp3_allocation_callbacks* pAllocationCallbacks)
87754 {
87755     if (pAllocationCallbacks != NULL) {
87756         return *pAllocationCallbacks;
87757     } else {
87758         drmp3_allocation_callbacks allocationCallbacks;
87759         allocationCallbacks.pUserData = NULL;
87760         allocationCallbacks.onMalloc  = drmp3__malloc_default;
87761         allocationCallbacks.onRealloc = drmp3__realloc_default;
87762         allocationCallbacks.onFree    = drmp3__free_default;
87763         return allocationCallbacks;
87764     }
87765 }
87766 static size_t drmp3__on_read(drmp3* pMP3, void* pBufferOut, size_t bytesToRead)
87767 {
87768     size_t bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead);
87769     pMP3->streamCursor += bytesRead;
87770     return bytesRead;
87771 }
87772 static drmp3_bool32 drmp3__on_seek(drmp3* pMP3, int offset, drmp3_seek_origin origin)
87773 {
87774     DRMP3_ASSERT(offset >= 0);
87775     if (!pMP3->onSeek(pMP3->pUserData, offset, origin)) {
87776         return DRMP3_FALSE;
87777     }
87778     if (origin == drmp3_seek_origin_start) {
87779         pMP3->streamCursor = (drmp3_uint64)offset;
87780     } else {
87781         pMP3->streamCursor += offset;
87782     }
87783     return DRMP3_TRUE;
87784 }
87785 static drmp3_bool32 drmp3__on_seek_64(drmp3* pMP3, drmp3_uint64 offset, drmp3_seek_origin origin)
87786 {
87787     if (offset <= 0x7FFFFFFF) {
87788         return drmp3__on_seek(pMP3, (int)offset, origin);
87789     }
87790     if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_start)) {
87791         return DRMP3_FALSE;
87792     }
87793     offset -= 0x7FFFFFFF;
87794     while (offset > 0) {
87795         if (offset <= 0x7FFFFFFF) {
87796             if (!drmp3__on_seek(pMP3, (int)offset, drmp3_seek_origin_current)) {
87797                 return DRMP3_FALSE;
87798             }
87799             offset = 0;
87800         } else {
87801             if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_current)) {
87802                 return DRMP3_FALSE;
87803             }
87804             offset -= 0x7FFFFFFF;
87805         }
87806     }
87807     return DRMP3_TRUE;
87808 }
87809 static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
87810 {
87811     drmp3_uint32 pcmFramesRead = 0;
87812     DRMP3_ASSERT(pMP3 != NULL);
87813     DRMP3_ASSERT(pMP3->onRead != NULL);
87814     if (pMP3->atEnd) {
87815         return 0;
87816     }
87817     for (;;) {
87818         drmp3dec_frame_info info;
87819         if (pMP3->dataSize < DRMP3_MIN_DATA_CHUNK_SIZE) {
87820             size_t bytesRead;
87821             if (pMP3->pData != NULL) {
87822                 DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
87823             }
87824             pMP3->dataConsumed = 0;
87825             if (pMP3->dataCapacity < DRMP3_DATA_CHUNK_SIZE) {
87826                 drmp3_uint8* pNewData;
87827                 size_t newDataCap;
87828                 newDataCap = DRMP3_DATA_CHUNK_SIZE;
87829                 pNewData = (drmp3_uint8*)drmp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks);
87830                 if (pNewData == NULL) {
87831                     return 0;
87832                 }
87833                 pMP3->pData = pNewData;
87834                 pMP3->dataCapacity = newDataCap;
87835             }
87836             bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
87837             if (bytesRead == 0) {
87838                 if (pMP3->dataSize == 0) {
87839                     pMP3->atEnd = DRMP3_TRUE;
87840                     return 0;
87841                 }
87842             }
87843             pMP3->dataSize += bytesRead;
87844         }
87845         if (pMP3->dataSize > INT_MAX) {
87846             pMP3->atEnd = DRMP3_TRUE;
87847             return 0;
87848         }
87849         DRMP3_ASSERT(pMP3->pData != NULL);
87850         DRMP3_ASSERT(pMP3->dataCapacity > 0);
87851         pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info);
87852         if (info.frame_bytes > 0) {
87853             pMP3->dataConsumed += (size_t)info.frame_bytes;
87854             pMP3->dataSize     -= (size_t)info.frame_bytes;
87855         }
87856         if (pcmFramesRead > 0) {
87857             pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header);
87858             pMP3->pcmFramesConsumedInMP3Frame = 0;
87859             pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead;
87860             pMP3->mp3FrameChannels = info.channels;
87861             pMP3->mp3FrameSampleRate = info.hz;
87862             break;
87863         } else if (info.frame_bytes == 0) {
87864             size_t bytesRead;
87865             DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
87866             pMP3->dataConsumed = 0;
87867             if (pMP3->dataCapacity == pMP3->dataSize) {
87868                 drmp3_uint8* pNewData;
87869                 size_t newDataCap;
87870                 newDataCap = pMP3->dataCapacity + DRMP3_DATA_CHUNK_SIZE;
87871                 pNewData = (drmp3_uint8*)drmp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks);
87872                 if (pNewData == NULL) {
87873                     return 0;
87874                 }
87875                 pMP3->pData = pNewData;
87876                 pMP3->dataCapacity = newDataCap;
87877             }
87878             bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
87879             if (bytesRead == 0) {
87880                 pMP3->atEnd = DRMP3_TRUE;
87881                 return 0;
87882             }
87883             pMP3->dataSize += bytesRead;
87884         }
87885     };
87886     return pcmFramesRead;
87887 }
87888 static drmp3_uint32 drmp3_decode_next_frame_ex__memory(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
87889 {
87890     drmp3_uint32 pcmFramesRead = 0;
87891     drmp3dec_frame_info info;
87892     DRMP3_ASSERT(pMP3 != NULL);
87893     DRMP3_ASSERT(pMP3->memory.pData != NULL);
87894     if (pMP3->atEnd) {
87895         return 0;
87896     }
87897     for (;;) {
87898         pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info);
87899         if (pcmFramesRead > 0) {
87900             pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header);
87901             pMP3->pcmFramesConsumedInMP3Frame  = 0;
87902             pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead;
87903             pMP3->mp3FrameChannels             = info.channels;
87904             pMP3->mp3FrameSampleRate           = info.hz;
87905             break;
87906         } else if (info.frame_bytes > 0) {
87907             pMP3->memory.currentReadPos += (size_t)info.frame_bytes;
87908         } else {
87909             break;
87910         }
87911     }
87912     pMP3->memory.currentReadPos += (size_t)info.frame_bytes;
87913     return pcmFramesRead;
87914 }
87915 static drmp3_uint32 drmp3_decode_next_frame_ex(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
87916 {
87917     if (pMP3->memory.pData != NULL && pMP3->memory.dataSize > 0) {
87918         return drmp3_decode_next_frame_ex__memory(pMP3, pPCMFrames);
87919     } else {
87920         return drmp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames);
87921     }
87922 }
87923 static drmp3_uint32 drmp3_decode_next_frame(drmp3* pMP3)
87924 {
87925     DRMP3_ASSERT(pMP3 != NULL);
87926     return drmp3_decode_next_frame_ex(pMP3, (drmp3d_sample_t*)pMP3->pcmFrames);
87927 }
87928 #if 0
87929 static drmp3_uint32 drmp3_seek_next_frame(drmp3* pMP3)
87930 {
87931     drmp3_uint32 pcmFrameCount;
87932     DRMP3_ASSERT(pMP3 != NULL);
87933     pcmFrameCount = drmp3_decode_next_frame_ex(pMP3, NULL);
87934     if (pcmFrameCount == 0) {
87935         return 0;
87936     }
87937     pMP3->currentPCMFrame             += pcmFrameCount;
87938     pMP3->pcmFramesConsumedInMP3Frame  = pcmFrameCount;
87939     pMP3->pcmFramesRemainingInMP3Frame = 0;
87940     return pcmFrameCount;
87941 }
87942 #endif
87943 static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks)
87944 {
87945     DRMP3_ASSERT(pMP3 != NULL);
87946     DRMP3_ASSERT(onRead != NULL);
87947     drmp3dec_init(&pMP3->decoder);
87948     pMP3->onRead = onRead;
87949     pMP3->onSeek = onSeek;
87950     pMP3->pUserData = pUserData;
87951     pMP3->allocationCallbacks = drmp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
87952     if (pMP3->allocationCallbacks.onFree == NULL || (pMP3->allocationCallbacks.onMalloc == NULL && pMP3->allocationCallbacks.onRealloc == NULL)) {
87953         return DRMP3_FALSE;
87954     }
87955     if (drmp3_decode_next_frame(pMP3) == 0) {
87956         drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks);
87957         return DRMP3_FALSE;
87958     }
87959     pMP3->channels   = pMP3->mp3FrameChannels;
87960     pMP3->sampleRate = pMP3->mp3FrameSampleRate;
87961     return DRMP3_TRUE;
87962 }
87963 DRMP3_API drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks)
87964 {
87965     if (pMP3 == NULL || onRead == NULL) {
87966         return DRMP3_FALSE;
87967     }
87968     DRMP3_ZERO_OBJECT(pMP3);
87969     return drmp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks);
87970 }
87971 static size_t drmp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
87972 {
87973     drmp3* pMP3 = (drmp3*)pUserData;
87974     size_t bytesRemaining;
87975     DRMP3_ASSERT(pMP3 != NULL);
87976     DRMP3_ASSERT(pMP3->memory.dataSize >= pMP3->memory.currentReadPos);
87977     bytesRemaining = pMP3->memory.dataSize - pMP3->memory.currentReadPos;
87978     if (bytesToRead > bytesRemaining) {
87979         bytesToRead = bytesRemaining;
87980     }
87981     if (bytesToRead > 0) {
87982         DRMP3_COPY_MEMORY(pBufferOut, pMP3->memory.pData + pMP3->memory.currentReadPos, bytesToRead);
87983         pMP3->memory.currentReadPos += bytesToRead;
87984     }
87985     return bytesToRead;
87986 }
87987 static drmp3_bool32 drmp3__on_seek_memory(void* pUserData, int byteOffset, drmp3_seek_origin origin)
87988 {
87989     drmp3* pMP3 = (drmp3*)pUserData;
87990     DRMP3_ASSERT(pMP3 != NULL);
87991     if (origin == drmp3_seek_origin_current) {
87992         if (byteOffset > 0) {
87993             if (pMP3->memory.currentReadPos + byteOffset > pMP3->memory.dataSize) {
87994                 byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos);
87995             }
87996         } else {
87997             if (pMP3->memory.currentReadPos < (size_t)-byteOffset) {
87998                 byteOffset = -(int)pMP3->memory.currentReadPos;
87999             }
88000         }
88001         pMP3->memory.currentReadPos += byteOffset;
88002     } else {
88003         if ((drmp3_uint32)byteOffset <= pMP3->memory.dataSize) {
88004             pMP3->memory.currentReadPos = byteOffset;
88005         } else {
88006             pMP3->memory.currentReadPos = pMP3->memory.dataSize;
88007         }
88008     }
88009     return DRMP3_TRUE;
88010 }
88011 DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_allocation_callbacks* pAllocationCallbacks)
88012 {
88013     if (pMP3 == NULL) {
88014         return DRMP3_FALSE;
88015     }
88016     DRMP3_ZERO_OBJECT(pMP3);
88017     if (pData == NULL || dataSize == 0) {
88018         return DRMP3_FALSE;
88019     }
88020     pMP3->memory.pData = (const drmp3_uint8*)pData;
88021     pMP3->memory.dataSize = dataSize;
88022     pMP3->memory.currentReadPos = 0;
88023     return drmp3_init_internal(pMP3, drmp3__on_read_memory, drmp3__on_seek_memory, pMP3, pAllocationCallbacks);
88024 }
88025 #ifndef DR_MP3_NO_STDIO
88026 #include <stdio.h>
88027 #include <wchar.h>
88028 #include <errno.h>
88029 static drmp3_result drmp3_result_from_errno(int e)
88030 {
88031     switch (e)
88032     {
88033         case 0: return DRMP3_SUCCESS;
88034     #ifdef EPERM
88035         case EPERM: return DRMP3_INVALID_OPERATION;
88036     #endif
88037     #ifdef ENOENT
88038         case ENOENT: return DRMP3_DOES_NOT_EXIST;
88039     #endif
88040     #ifdef ESRCH
88041         case ESRCH: return DRMP3_DOES_NOT_EXIST;
88042     #endif
88043     #ifdef EINTR
88044         case EINTR: return DRMP3_INTERRUPT;
88045     #endif
88046     #ifdef EIO
88047         case EIO: return DRMP3_IO_ERROR;
88048     #endif
88049     #ifdef ENXIO
88050         case ENXIO: return DRMP3_DOES_NOT_EXIST;
88051     #endif
88052     #ifdef E2BIG
88053         case E2BIG: return DRMP3_INVALID_ARGS;
88054     #endif
88055     #ifdef ENOEXEC
88056         case ENOEXEC: return DRMP3_INVALID_FILE;
88057     #endif
88058     #ifdef EBADF
88059         case EBADF: return DRMP3_INVALID_FILE;
88060     #endif
88061     #ifdef ECHILD
88062         case ECHILD: return DRMP3_ERROR;
88063     #endif
88064     #ifdef EAGAIN
88065         case EAGAIN: return DRMP3_UNAVAILABLE;
88066     #endif
88067     #ifdef ENOMEM
88068         case ENOMEM: return DRMP3_OUT_OF_MEMORY;
88069     #endif
88070     #ifdef EACCES
88071         case EACCES: return DRMP3_ACCESS_DENIED;
88072     #endif
88073     #ifdef EFAULT
88074         case EFAULT: return DRMP3_BAD_ADDRESS;
88075     #endif
88076     #ifdef ENOTBLK
88077         case ENOTBLK: return DRMP3_ERROR;
88078     #endif
88079     #ifdef EBUSY
88080         case EBUSY: return DRMP3_BUSY;
88081     #endif
88082     #ifdef EEXIST
88083         case EEXIST: return DRMP3_ALREADY_EXISTS;
88084     #endif
88085     #ifdef EXDEV
88086         case EXDEV: return DRMP3_ERROR;
88087     #endif
88088     #ifdef ENODEV
88089         case ENODEV: return DRMP3_DOES_NOT_EXIST;
88090     #endif
88091     #ifdef ENOTDIR
88092         case ENOTDIR: return DRMP3_NOT_DIRECTORY;
88093     #endif
88094     #ifdef EISDIR
88095         case EISDIR: return DRMP3_IS_DIRECTORY;
88096     #endif
88097     #ifdef EINVAL
88098         case EINVAL: return DRMP3_INVALID_ARGS;
88099     #endif
88100     #ifdef ENFILE
88101         case ENFILE: return DRMP3_TOO_MANY_OPEN_FILES;
88102     #endif
88103     #ifdef EMFILE
88104         case EMFILE: return DRMP3_TOO_MANY_OPEN_FILES;
88105     #endif
88106     #ifdef ENOTTY
88107         case ENOTTY: return DRMP3_INVALID_OPERATION;
88108     #endif
88109     #ifdef ETXTBSY
88110         case ETXTBSY: return DRMP3_BUSY;
88111     #endif
88112     #ifdef EFBIG
88113         case EFBIG: return DRMP3_TOO_BIG;
88114     #endif
88115     #ifdef ENOSPC
88116         case ENOSPC: return DRMP3_NO_SPACE;
88117     #endif
88118     #ifdef ESPIPE
88119         case ESPIPE: return DRMP3_BAD_SEEK;
88120     #endif
88121     #ifdef EROFS
88122         case EROFS: return DRMP3_ACCESS_DENIED;
88123     #endif
88124     #ifdef EMLINK
88125         case EMLINK: return DRMP3_TOO_MANY_LINKS;
88126     #endif
88127     #ifdef EPIPE
88128         case EPIPE: return DRMP3_BAD_PIPE;
88129     #endif
88130     #ifdef EDOM
88131         case EDOM: return DRMP3_OUT_OF_RANGE;
88132     #endif
88133     #ifdef ERANGE
88134         case ERANGE: return DRMP3_OUT_OF_RANGE;
88135     #endif
88136     #ifdef EDEADLK
88137         case EDEADLK: return DRMP3_DEADLOCK;
88138     #endif
88139     #ifdef ENAMETOOLONG
88140         case ENAMETOOLONG: return DRMP3_PATH_TOO_LONG;
88141     #endif
88142     #ifdef ENOLCK
88143         case ENOLCK: return DRMP3_ERROR;
88144     #endif
88145     #ifdef ENOSYS
88146         case ENOSYS: return DRMP3_NOT_IMPLEMENTED;
88147     #endif
88148     #ifdef ENOTEMPTY
88149         case ENOTEMPTY: return DRMP3_DIRECTORY_NOT_EMPTY;
88150     #endif
88151     #ifdef ELOOP
88152         case ELOOP: return DRMP3_TOO_MANY_LINKS;
88153     #endif
88154     #ifdef ENOMSG
88155         case ENOMSG: return DRMP3_NO_MESSAGE;
88156     #endif
88157     #ifdef EIDRM
88158         case EIDRM: return DRMP3_ERROR;
88159     #endif
88160     #ifdef ECHRNG
88161         case ECHRNG: return DRMP3_ERROR;
88162     #endif
88163     #ifdef EL2NSYNC
88164         case EL2NSYNC: return DRMP3_ERROR;
88165     #endif
88166     #ifdef EL3HLT
88167         case EL3HLT: return DRMP3_ERROR;
88168     #endif
88169     #ifdef EL3RST
88170         case EL3RST: return DRMP3_ERROR;
88171     #endif
88172     #ifdef ELNRNG
88173         case ELNRNG: return DRMP3_OUT_OF_RANGE;
88174     #endif
88175     #ifdef EUNATCH
88176         case EUNATCH: return DRMP3_ERROR;
88177     #endif
88178     #ifdef ENOCSI
88179         case ENOCSI: return DRMP3_ERROR;
88180     #endif
88181     #ifdef EL2HLT
88182         case EL2HLT: return DRMP3_ERROR;
88183     #endif
88184     #ifdef EBADE
88185         case EBADE: return DRMP3_ERROR;
88186     #endif
88187     #ifdef EBADR
88188         case EBADR: return DRMP3_ERROR;
88189     #endif
88190     #ifdef EXFULL
88191         case EXFULL: return DRMP3_ERROR;
88192     #endif
88193     #ifdef ENOANO
88194         case ENOANO: return DRMP3_ERROR;
88195     #endif
88196     #ifdef EBADRQC
88197         case EBADRQC: return DRMP3_ERROR;
88198     #endif
88199     #ifdef EBADSLT
88200         case EBADSLT: return DRMP3_ERROR;
88201     #endif
88202     #ifdef EBFONT
88203         case EBFONT: return DRMP3_INVALID_FILE;
88204     #endif
88205     #ifdef ENOSTR
88206         case ENOSTR: return DRMP3_ERROR;
88207     #endif
88208     #ifdef ENODATA
88209         case ENODATA: return DRMP3_NO_DATA_AVAILABLE;
88210     #endif
88211     #ifdef ETIME
88212         case ETIME: return DRMP3_TIMEOUT;
88213     #endif
88214     #ifdef ENOSR
88215         case ENOSR: return DRMP3_NO_DATA_AVAILABLE;
88216     #endif
88217     #ifdef ENONET
88218         case ENONET: return DRMP3_NO_NETWORK;
88219     #endif
88220     #ifdef ENOPKG
88221         case ENOPKG: return DRMP3_ERROR;
88222     #endif
88223     #ifdef EREMOTE
88224         case EREMOTE: return DRMP3_ERROR;
88225     #endif
88226     #ifdef ENOLINK
88227         case ENOLINK: return DRMP3_ERROR;
88228     #endif
88229     #ifdef EADV
88230         case EADV: return DRMP3_ERROR;
88231     #endif
88232     #ifdef ESRMNT
88233         case ESRMNT: return DRMP3_ERROR;
88234     #endif
88235     #ifdef ECOMM
88236         case ECOMM: return DRMP3_ERROR;
88237     #endif
88238     #ifdef EPROTO
88239         case EPROTO: return DRMP3_ERROR;
88240     #endif
88241     #ifdef EMULTIHOP
88242         case EMULTIHOP: return DRMP3_ERROR;
88243     #endif
88244     #ifdef EDOTDOT
88245         case EDOTDOT: return DRMP3_ERROR;
88246     #endif
88247     #ifdef EBADMSG
88248         case EBADMSG: return DRMP3_BAD_MESSAGE;
88249     #endif
88250     #ifdef EOVERFLOW
88251         case EOVERFLOW: return DRMP3_TOO_BIG;
88252     #endif
88253     #ifdef ENOTUNIQ
88254         case ENOTUNIQ: return DRMP3_NOT_UNIQUE;
88255     #endif
88256     #ifdef EBADFD
88257         case EBADFD: return DRMP3_ERROR;
88258     #endif
88259     #ifdef EREMCHG
88260         case EREMCHG: return DRMP3_ERROR;
88261     #endif
88262     #ifdef ELIBACC
88263         case ELIBACC: return DRMP3_ACCESS_DENIED;
88264     #endif
88265     #ifdef ELIBBAD
88266         case ELIBBAD: return DRMP3_INVALID_FILE;
88267     #endif
88268     #ifdef ELIBSCN
88269         case ELIBSCN: return DRMP3_INVALID_FILE;
88270     #endif
88271     #ifdef ELIBMAX
88272         case ELIBMAX: return DRMP3_ERROR;
88273     #endif
88274     #ifdef ELIBEXEC
88275         case ELIBEXEC: return DRMP3_ERROR;
88276     #endif
88277     #ifdef EILSEQ
88278         case EILSEQ: return DRMP3_INVALID_DATA;
88279     #endif
88280     #ifdef ERESTART
88281         case ERESTART: return DRMP3_ERROR;
88282     #endif
88283     #ifdef ESTRPIPE
88284         case ESTRPIPE: return DRMP3_ERROR;
88285     #endif
88286     #ifdef EUSERS
88287         case EUSERS: return DRMP3_ERROR;
88288     #endif
88289     #ifdef ENOTSOCK
88290         case ENOTSOCK: return DRMP3_NOT_SOCKET;
88291     #endif
88292     #ifdef EDESTADDRREQ
88293         case EDESTADDRREQ: return DRMP3_NO_ADDRESS;
88294     #endif
88295     #ifdef EMSGSIZE
88296         case EMSGSIZE: return DRMP3_TOO_BIG;
88297     #endif
88298     #ifdef EPROTOTYPE
88299         case EPROTOTYPE: return DRMP3_BAD_PROTOCOL;
88300     #endif
88301     #ifdef ENOPROTOOPT
88302         case ENOPROTOOPT: return DRMP3_PROTOCOL_UNAVAILABLE;
88303     #endif
88304     #ifdef EPROTONOSUPPORT
88305         case EPROTONOSUPPORT: return DRMP3_PROTOCOL_NOT_SUPPORTED;
88306     #endif
88307     #ifdef ESOCKTNOSUPPORT
88308         case ESOCKTNOSUPPORT: return DRMP3_SOCKET_NOT_SUPPORTED;
88309     #endif
88310     #ifdef EOPNOTSUPP
88311         case EOPNOTSUPP: return DRMP3_INVALID_OPERATION;
88312     #endif
88313     #ifdef EPFNOSUPPORT
88314         case EPFNOSUPPORT: return DRMP3_PROTOCOL_FAMILY_NOT_SUPPORTED;
88315     #endif
88316     #ifdef EAFNOSUPPORT
88317         case EAFNOSUPPORT: return DRMP3_ADDRESS_FAMILY_NOT_SUPPORTED;
88318     #endif
88319     #ifdef EADDRINUSE
88320         case EADDRINUSE: return DRMP3_ALREADY_IN_USE;
88321     #endif
88322     #ifdef EADDRNOTAVAIL
88323         case EADDRNOTAVAIL: return DRMP3_ERROR;
88324     #endif
88325     #ifdef ENETDOWN
88326         case ENETDOWN: return DRMP3_NO_NETWORK;
88327     #endif
88328     #ifdef ENETUNREACH
88329         case ENETUNREACH: return DRMP3_NO_NETWORK;
88330     #endif
88331     #ifdef ENETRESET
88332         case ENETRESET: return DRMP3_NO_NETWORK;
88333     #endif
88334     #ifdef ECONNABORTED
88335         case ECONNABORTED: return DRMP3_NO_NETWORK;
88336     #endif
88337     #ifdef ECONNRESET
88338         case ECONNRESET: return DRMP3_CONNECTION_RESET;
88339     #endif
88340     #ifdef ENOBUFS
88341         case ENOBUFS: return DRMP3_NO_SPACE;
88342     #endif
88343     #ifdef EISCONN
88344         case EISCONN: return DRMP3_ALREADY_CONNECTED;
88345     #endif
88346     #ifdef ENOTCONN
88347         case ENOTCONN: return DRMP3_NOT_CONNECTED;
88348     #endif
88349     #ifdef ESHUTDOWN
88350         case ESHUTDOWN: return DRMP3_ERROR;
88351     #endif
88352     #ifdef ETOOMANYREFS
88353         case ETOOMANYREFS: return DRMP3_ERROR;
88354     #endif
88355     #ifdef ETIMEDOUT
88356         case ETIMEDOUT: return DRMP3_TIMEOUT;
88357     #endif
88358     #ifdef ECONNREFUSED
88359         case ECONNREFUSED: return DRMP3_CONNECTION_REFUSED;
88360     #endif
88361     #ifdef EHOSTDOWN
88362         case EHOSTDOWN: return DRMP3_NO_HOST;
88363     #endif
88364     #ifdef EHOSTUNREACH
88365         case EHOSTUNREACH: return DRMP3_NO_HOST;
88366     #endif
88367     #ifdef EALREADY
88368         case EALREADY: return DRMP3_IN_PROGRESS;
88369     #endif
88370     #ifdef EINPROGRESS
88371         case EINPROGRESS: return DRMP3_IN_PROGRESS;
88372     #endif
88373     #ifdef ESTALE
88374         case ESTALE: return DRMP3_INVALID_FILE;
88375     #endif
88376     #ifdef EUCLEAN
88377         case EUCLEAN: return DRMP3_ERROR;
88378     #endif
88379     #ifdef ENOTNAM
88380         case ENOTNAM: return DRMP3_ERROR;
88381     #endif
88382     #ifdef ENAVAIL
88383         case ENAVAIL: return DRMP3_ERROR;
88384     #endif
88385     #ifdef EISNAM
88386         case EISNAM: return DRMP3_ERROR;
88387     #endif
88388     #ifdef EREMOTEIO
88389         case EREMOTEIO: return DRMP3_IO_ERROR;
88390     #endif
88391     #ifdef EDQUOT
88392         case EDQUOT: return DRMP3_NO_SPACE;
88393     #endif
88394     #ifdef ENOMEDIUM
88395         case ENOMEDIUM: return DRMP3_DOES_NOT_EXIST;
88396     #endif
88397     #ifdef EMEDIUMTYPE
88398         case EMEDIUMTYPE: return DRMP3_ERROR;
88399     #endif
88400     #ifdef ECANCELED
88401         case ECANCELED: return DRMP3_CANCELLED;
88402     #endif
88403     #ifdef ENOKEY
88404         case ENOKEY: return DRMP3_ERROR;
88405     #endif
88406     #ifdef EKEYEXPIRED
88407         case EKEYEXPIRED: return DRMP3_ERROR;
88408     #endif
88409     #ifdef EKEYREVOKED
88410         case EKEYREVOKED: return DRMP3_ERROR;
88411     #endif
88412     #ifdef EKEYREJECTED
88413         case EKEYREJECTED: return DRMP3_ERROR;
88414     #endif
88415     #ifdef EOWNERDEAD
88416         case EOWNERDEAD: return DRMP3_ERROR;
88417     #endif
88418     #ifdef ENOTRECOVERABLE
88419         case ENOTRECOVERABLE: return DRMP3_ERROR;
88420     #endif
88421     #ifdef ERFKILL
88422         case ERFKILL: return DRMP3_ERROR;
88423     #endif
88424     #ifdef EHWPOISON
88425         case EHWPOISON: return DRMP3_ERROR;
88426     #endif
88427         default: return DRMP3_ERROR;
88428     }
88429 }
88430 static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
88431 {
88432 #if defined(_MSC_VER) && _MSC_VER >= 1400
88433     errno_t err;
88434 #endif
88435     if (ppFile != NULL) {
88436         *ppFile = NULL;
88437     }
88438     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
88439         return DRMP3_INVALID_ARGS;
88440     }
88441 #if defined(_MSC_VER) && _MSC_VER >= 1400
88442     err = fopen_s(ppFile, pFilePath, pOpenMode);
88443     if (err != 0) {
88444         return drmp3_result_from_errno(err);
88445     }
88446 #else
88447 #if defined(_WIN32) || defined(__APPLE__)
88448     *ppFile = fopen(pFilePath, pOpenMode);
88449 #else
88450     #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
88451         *ppFile = fopen64(pFilePath, pOpenMode);
88452     #else
88453         *ppFile = fopen(pFilePath, pOpenMode);
88454     #endif
88455 #endif
88456     if (*ppFile == NULL) {
88457         drmp3_result result = drmp3_result_from_errno(errno);
88458         if (result == DRMP3_SUCCESS) {
88459             result = DRMP3_ERROR;
88460         }
88461         return result;
88462     }
88463 #endif
88464     return DRMP3_SUCCESS;
88465 }
88466 #if defined(_WIN32)
88467     #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
88468         #define DRMP3_HAS_WFOPEN
88469     #endif
88470 #endif
88471 static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drmp3_allocation_callbacks* pAllocationCallbacks)
88472 {
88473     if (ppFile != NULL) {
88474         *ppFile = NULL;
88475     }
88476     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
88477         return DRMP3_INVALID_ARGS;
88478     }
88479 #if defined(DRMP3_HAS_WFOPEN)
88480     {
88481     #if defined(_MSC_VER) && _MSC_VER >= 1400
88482         errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
88483         if (err != 0) {
88484             return drmp3_result_from_errno(err);
88485         }
88486     #else
88487         *ppFile = _wfopen(pFilePath, pOpenMode);
88488         if (*ppFile == NULL) {
88489             return drmp3_result_from_errno(errno);
88490         }
88491     #endif
88492         (void)pAllocationCallbacks;
88493     }
88494 #else
88495     {
88496         mbstate_t mbs;
88497         size_t lenMB;
88498         const wchar_t* pFilePathTemp = pFilePath;
88499         char* pFilePathMB = NULL;
88500         char pOpenModeMB[32] = {0};
88501         DRMP3_ZERO_OBJECT(&mbs);
88502         lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
88503         if (lenMB == (size_t)-1) {
88504             return drmp3_result_from_errno(errno);
88505         }
88506         pFilePathMB = (char*)drmp3__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
88507         if (pFilePathMB == NULL) {
88508             return DRMP3_OUT_OF_MEMORY;
88509         }
88510         pFilePathTemp = pFilePath;
88511         DRMP3_ZERO_OBJECT(&mbs);
88512         wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
88513         {
88514             size_t i = 0;
88515             for (;;) {
88516                 if (pOpenMode[i] == 0) {
88517                     pOpenModeMB[i] = '\0';
88518                     break;
88519                 }
88520                 pOpenModeMB[i] = (char)pOpenMode[i];
88521                 i += 1;
88522             }
88523         }
88524         *ppFile = fopen(pFilePathMB, pOpenModeMB);
88525         drmp3__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
88526     }
88527     if (*ppFile == NULL) {
88528         return DRMP3_ERROR;
88529     }
88530 #endif
88531     return DRMP3_SUCCESS;
88532 }
88533 static size_t drmp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
88534 {
88535     return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
88536 }
88537 static drmp3_bool32 drmp3__on_seek_stdio(void* pUserData, int offset, drmp3_seek_origin origin)
88538 {
88539     return fseek((FILE*)pUserData, offset, (origin == drmp3_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
88540 }
88541 DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks)
88542 {
88543     drmp3_bool32 result;
88544     FILE* pFile;
88545     if (drmp3_fopen(&pFile, pFilePath, "rb") != DRMP3_SUCCESS) {
88546         return DRMP3_FALSE;
88547     }
88548     result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
88549     if (result != DRMP3_TRUE) {
88550         fclose(pFile);
88551         return result;
88552     }
88553     return DRMP3_TRUE;
88554 }
88555 DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks)
88556 {
88557     drmp3_bool32 result;
88558     FILE* pFile;
88559     if (drmp3_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != DRMP3_SUCCESS) {
88560         return DRMP3_FALSE;
88561     }
88562     result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
88563     if (result != DRMP3_TRUE) {
88564         fclose(pFile);
88565         return result;
88566     }
88567     return DRMP3_TRUE;
88568 }
88569 #endif
88570 DRMP3_API void drmp3_uninit(drmp3* pMP3)
88571 {
88572     if (pMP3 == NULL) {
88573         return;
88574     }
88575 #ifndef DR_MP3_NO_STDIO
88576     if (pMP3->onRead == drmp3__on_read_stdio) {
88577         FILE* pFile = (FILE*)pMP3->pUserData;
88578         if (pFile != NULL) {
88579             fclose(pFile);
88580             pMP3->pUserData = NULL;
88581         }
88582     }
88583 #endif
88584     drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks);
88585 }
88586 #if defined(DR_MP3_FLOAT_OUTPUT)
88587 static void drmp3_f32_to_s16(drmp3_int16* dst, const float* src, drmp3_uint64 sampleCount)
88588 {
88589     drmp3_uint64 i;
88590     drmp3_uint64 i4;
88591     drmp3_uint64 sampleCount4;
88592     i = 0;
88593     sampleCount4 = sampleCount >> 2;
88594     for (i4 = 0; i4 < sampleCount4; i4 += 1) {
88595         float x0 = src[i+0];
88596         float x1 = src[i+1];
88597         float x2 = src[i+2];
88598         float x3 = src[i+3];
88599         x0 = ((x0 < -1) ? -1 : ((x0 > 1) ? 1 : x0));
88600         x1 = ((x1 < -1) ? -1 : ((x1 > 1) ? 1 : x1));
88601         x2 = ((x2 < -1) ? -1 : ((x2 > 1) ? 1 : x2));
88602         x3 = ((x3 < -1) ? -1 : ((x3 > 1) ? 1 : x3));
88603         x0 = x0 * 32767.0f;
88604         x1 = x1 * 32767.0f;
88605         x2 = x2 * 32767.0f;
88606         x3 = x3 * 32767.0f;
88607         dst[i+0] = (drmp3_int16)x0;
88608         dst[i+1] = (drmp3_int16)x1;
88609         dst[i+2] = (drmp3_int16)x2;
88610         dst[i+3] = (drmp3_int16)x3;
88611         i += 4;
88612     }
88613     for (; i < sampleCount; i += 1) {
88614         float x = src[i];
88615         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
88616         x = x * 32767.0f;
88617         dst[i] = (drmp3_int16)x;
88618     }
88619 }
88620 #endif
88621 #if !defined(DR_MP3_FLOAT_OUTPUT)
88622 static void drmp3_s16_to_f32(float* dst, const drmp3_int16* src, drmp3_uint64 sampleCount)
88623 {
88624     drmp3_uint64 i;
88625     for (i = 0; i < sampleCount; i += 1) {
88626         float x = (float)src[i];
88627         x = x * 0.000030517578125f;
88628         dst[i] = x;
88629     }
88630 }
88631 #endif
88632 static drmp3_uint64 drmp3_read_pcm_frames_raw(drmp3* pMP3, drmp3_uint64 framesToRead, void* pBufferOut)
88633 {
88634     drmp3_uint64 totalFramesRead = 0;
88635     DRMP3_ASSERT(pMP3 != NULL);
88636     DRMP3_ASSERT(pMP3->onRead != NULL);
88637     while (framesToRead > 0) {
88638         drmp3_uint32 framesToConsume = (drmp3_uint32)DRMP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead);
88639         if (pBufferOut != NULL) {
88640         #if defined(DR_MP3_FLOAT_OUTPUT)
88641             float* pFramesOutF32 = (float*)DRMP3_OFFSET_PTR(pBufferOut,          sizeof(float) * totalFramesRead                   * pMP3->channels);
88642             float* pFramesInF32  = (float*)DRMP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels);
88643             DRMP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels);
88644         #else
88645             drmp3_int16* pFramesOutS16 = (drmp3_int16*)DRMP3_OFFSET_PTR(pBufferOut,          sizeof(drmp3_int16) * totalFramesRead                   * pMP3->channels);
88646             drmp3_int16* pFramesInS16  = (drmp3_int16*)DRMP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(drmp3_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels);
88647             DRMP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(drmp3_int16) * framesToConsume * pMP3->channels);
88648         #endif
88649         }
88650         pMP3->currentPCMFrame              += framesToConsume;
88651         pMP3->pcmFramesConsumedInMP3Frame  += framesToConsume;
88652         pMP3->pcmFramesRemainingInMP3Frame -= framesToConsume;
88653         totalFramesRead                    += framesToConsume;
88654         framesToRead                       -= framesToConsume;
88655         if (framesToRead == 0) {
88656             break;
88657         }
88658         DRMP3_ASSERT(pMP3->pcmFramesRemainingInMP3Frame == 0);
88659         if (drmp3_decode_next_frame(pMP3) == 0) {
88660             break;
88661         }
88662     }
88663     return totalFramesRead;
88664 }
88665 DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut)
88666 {
88667     if (pMP3 == NULL || pMP3->onRead == NULL) {
88668         return 0;
88669     }
88670 #if defined(DR_MP3_FLOAT_OUTPUT)
88671     return drmp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut);
88672 #else
88673     {
88674         drmp3_int16 pTempS16[8192];
88675         drmp3_uint64 totalPCMFramesRead = 0;
88676         while (totalPCMFramesRead < framesToRead) {
88677             drmp3_uint64 framesJustRead;
88678             drmp3_uint64 framesRemaining = framesToRead - totalPCMFramesRead;
88679             drmp3_uint64 framesToReadNow = DRMP3_COUNTOF(pTempS16) / pMP3->channels;
88680             if (framesToReadNow > framesRemaining) {
88681                 framesToReadNow = framesRemaining;
88682             }
88683             framesJustRead = drmp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempS16);
88684             if (framesJustRead == 0) {
88685                 break;
88686             }
88687             drmp3_s16_to_f32((float*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalPCMFramesRead * pMP3->channels), pTempS16, framesJustRead * pMP3->channels);
88688             totalPCMFramesRead += framesJustRead;
88689         }
88690         return totalPCMFramesRead;
88691     }
88692 #endif
88693 }
88694 DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut)
88695 {
88696     if (pMP3 == NULL || pMP3->onRead == NULL) {
88697         return 0;
88698     }
88699 #if !defined(DR_MP3_FLOAT_OUTPUT)
88700     return drmp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut);
88701 #else
88702     {
88703         float pTempF32[4096];
88704         drmp3_uint64 totalPCMFramesRead = 0;
88705         while (totalPCMFramesRead < framesToRead) {
88706             drmp3_uint64 framesJustRead;
88707             drmp3_uint64 framesRemaining = framesToRead - totalPCMFramesRead;
88708             drmp3_uint64 framesToReadNow = DRMP3_COUNTOF(pTempF32) / pMP3->channels;
88709             if (framesToReadNow > framesRemaining) {
88710                 framesToReadNow = framesRemaining;
88711             }
88712             framesJustRead = drmp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempF32);
88713             if (framesJustRead == 0) {
88714                 break;
88715             }
88716             drmp3_f32_to_s16((drmp3_int16*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(drmp3_int16) * totalPCMFramesRead * pMP3->channels), pTempF32, framesJustRead * pMP3->channels);
88717             totalPCMFramesRead += framesJustRead;
88718         }
88719         return totalPCMFramesRead;
88720     }
88721 #endif
88722 }
88723 static void drmp3_reset(drmp3* pMP3)
88724 {
88725     DRMP3_ASSERT(pMP3 != NULL);
88726     pMP3->pcmFramesConsumedInMP3Frame = 0;
88727     pMP3->pcmFramesRemainingInMP3Frame = 0;
88728     pMP3->currentPCMFrame = 0;
88729     pMP3->dataSize = 0;
88730     pMP3->atEnd = DRMP3_FALSE;
88731     drmp3dec_init(&pMP3->decoder);
88732 }
88733 static drmp3_bool32 drmp3_seek_to_start_of_stream(drmp3* pMP3)
88734 {
88735     DRMP3_ASSERT(pMP3 != NULL);
88736     DRMP3_ASSERT(pMP3->onSeek != NULL);
88737     if (!drmp3__on_seek(pMP3, 0, drmp3_seek_origin_start)) {
88738         return DRMP3_FALSE;
88739     }
88740     drmp3_reset(pMP3);
88741     return DRMP3_TRUE;
88742 }
88743 static drmp3_bool32 drmp3_seek_forward_by_pcm_frames__brute_force(drmp3* pMP3, drmp3_uint64 frameOffset)
88744 {
88745     drmp3_uint64 framesRead;
88746 #if defined(DR_MP3_FLOAT_OUTPUT)
88747     framesRead = drmp3_read_pcm_frames_f32(pMP3, frameOffset, NULL);
88748 #else
88749     framesRead = drmp3_read_pcm_frames_s16(pMP3, frameOffset, NULL);
88750 #endif
88751     if (framesRead != frameOffset) {
88752         return DRMP3_FALSE;
88753     }
88754     return DRMP3_TRUE;
88755 }
88756 static drmp3_bool32 drmp3_seek_to_pcm_frame__brute_force(drmp3* pMP3, drmp3_uint64 frameIndex)
88757 {
88758     DRMP3_ASSERT(pMP3 != NULL);
88759     if (frameIndex == pMP3->currentPCMFrame) {
88760         return DRMP3_TRUE;
88761     }
88762     if (frameIndex < pMP3->currentPCMFrame) {
88763         if (!drmp3_seek_to_start_of_stream(pMP3)) {
88764             return DRMP3_FALSE;
88765         }
88766     }
88767     DRMP3_ASSERT(frameIndex >= pMP3->currentPCMFrame);
88768     return drmp3_seek_forward_by_pcm_frames__brute_force(pMP3, (frameIndex - pMP3->currentPCMFrame));
88769 }
88770 static drmp3_bool32 drmp3_find_closest_seek_point(drmp3* pMP3, drmp3_uint64 frameIndex, drmp3_uint32* pSeekPointIndex)
88771 {
88772     drmp3_uint32 iSeekPoint;
88773     DRMP3_ASSERT(pSeekPointIndex != NULL);
88774     *pSeekPointIndex = 0;
88775     if (frameIndex < pMP3->pSeekPoints[0].pcmFrameIndex) {
88776         return DRMP3_FALSE;
88777     }
88778     for (iSeekPoint = 0; iSeekPoint < pMP3->seekPointCount; ++iSeekPoint) {
88779         if (pMP3->pSeekPoints[iSeekPoint].pcmFrameIndex > frameIndex) {
88780             break;
88781         }
88782         *pSeekPointIndex = iSeekPoint;
88783     }
88784     return DRMP3_TRUE;
88785 }
88786 static drmp3_bool32 drmp3_seek_to_pcm_frame__seek_table(drmp3* pMP3, drmp3_uint64 frameIndex)
88787 {
88788     drmp3_seek_point seekPoint;
88789     drmp3_uint32 priorSeekPointIndex;
88790     drmp3_uint16 iMP3Frame;
88791     drmp3_uint64 leftoverFrames;
88792     DRMP3_ASSERT(pMP3 != NULL);
88793     DRMP3_ASSERT(pMP3->pSeekPoints != NULL);
88794     DRMP3_ASSERT(pMP3->seekPointCount > 0);
88795     if (drmp3_find_closest_seek_point(pMP3, frameIndex, &priorSeekPointIndex)) {
88796         seekPoint = pMP3->pSeekPoints[priorSeekPointIndex];
88797     } else {
88798         seekPoint.seekPosInBytes     = 0;
88799         seekPoint.pcmFrameIndex      = 0;
88800         seekPoint.mp3FramesToDiscard = 0;
88801         seekPoint.pcmFramesToDiscard = 0;
88802     }
88803     if (!drmp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, drmp3_seek_origin_start)) {
88804         return DRMP3_FALSE;
88805     }
88806     drmp3_reset(pMP3);
88807     for (iMP3Frame = 0; iMP3Frame < seekPoint.mp3FramesToDiscard; ++iMP3Frame) {
88808         drmp3_uint32 pcmFramesRead;
88809         drmp3d_sample_t* pPCMFrames;
88810         pPCMFrames = NULL;
88811         if (iMP3Frame == seekPoint.mp3FramesToDiscard-1) {
88812             pPCMFrames = (drmp3d_sample_t*)pMP3->pcmFrames;
88813         }
88814         pcmFramesRead = drmp3_decode_next_frame_ex(pMP3, pPCMFrames);
88815         if (pcmFramesRead == 0) {
88816             return DRMP3_FALSE;
88817         }
88818     }
88819     pMP3->currentPCMFrame = seekPoint.pcmFrameIndex - seekPoint.pcmFramesToDiscard;
88820     leftoverFrames = frameIndex - pMP3->currentPCMFrame;
88821     return drmp3_seek_forward_by_pcm_frames__brute_force(pMP3, leftoverFrames);
88822 }
88823 DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex)
88824 {
88825     if (pMP3 == NULL || pMP3->onSeek == NULL) {
88826         return DRMP3_FALSE;
88827     }
88828     if (frameIndex == 0) {
88829         return drmp3_seek_to_start_of_stream(pMP3);
88830     }
88831     if (pMP3->pSeekPoints != NULL && pMP3->seekPointCount > 0) {
88832         return drmp3_seek_to_pcm_frame__seek_table(pMP3, frameIndex);
88833     } else {
88834         return drmp3_seek_to_pcm_frame__brute_force(pMP3, frameIndex);
88835     }
88836 }
88837 DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount)
88838 {
88839     drmp3_uint64 currentPCMFrame;
88840     drmp3_uint64 totalPCMFrameCount;
88841     drmp3_uint64 totalMP3FrameCount;
88842     if (pMP3 == NULL) {
88843         return DRMP3_FALSE;
88844     }
88845     if (pMP3->onSeek == NULL) {
88846         return DRMP3_FALSE;
88847     }
88848     currentPCMFrame = pMP3->currentPCMFrame;
88849     if (!drmp3_seek_to_start_of_stream(pMP3)) {
88850         return DRMP3_FALSE;
88851     }
88852     totalPCMFrameCount = 0;
88853     totalMP3FrameCount = 0;
88854     for (;;) {
88855         drmp3_uint32 pcmFramesInCurrentMP3Frame;
88856         pcmFramesInCurrentMP3Frame = drmp3_decode_next_frame_ex(pMP3, NULL);
88857         if (pcmFramesInCurrentMP3Frame == 0) {
88858             break;
88859         }
88860         totalPCMFrameCount += pcmFramesInCurrentMP3Frame;
88861         totalMP3FrameCount += 1;
88862     }
88863     if (!drmp3_seek_to_start_of_stream(pMP3)) {
88864         return DRMP3_FALSE;
88865     }
88866     if (!drmp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) {
88867         return DRMP3_FALSE;
88868     }
88869     if (pMP3FrameCount != NULL) {
88870         *pMP3FrameCount = totalMP3FrameCount;
88871     }
88872     if (pPCMFrameCount != NULL) {
88873         *pPCMFrameCount = totalPCMFrameCount;
88874     }
88875     return DRMP3_TRUE;
88876 }
88877 DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3)
88878 {
88879     drmp3_uint64 totalPCMFrameCount;
88880     if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) {
88881         return 0;
88882     }
88883     return totalPCMFrameCount;
88884 }
88885 DRMP3_API drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3)
88886 {
88887     drmp3_uint64 totalMP3FrameCount;
88888     if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, NULL)) {
88889         return 0;
88890     }
88891     return totalMP3FrameCount;
88892 }
88893 static void drmp3__accumulate_running_pcm_frame_count(drmp3* pMP3, drmp3_uint32 pcmFrameCountIn, drmp3_uint64* pRunningPCMFrameCount, float* pRunningPCMFrameCountFractionalPart)
88894 {
88895     float srcRatio;
88896     float pcmFrameCountOutF;
88897     drmp3_uint32 pcmFrameCountOut;
88898     srcRatio = (float)pMP3->mp3FrameSampleRate / (float)pMP3->sampleRate;
88899     DRMP3_ASSERT(srcRatio > 0);
88900     pcmFrameCountOutF = *pRunningPCMFrameCountFractionalPart + (pcmFrameCountIn / srcRatio);
88901     pcmFrameCountOut  = (drmp3_uint32)pcmFrameCountOutF;
88902     *pRunningPCMFrameCountFractionalPart = pcmFrameCountOutF - pcmFrameCountOut;
88903     *pRunningPCMFrameCount += pcmFrameCountOut;
88904 }
88905 typedef struct
88906 {
88907     drmp3_uint64 bytePos;
88908     drmp3_uint64 pcmFrameIndex;
88909 } drmp3__seeking_mp3_frame_info;
88910 DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints)
88911 {
88912     drmp3_uint32 seekPointCount;
88913     drmp3_uint64 currentPCMFrame;
88914     drmp3_uint64 totalMP3FrameCount;
88915     drmp3_uint64 totalPCMFrameCount;
88916     if (pMP3 == NULL || pSeekPointCount == NULL || pSeekPoints == NULL) {
88917         return DRMP3_FALSE;
88918     }
88919     seekPointCount = *pSeekPointCount;
88920     if (seekPointCount == 0) {
88921         return DRMP3_FALSE;
88922     }
88923     currentPCMFrame = pMP3->currentPCMFrame;
88924     if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, &totalPCMFrameCount)) {
88925         return DRMP3_FALSE;
88926     }
88927     if (totalMP3FrameCount < DRMP3_SEEK_LEADING_MP3_FRAMES+1) {
88928         seekPointCount = 1;
88929         pSeekPoints[0].seekPosInBytes     = 0;
88930         pSeekPoints[0].pcmFrameIndex      = 0;
88931         pSeekPoints[0].mp3FramesToDiscard = 0;
88932         pSeekPoints[0].pcmFramesToDiscard = 0;
88933     } else {
88934         drmp3_uint64 pcmFramesBetweenSeekPoints;
88935         drmp3__seeking_mp3_frame_info mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES+1];
88936         drmp3_uint64 runningPCMFrameCount = 0;
88937         float runningPCMFrameCountFractionalPart = 0;
88938         drmp3_uint64 nextTargetPCMFrame;
88939         drmp3_uint32 iMP3Frame;
88940         drmp3_uint32 iSeekPoint;
88941         if (seekPointCount > totalMP3FrameCount-1) {
88942             seekPointCount = (drmp3_uint32)totalMP3FrameCount-1;
88943         }
88944         pcmFramesBetweenSeekPoints = totalPCMFrameCount / (seekPointCount+1);
88945         if (!drmp3_seek_to_start_of_stream(pMP3)) {
88946             return DRMP3_FALSE;
88947         }
88948         for (iMP3Frame = 0; iMP3Frame < DRMP3_SEEK_LEADING_MP3_FRAMES+1; ++iMP3Frame) {
88949             drmp3_uint32 pcmFramesInCurrentMP3FrameIn;
88950             DRMP3_ASSERT(pMP3->streamCursor >= pMP3->dataSize);
88951             mp3FrameInfo[iMP3Frame].bytePos       = pMP3->streamCursor - pMP3->dataSize;
88952             mp3FrameInfo[iMP3Frame].pcmFrameIndex = runningPCMFrameCount;
88953             pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL);
88954             if (pcmFramesInCurrentMP3FrameIn == 0) {
88955                 return DRMP3_FALSE;
88956             }
88957             drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart);
88958         }
88959         nextTargetPCMFrame = 0;
88960         for (iSeekPoint = 0; iSeekPoint < seekPointCount; ++iSeekPoint) {
88961             nextTargetPCMFrame += pcmFramesBetweenSeekPoints;
88962             for (;;) {
88963                 if (nextTargetPCMFrame < runningPCMFrameCount) {
88964                     pSeekPoints[iSeekPoint].seekPosInBytes     = mp3FrameInfo[0].bytePos;
88965                     pSeekPoints[iSeekPoint].pcmFrameIndex      = nextTargetPCMFrame;
88966                     pSeekPoints[iSeekPoint].mp3FramesToDiscard = DRMP3_SEEK_LEADING_MP3_FRAMES;
88967                     pSeekPoints[iSeekPoint].pcmFramesToDiscard = (drmp3_uint16)(nextTargetPCMFrame - mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex);
88968                     break;
88969                 } else {
88970                     size_t i;
88971                     drmp3_uint32 pcmFramesInCurrentMP3FrameIn;
88972                     for (i = 0; i < DRMP3_COUNTOF(mp3FrameInfo)-1; ++i) {
88973                         mp3FrameInfo[i] = mp3FrameInfo[i+1];
88974                     }
88975                     mp3FrameInfo[DRMP3_COUNTOF(mp3FrameInfo)-1].bytePos       = pMP3->streamCursor - pMP3->dataSize;
88976                     mp3FrameInfo[DRMP3_COUNTOF(mp3FrameInfo)-1].pcmFrameIndex = runningPCMFrameCount;
88977                     pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL);
88978                     if (pcmFramesInCurrentMP3FrameIn == 0) {
88979                         pSeekPoints[iSeekPoint].seekPosInBytes     = mp3FrameInfo[0].bytePos;
88980                         pSeekPoints[iSeekPoint].pcmFrameIndex      = nextTargetPCMFrame;
88981                         pSeekPoints[iSeekPoint].mp3FramesToDiscard = DRMP3_SEEK_LEADING_MP3_FRAMES;
88982                         pSeekPoints[iSeekPoint].pcmFramesToDiscard = (drmp3_uint16)(nextTargetPCMFrame - mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex);
88983                         break;
88984                     }
88985                     drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart);
88986                 }
88987             }
88988         }
88989         if (!drmp3_seek_to_start_of_stream(pMP3)) {
88990             return DRMP3_FALSE;
88991         }
88992         if (!drmp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) {
88993             return DRMP3_FALSE;
88994         }
88995     }
88996     *pSeekPointCount = seekPointCount;
88997     return DRMP3_TRUE;
88998 }
88999 DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints)
89000 {
89001     if (pMP3 == NULL) {
89002         return DRMP3_FALSE;
89003     }
89004     if (seekPointCount == 0 || pSeekPoints == NULL) {
89005         pMP3->seekPointCount = 0;
89006         pMP3->pSeekPoints = NULL;
89007     } else {
89008         pMP3->seekPointCount = seekPointCount;
89009         pMP3->pSeekPoints = pSeekPoints;
89010     }
89011     return DRMP3_TRUE;
89012 }
89013 static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount)
89014 {
89015     drmp3_uint64 totalFramesRead = 0;
89016     drmp3_uint64 framesCapacity = 0;
89017     float* pFrames = NULL;
89018     float temp[4096];
89019     DRMP3_ASSERT(pMP3 != NULL);
89020     for (;;) {
89021         drmp3_uint64 framesToReadRightNow = DRMP3_COUNTOF(temp) / pMP3->channels;
89022         drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_f32(pMP3, framesToReadRightNow, temp);
89023         if (framesJustRead == 0) {
89024             break;
89025         }
89026         if (framesCapacity < totalFramesRead + framesJustRead) {
89027             drmp3_uint64 oldFramesBufferSize;
89028             drmp3_uint64 newFramesBufferSize;
89029             drmp3_uint64 newFramesCap;
89030             float* pNewFrames;
89031             newFramesCap = framesCapacity * 2;
89032             if (newFramesCap < totalFramesRead + framesJustRead) {
89033                 newFramesCap = totalFramesRead + framesJustRead;
89034             }
89035             oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(float);
89036             newFramesBufferSize = newFramesCap   * pMP3->channels * sizeof(float);
89037             if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) {
89038                 break;
89039             }
89040             pNewFrames = (float*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
89041             if (pNewFrames == NULL) {
89042                 drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
89043                 break;
89044             }
89045             pFrames = pNewFrames;
89046             framesCapacity = newFramesCap;
89047         }
89048         DRMP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(float)));
89049         totalFramesRead += framesJustRead;
89050         if (framesJustRead != framesToReadRightNow) {
89051             break;
89052         }
89053     }
89054     if (pConfig != NULL) {
89055         pConfig->channels   = pMP3->channels;
89056         pConfig->sampleRate = pMP3->sampleRate;
89057     }
89058     drmp3_uninit(pMP3);
89059     if (pTotalFrameCount) {
89060         *pTotalFrameCount = totalFramesRead;
89061     }
89062     return pFrames;
89063 }
89064 static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount)
89065 {
89066     drmp3_uint64 totalFramesRead = 0;
89067     drmp3_uint64 framesCapacity = 0;
89068     drmp3_int16* pFrames = NULL;
89069     drmp3_int16 temp[4096];
89070     DRMP3_ASSERT(pMP3 != NULL);
89071     for (;;) {
89072         drmp3_uint64 framesToReadRightNow = DRMP3_COUNTOF(temp) / pMP3->channels;
89073         drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_s16(pMP3, framesToReadRightNow, temp);
89074         if (framesJustRead == 0) {
89075             break;
89076         }
89077         if (framesCapacity < totalFramesRead + framesJustRead) {
89078             drmp3_uint64 newFramesBufferSize;
89079             drmp3_uint64 oldFramesBufferSize;
89080             drmp3_uint64 newFramesCap;
89081             drmp3_int16* pNewFrames;
89082             newFramesCap = framesCapacity * 2;
89083             if (newFramesCap < totalFramesRead + framesJustRead) {
89084                 newFramesCap = totalFramesRead + framesJustRead;
89085             }
89086             oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(drmp3_int16);
89087             newFramesBufferSize = newFramesCap   * pMP3->channels * sizeof(drmp3_int16);
89088             if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) {
89089                 break;
89090             }
89091             pNewFrames = (drmp3_int16*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
89092             if (pNewFrames == NULL) {
89093                 drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
89094                 break;
89095             }
89096             pFrames = pNewFrames;
89097             framesCapacity = newFramesCap;
89098         }
89099         DRMP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(drmp3_int16)));
89100         totalFramesRead += framesJustRead;
89101         if (framesJustRead != framesToReadRightNow) {
89102             break;
89103         }
89104     }
89105     if (pConfig != NULL) {
89106         pConfig->channels   = pMP3->channels;
89107         pConfig->sampleRate = pMP3->sampleRate;
89108     }
89109     drmp3_uninit(pMP3);
89110     if (pTotalFrameCount) {
89111         *pTotalFrameCount = totalFramesRead;
89112     }
89113     return pFrames;
89114 }
89115 DRMP3_API float* drmp3_open_and_read_pcm_frames_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
89116 {
89117     drmp3 mp3;
89118     if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) {
89119         return NULL;
89120     }
89121     return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
89122 }
89123 DRMP3_API drmp3_int16* drmp3_open_and_read_pcm_frames_s16(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
89124 {
89125     drmp3 mp3;
89126     if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) {
89127         return NULL;
89128     }
89129     return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
89130 }
89131 DRMP3_API float* drmp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
89132 {
89133     drmp3 mp3;
89134     if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) {
89135         return NULL;
89136     }
89137     return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
89138 }
89139 DRMP3_API drmp3_int16* drmp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
89140 {
89141     drmp3 mp3;
89142     if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) {
89143         return NULL;
89144     }
89145     return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
89146 }
89147 #ifndef DR_MP3_NO_STDIO
89148 DRMP3_API float* drmp3_open_file_and_read_pcm_frames_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
89149 {
89150     drmp3 mp3;
89151     if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) {
89152         return NULL;
89153     }
89154     return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
89155 }
89156 DRMP3_API drmp3_int16* drmp3_open_file_and_read_pcm_frames_s16(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
89157 {
89158     drmp3 mp3;
89159     if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) {
89160         return NULL;
89161     }
89162     return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
89163 }
89164 #endif
89165 DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks)
89166 {
89167     if (pAllocationCallbacks != NULL) {
89168         return drmp3__malloc_from_callbacks(sz, pAllocationCallbacks);
89169     } else {
89170         return drmp3__malloc_default(sz, NULL);
89171     }
89172 }
89173 DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks)
89174 {
89175     if (pAllocationCallbacks != NULL) {
89176         drmp3__free_from_callbacks(p, pAllocationCallbacks);
89177     } else {
89178         drmp3__free_default(p, NULL);
89179     }
89180 }
89181 #endif
89182 /* dr_mp3_c end */
89183 #endif  /* DRMP3_IMPLEMENTATION */
89184 #endif  /* MA_NO_MP3 */
89185
89186
89187 /* End globally disabled warnings. */
89188 #if defined(_MSC_VER)
89189     #pragma warning(pop)
89190 #endif
89191
89192 #endif  /* miniaudio_c */
89193 #endif  /* MINIAUDIO_IMPLEMENTATION */
89194
89195 /*
89196 RELEASE NOTES - VERSION 0.11.x
89197 ==============================
89198 Version 0.11 adds some high level APIs and includes some breaking API changes.
89199
89200
89201 High Level Engine API
89202 ---------------------
89203 The engine API provides sound management, mixing and effect processing. It can be used as both an
89204 alternative to the low level device API or as a supplementary feature depending on your needs. See
89205 the documentation for information on how to use this API.
89206
89207
89208 Resource Management
89209 -------------------
89210 Support for management of sound files has been added via the new `ma_resource_manager` API. This
89211 supports loading of sounds entirely in memory with reference counting and also streaming. See the
89212 documentation for more information on the resource manager.
89213
89214
89215 Node Graphs
89216 -----------
89217 A node graph system has been added to support complex effect chains and mixing. The node graph is
89218 made up of a series of connected nodes, with the output of one node being fed into the input of
89219 another node. By connecting nodes together you can create complex effect and mixing graphs. A
89220 number of different types of nodes are included, but custom nodes are also supported. See the
89221 documentation for more information on the node graph system.
89222
89223
89224 Breaking API Changes
89225 --------------------
89226 There are many breaking API changes in this release.
89227
89228   - The "loop" parameter has been removed from ma_data_source_read_pcm_frames(). To enabled looping
89229     you now need to call ma_data_source_set_looping(). The looping state can be retrieved with
89230     ma_data_source_is_looping().
89231   - ma_channel_mix_mode_planar_blend has been removed. Use ma_channel_mix_mode_rectangular instead.
89232   - MA_MIN_SAMPLE_RATE and MA_MAX_SAMPLE_RATE have been removed. Use ma_standard_sample_rate_min
89233     and ma_standard_sample_rate_max instead.
89234   - The ma_device_info structure has changed. Now, an array of supported format/channels/rate
89235     combinations are stored in an array and the old minChannels, maxChannels, etc. have been
89236     removed.
89237   - The shareMode parameter has been removed from ma_context_get_device_info(). Whether or not the
89238     format relates to a shared or exclusive device is now set in a flags variables.
89239   - The noPreZeroedOutputBuffer variable in the device config has been renamed to
89240     noPreSilencedOutputBuffer.
89241   - The pBufferOut parameter has been removed from the ring buffer commit functions.
89242   - The ma_zero_pcm_frames() function has been removed. Use ma_silence_pcm_frames() instead.
89243   - ma_clip_samples_f32() has been updated to take an input and output buffer rather than working
89244     exclusively in-place.
89245   - ma_clip_pcm_frames_f32() has been removed. Use ma_clip_samples_f32() or ma_clip_pcm_frames()
89246     instead.
89247   - ma_data_source_callbacks has been removed. If you're building a custom data source you need to
89248     use ma_data_source_vtable instead.
89249   - Support for mapping has been removed from data sources since it had very limited use and has
89250     proven to not be worth the maintenance cost.
89251   - The onLog callback has been removed from the context config. This has been replaced with a much
89252     more flexible logging system. The context will have a `ma_log` object which can be retrieved
89253     with `ma_context_get_log()`. From there you can register a callback with the `ma_log` object
89254     with `ma_log_register_callback()`. An pre-allocated log can be specified in the context config.
89255   - MA_LOG_LEVEL_VERBOSE has been removed and replaced with MA_LOG_LEVEL_DEBUG. With this change,
89256     logs posted with MA_LOG_LEVEL_DEBUG will only be output if MA_DEBUG_OUTPUT is enabled.
89257   - MA_LOG_LEVEL has been removed. Now all log levels are posted, except for MA_LOG_LEVEL_DEBUG
89258     which will only be posted if MA_DEBUG_OUTPUT is enabled.
89259   - ma_resource_format has been replaced with ma_encoding_format.
89260   - The encoding-specific initialization functions for decoders, such as ma_decoder_init_wav(),
89261     have been removed. Instead you should set the encodingFormat variable in the decoder config.
89262   - ma_decoder_get_length_in_pcm_frames() has been updated to return a result code and output the
89263     length via an output parameter. This makes it consistent with data sources.
89264   - ma_decoder_read_pcm_frames() has been updated to return a result code and output the number of
89265     frames read via an output parameter.
89266   - Allocation callbacks must now implement the onRealloc() callback. Previously miniaudio would
89267     emulate this in terms of malloc and free, but for simplicity it is now required that allocation
89268     callbacks handle this theselves.
89269   - ma_get_standard_channel_map() has been renamed to ma_channel_map_init_standard() and now
89270     includes a parameter specifying the capacity of the output channel map. This is useful for
89271     initializing a channel map with a fixed capacity.
89272   - ma_channel_map_valid() has been renamed to ma_channel_map_is_valid().
89273   - ma_channel_map_equal() has been renamed to ma_channel_map_is_equal().
89274   - ma_channel_map_blank() has been renamed to ma_channel_map_is_blank().
89275   - The Speex resampler has been removed. Support for custom resamplers has been added. If you need
89276     a Speex resampler you will need to implement a custom resampler.
89277   - The following functions from the resampler have changed to return a result code and output
89278     their result via an output parameter:
89279     - ma_linear_resampler_get_required_input_frame_count()
89280     - ma_linear_resampler_get_expected_output_frame_count()
89281     - ma_resampler_get_required_input_frame_count()
89282     - ma_resampler_get_expected_output_frame_count()
89283   - Many init/uninit functions have been changed to take a pointer to allocation callbacks.
89284   - ma_scale_buffer_size() has been removed.
89285   - ma_encoder_write_pcm_frames() has been updated to return a result code and output the number of
89286     frames written via an output parameter.
89287   - ma_noise_read_pcm_frames() has been updated to return a result code and output the number of
89288     frames read via an output parameter.
89289   - ma_waveform_read_pcm_frames() has been updated to return a result code and output the number of
89290     frames read via an output parameter.
89291   - The MA_STATE_* tokens have been reanmed to ma_device_state_* and turned into an enum.
89292   - ma_factor_to_gain_db() has been renamed to ma_volume_linear_to_db()
89293   - ma_gain_db_to_factor() has been renamed to ma_volume_db_to_linear()
89294
89295
89296 Changes to Custom Data Sources
89297 ------------------------------
89298 The implementation of data sources has seen some changes. Previously, you needed to only implement
89299 the `ma_data_source_callbacks` structure and make it the first member of the data source's
89300 structure. This has now changed. You now need to make the first member of the data source's
89301 structure `ma_data_source_base` and initialize and uninitialize it with `ma_data_source_init()` and
89302 `ma_data_source_uninit()` from your data source's init/uninit routines.
89303
89304 When you call `ma_data_source_init()` you will need to specify a config. The config includes a
89305 pointer to a `ma_data_source_vtable` object which needs to be filled out.
89306
89307 The onGetDataFormat callback has been changed to output the channel map. With this change,
89308 ma_data_source_get_data_format() has been update to accept a channel map.
89309
89310 The onMap and onUnmap callbacks have been removed, as has ma_data_source_map() and
89311 ma_data_source_unmap().
89312
89313
89314 Other Changes
89315 -------------
89316 There have also been some other smaller changes added to this release.
89317
89318   - Support for custom resmplers has been added. See the implementation of ma_linear_resampler for
89319     an example on how to implement a custom resmpler.
89320   - ma_decoder_get_data_format() has been added.
89321   - Support has been added for disabling denormals on the audio thread. This is configured on a
89322     per-device basis via the device config and are disabled by default. Use the noDisableDenormals
89323     config variable to control this.
89324   - A delay/echo effect has been added called `ma_delay`.
89325   - A stereo pan effect has been added called `ma_panner`.
89326   - A spataializer effect has been added called `ma_spatializer`. This is used by the engine to
89327     achieve it's 3D spatialization effect for sounds.
89328   - ma_free() now performs a null pointer check which means NULL should never be passed into
89329     allocation callbacks.
89330   - Filters, effects and data conversion no longer have a dependency on MA_MAX_CHANNELS.
89331   - MA_MAX_CHANNELS has been increased from 32 to 254 and currently only affects devices. This may
89332     be relaxed in a future version.
89333 */
89334
89335 /*
89336 REVISION HISTORY
89337 ================
89338 v0.11.2 - 2021-12-31
89339   - Add a new device notification system to replace the stop callback. The stop callback is still
89340     in place, but will be removed in version 0.12. New code should use the notificationCallback
89341     member in the device config instead of stopCallback.
89342   - Fix a bug where the stopped notification doesn't get fired.
89343   - iOS: The IO buffer size is now configured based on the device's configured period size.
89344   - WebAudio: Optimizations to some JavaScript code.
89345
89346 v0.11.1 - 2021-12-27
89347   - Result codes are now declared as an enum rather than #defines.
89348   - Channel positions (MA_CHANNEL_*) are now declared as an enum rather than #defines.
89349   - Add ma_device_get_info() for retrieving device information from an initialized device.
89350   - Add ma_device_get_name() for retrieving the name of an initialized device.
89351   - Add support for setting the directional attenuation factor to sounds and groups.
89352   - Fix a crash when passing in NULL for the pEngine parameter of ma_engine_init().
89353   - Fix a bug where the node graph will output silence if a node has zero input connections.
89354   - Fix a bug in the engine where sounds in front of the listener are too loud.
89355   - AAudio: Fix an incorrect assert.
89356   - AAudio: Fix a bug that resulted in exclusive mode always resulting in initialization failure.
89357   - AAudio: Fix a bug that resulted in a capture device incorrectly being detected as disconnected.
89358   - OpenSL: Fix an error when initializing a device with a non-NULL device ID.
89359   - OpenSL: Fix some bugs with device initialization.
89360
89361 v0.11.0 - 2021-12-18
89362   - Add a node graph system for advanced mixing and effect processing.
89363   - Add a resource manager for loading and streaming sounds.
89364   - Add a high level engine API for sound management and mixing. This wraps around the node graph
89365     and resource manager.
89366   - Add support for custom resmplers.
89367   - Add ma_decoder_get_data_format().
89368   - Add support for disabling denormals on the audio thread.
89369   - Add a delay/echo effect called ma_delay.
89370   - Add a stereo pan effect called ma_panner.
89371   - Add a spataializer effect called ma_spatializer.
89372   - Add support for amplification for device master volume.
89373   - Remove dependency on MA_MAX_CHANNELS from filters and data conversion.
89374   - Increase MA_MAX_CHANNELS from 32 to 254.
89375   - API CHANGE: Changes have been made to the way custom data sources are made. See documentation
89376     on how to implement custom data sources.
89377   - API CHANGE: Remove ma_data_source_map() and ma_data_source_unmap()
89378   - API CHANGE: Remove the `loop` parameter from ma_data_source_read_pcm_frames(). Use
89379     ma_data_source_set_looping() to enable or disable looping.
89380   - API CHANGE: Remove ma_channel_mix_mode_planar_blend. Use ma_channel_mix_mode_rectangular instead.
89381   - API CHANGE: Remove MA_MIN_SAMPLE_RATE and MA_MAX_SAMPLE_RATE. Use ma_standard_sample_rate_min
89382     and ma_standard_sample_rate_max instead.
89383   - API CHANGE: Changes have been made to the ma_device_info structure. See documentation for
89384     details of these changes.
89385   - API CHANGE: Remove the `shareMode` parameter from ma_context_get_device_info().
89386   - API CHANGE: Rename noPreZeroedOutputBuffer to noPreSilencedOutputBuffer in the device config.
89387   - API CHANGE: Remove pBufferOut parameter from ring buffer commit functions.
89388   - API CHANGE: Remove ma_zero_pcm_frames(). Use ma_silence_pcm_frames() instead.
89389   - API CHANGE: Change ma_clip_samples_f32() to take input and output buffers rather than working
89390     exclusively in-place.
89391   - API CHANGE: Remove ma_clip_pcm_frames_f32(). Use ma_clip_samples_f32() or ma_clip_pcm_frames()
89392     instead.
89393   - API CHANGE: Remove the onLog callback from the context config and replaced with a more
89394     flexible system. See the documentation for how to use logging.
89395   - API CHANGE: Remove MA_LOG_LEVEL_VERBOSE and add MA_LOG_LEVEL_DEBUG. Logs using the
89396     MA_LOG_LEVEL_DEBUG logging level will only be output when miniaudio is compiled with the
89397     MA_DEBUG_OUTPUT option.
89398   - API CHANGE: MA_LOG_LEVEL has been removed. All log levels will be posted, except for
89399     MA_LOG_LEVEL_DEBUG which will only be output when MA_DEBUG_OUTPUT is enabled.
89400   - API CHANGE: Rename ma_resource_format to ma_encoding_format.
89401   - API CHANGE: Remove all encoding-specific initialization routines for decoders. Use the
89402     encodingFormat properties in the decoder config instead.
89403   - API CHANGE: Change ma_decoder_get_length_in_pcm_frames() to return a result code and output the
89404     number of frames read via an output parameter.
89405   - API CHANGE: Allocation callbacks must now implement the onRealloc() callback.
89406   - API CHANGE: Remove ma_get_standard_channel_map() and add ma_channel_map_init_standard().
89407   - API CHANGE: Rename ma_channel_map_valid() to ma_channel_map_is_valid().
89408   - API CHANGE: Rename ma_channel_map_equal() to ma_channel_map_is_equal().
89409   - API CHANGE: Rename ma_channel_map_blank() to ma_channel_map_is_blank().
89410   - API CHANGE: Remove the Speex resampler. Use a custom resampler instead.
89411   - API CHANGE: Change the following resampler APIs to return a result code and output their result
89412     via an output parameter:
89413     - ma_linear_resampler_get_required_input_frame_count()
89414     - ma_linear_resampler_get_expected_output_frame_count()
89415     - ma_resampler_get_required_input_frame_count()
89416     - ma_resampler_get_expected_output_frame_count()
89417   - API CHANGE: Update relevant init/uninit functions to take a pointer to allocation callbacks.
89418   - API CHANGE: Remove ma_scale_buffer_size()
89419   - API CHANGE: Update ma_encoder_write_pcm_frames() to return a result code and output the number
89420     of frames written via an output parameter.
89421   - API CHANGE: Update ma_noise_read_pcm_frames() to return a result code and output the number of
89422     frames read via an output parameter.
89423   - API CHANGE: Update ma_waveform_read_pcm_frames() to return a result code and output the number
89424     of frames read via an output parameter.
89425   - API CHANGE: Remove The MA_STATE_* and add ma_device_state_* enums.
89426   - API CHANGE: Rename ma_factor_to_gain_db() to ma_volume_linear_to_db().
89427   - API CHANGE: Rename ma_gain_db_to_factor() to ma_volume_db_to_linear().
89428   - API CHANGE: Rename ma_device_set_master_gain_db() to ma_device_set_master_volume_db().
89429   - API CHANGE: Rename ma_device_get_master_gain_db() to ma_device_get_master_volume_db()
89430
89431 v0.10.43 - 2021-12-10
89432   - ALSA: Fix use of uninitialized variables.
89433   - ALSA: Fix enumeration of devices that support both playback and capture.
89434   - PulseAudio: Fix a possible division by zero.
89435   - WebAudio: Fix errors in strict mode.
89436
89437 v0.10.42 - 2021-08-22
89438   - Fix a possible deadlock when stopping devices.
89439
89440 v0.10.41 - 2021-08-15
89441   - Core Audio: Fix some deadlock errors.
89442
89443 v0.10.40 - 2021-07-23
89444   - Fix a bug when converting from stereo to mono.
89445   - PulseAudio: Fix a glitch when pausing and resuming a device.
89446
89447 v0.10.39 - 2021-07-20
89448   - Core Audio: Fix a deadlock when the default device is changed.
89449   - Core Audio: Fix compilation errors on macOS and iOS.
89450   - PulseAudio: Fix a bug where the stop callback is not fired when a device is unplugged.
89451   - PulseAudio: Fix a null pointer dereference.
89452
89453 v0.10.38 - 2021-07-14
89454   - Fix a linking error when MA_DEBUG_OUTPUT is not enabled.
89455   - Fix an error where ma_log_postv() does not return a value.
89456   - OpenSL: Fix a bug with setting of stream types and recording presets.
89457
89458 0.10.37 - 2021-07-06
89459   - Fix a bug with log message formatting.
89460   - Fix build when compiling with MA_NO_THREADING.
89461   - Minor updates to channel mapping.
89462
89463 0.10.36 - 2021-07-03
89464   - Add support for custom decoding backends.
89465   - Fix some bugs with the Vorbis decoder.
89466   - PulseAudio: Fix a bug with channel mapping.
89467   - PulseAudio: Fix a bug where miniaudio does not fall back to a supported format when PulseAudio
89468     defaults to a format not known to miniaudio.
89469   - OpenSL: Fix a crash when initializing a capture device when a recording preset other than the
89470     default is specified.
89471   - Silence some warnings when compiling with MA_DEBUG_OUTPUT
89472   - Improvements to logging. See the `ma_log` API for details. The logCallback variable used by
89473     ma_context has been deprecated and will be replaced with the new system in version 0.11.
89474     - Initialize an `ma_log` object with `ma_log_init()`.
89475     - Register a callback with `ma_log_register_callback()`.
89476     - In the context config, set `pLog` to your `ma_log` object and stop using `logCallback`.
89477   - Prep work for some upcoming changes to data sources. These changes are still compatible with
89478     existing code, however code will need to be updated in preparation for version 0.11 which will
89479     be breaking. You should make these changes now for any custom data sources:
89480     - Change your base data source object from `ma_data_source_callbacks` to `ma_data_source_base`.
89481     - Call `ma_data_source_init()` for your base object in your custom data source's initialization
89482       routine. This takes a config object which includes a pointer to a vtable which is now where
89483       your custom callbacks are defined.
89484     - Call `ma_data_source_uninit()` in your custom data source's uninitialization routine. This
89485       doesn't currently do anything, but it placeholder in case some future uninitialization code
89486       is required to be added at a later date.
89487
89488 v0.10.35 - 2021-04-27
89489   - Fix the C++ build.
89490
89491 v0.10.34 - 2021-04-26
89492   - WASAPI: Fix a bug where a result code is not getting checked at initialization time.
89493   - WASAPI: Bug fixes for loopback mode.
89494   - ALSA: Fix a possible deadlock when stopping devices.
89495   - Mark devices as default on the null backend.
89496
89497 v0.10.33 - 2021-04-04
89498   - Core Audio: Fix a memory leak.
89499   - Core Audio: Fix a bug where the performance profile is not being used by playback devices.
89500   - JACK: Fix loading of 64-bit JACK on Windows.
89501   - Fix a calculation error and add a safety check to the following APIs to prevent a division by zero:
89502     - ma_calculate_buffer_size_in_milliseconds_from_frames()
89503     - ma_calculate_buffer_size_in_frames_from_milliseconds()
89504   - Fix compilation errors relating to c89atomic.
89505   - Update FLAC decoder.
89506
89507 v0.10.32 - 2021-02-23
89508   - WASAPI: Fix a deadlock in exclusive mode.
89509   - WASAPI: No longer return an error from ma_context_get_device_info() when an exclusive mode format
89510     cannot be retrieved.
89511   - WASAPI: Attempt to fix some bugs with device uninitialization.
89512   - PulseAudio: Yet another refactor, this time to remove the dependency on `pa_threaded_mainloop`.
89513   - Web Audio: Fix a bug on Chrome and any other browser using the same engine.
89514   - Web Audio: Automatically start the device on some user input if the device has been started. This
89515     is to work around Google's policy of not starting audio if no user input has yet been performed.
89516   - Fix a bug where thread handles are not being freed.
89517   - Fix some static analysis warnings in FLAC, WAV and MP3 decoders.
89518   - Fix a warning due to referencing _MSC_VER when it is undefined.
89519   - Update to latest version of c89atomic.
89520   - Internal refactoring to migrate over to the new backend callback system for the following backends:
89521     - PulseAudio
89522     - ALSA
89523     - Core Audio
89524     - AAudio
89525     - OpenSL|ES
89526     - OSS
89527     - audio(4)
89528     - sndio
89529
89530 v0.10.31 - 2021-01-17
89531   - Make some functions const correct.
89532   - Update ma_data_source_read_pcm_frames() to initialize pFramesRead to 0 for safety.
89533   - Add the MA_ATOMIC annotation for use with variables that should be used atomically and remove unnecessary volatile qualifiers.
89534   - Add support for enabling only specific backends at compile time. This is the reverse of the pre-existing system. With the new
89535     system, all backends are first disabled with `MA_ENABLE_ONLY_SPECIFIC_BACKENDS`, which is then followed with `MA_ENABLE_*`. The
89536     old system where you disable backends with `MA_NO_*` still exists and is still the default.
89537
89538 v0.10.30 - 2021-01-10
89539   - Fix a crash in ma_audio_buffer_read_pcm_frames().
89540   - Update spinlock APIs to take a volatile parameter as input.
89541   - Silence some unused parameter warnings.
89542   - Fix a warning on GCC when compiling as C++.
89543
89544 v0.10.29 - 2020-12-26
89545   - Fix some subtle multi-threading bugs on non-x86 platforms.
89546   - Fix a bug resulting in superfluous memory allocations when enumerating devices.
89547   - Core Audio: Fix a compilation error when compiling for iOS.
89548
89549 v0.10.28 - 2020-12-16
89550   - Fix a crash when initializing a POSIX thread.
89551   - OpenSL|ES: Respect the MA_NO_RUNTIME_LINKING option.
89552
89553 v0.10.27 - 2020-12-04
89554   - Add support for dynamically configuring some properties of `ma_noise` objects post-initialization.
89555   - Add support for configuring the channel mixing mode in the device config.
89556   - Fix a bug with simple channel mixing mode (drop or silence excess channels).
89557   - Fix some bugs with trying to access uninitialized variables.
89558   - Fix some errors with stopping devices for synchronous backends where the backend's stop callback would get fired twice.
89559   - Fix a bug in the decoder due to using an uninitialized variable.
89560   - Fix some data race errors.
89561
89562 v0.10.26 - 2020-11-24
89563   - WASAPI: Fix a bug where the exclusive mode format may not be retrieved correctly due to accessing freed memory.
89564   - Fix a bug with ma_waveform where glitching occurs after changing frequency.
89565   - Fix compilation with OpenWatcom.
89566   - Fix compilation with TCC.
89567   - Fix compilation with Digital Mars.
89568   - Fix compilation warnings.
89569   - Remove bitfields from public structures to aid in binding maintenance.
89570
89571 v0.10.25 - 2020-11-15
89572   - PulseAudio: Fix a bug where the stop callback isn't fired.
89573   - WebAudio: Fix an error that occurs when Emscripten increases the size of it's heap.
89574   - Custom Backends: Change the onContextInit and onDeviceInit callbacks to take a parameter which is a pointer to the config that was
89575     passed into ma_context_init() and ma_device_init(). This replaces the deviceType parameter of onDeviceInit.
89576   - Fix compilation warnings on older versions of GCC.
89577
89578 v0.10.24 - 2020-11-10
89579   - Fix a bug where initialization of a backend can fail due to some bad state being set from a prior failed attempt at initializing a
89580     lower priority backend.
89581
89582 v0.10.23 - 2020-11-09
89583   - AAudio: Add support for configuring a playback stream's usage.
89584   - Fix a compilation error when all built-in asynchronous backends are disabled at compile time.
89585   - Fix compilation errors when compiling as C++.
89586
89587 v0.10.22 - 2020-11-08
89588   - Add support for custom backends.
89589   - Add support for detecting default devices during device enumeration and with `ma_context_get_device_info()`.
89590   - Refactor to the PulseAudio backend. This simplifies the implementation and fixes a capture bug.
89591   - ALSA: Fix a bug in `ma_context_get_device_info()` where the PCM handle is left open in the event of an error.
89592   - Core Audio: Further improvements to sample rate selection.
89593   - Core Audio: Fix some bugs with capture mode.
89594   - OpenSL: Add support for configuring stream types and recording presets.
89595   - AAudio: Add support for configuring content types and input presets.
89596   - Fix bugs in `ma_decoder_init_file*()` where the file handle is not closed after a decoding error.
89597   - Fix some compilation warnings on GCC and Clang relating to the Speex resampler.
89598   - Fix a compilation error for the Linux build when the ALSA and JACK backends are both disabled.
89599   - Fix a compilation error for the BSD build.
89600   - Fix some compilation errors on older versions of GCC.
89601   - Add documentation for `MA_NO_RUNTIME_LINKING`.
89602
89603 v0.10.21 - 2020-10-30
89604   - Add ma_is_backend_enabled() and ma_get_enabled_backends() for retrieving enabled backends at run-time.
89605   - WASAPI: Fix a copy and paste bug relating to loopback mode.
89606   - Core Audio: Fix a bug when using multiple contexts.
89607   - Core Audio: Fix a compilation warning.
89608   - Core Audio: Improvements to sample rate selection.
89609   - Core Audio: Improvements to format/channels/rate selection when requesting defaults.
89610   - Core Audio: Add notes regarding the Apple notarization process.
89611   - Fix some bugs due to null pointer dereferences.
89612
89613 v0.10.20 - 2020-10-06
89614   - Fix build errors with UWP.
89615   - Minor documentation updates.
89616
89617 v0.10.19 - 2020-09-22
89618   - WASAPI: Return an error when exclusive mode is requested, but the native format is not supported by miniaudio.
89619   - Fix a bug where ma_decoder_seek_to_pcm_frames() never returns MA_SUCCESS even though it was successful.
89620   - Store the sample rate in the `ma_lpf` and `ma_hpf` structures.
89621
89622 v0.10.18 - 2020-08-30
89623   - Fix build errors with VC6.
89624   - Fix a bug in channel converter for s32 format.
89625   - Change channel converter configs to use the default channel map instead of a blank channel map when no channel map is specified when initializing the
89626     config. This fixes an issue where the optimized mono expansion path would never get used.
89627   - Use a more appropriate default format for FLAC decoders. This will now use ma_format_s16 when the FLAC is encoded as 16-bit.
89628   - Update FLAC decoder.
89629   - Update links to point to the new repository location (https://github.com/mackron/miniaudio).
89630
89631 v0.10.17 - 2020-08-28
89632   - Fix an error where the WAV codec is incorrectly excluded from the build depending on which compile time options are set.
89633   - Fix a bug in ma_audio_buffer_read_pcm_frames() where it isn't returning the correct number of frames processed.
89634   - Fix compilation error on Android.
89635   - Core Audio: Fix a bug with full-duplex mode.
89636   - Add ma_decoder_get_cursor_in_pcm_frames().
89637   - Update WAV codec.
89638
89639 v0.10.16 - 2020-08-14
89640   - WASAPI: Fix a potential crash due to using an uninitialized variable.
89641   - OpenSL: Enable runtime linking.
89642   - OpenSL: Fix a multithreading bug when initializing and uninitializing multiple contexts at the same time.
89643   - iOS: Improvements to device enumeration.
89644   - Fix a crash in ma_data_source_read_pcm_frames() when the output frame count parameter is NULL.
89645   - Fix a bug in ma_data_source_read_pcm_frames() where looping doesn't work.
89646   - Fix some compilation warnings on Windows when both DirectSound and WinMM are disabled.
89647   - Fix some compilation warnings when no decoders are enabled.
89648   - Add ma_audio_buffer_get_available_frames().
89649   - Add ma_decoder_get_available_frames().
89650   - Add sample rate to ma_data_source_get_data_format().
89651   - Change volume APIs to take 64-bit frame counts.
89652   - Updates to documentation.
89653
89654 v0.10.15 - 2020-07-15
89655   - Fix a bug when converting bit-masked channel maps to miniaudio channel maps. This affects the WASAPI and OpenSL backends.
89656
89657 v0.10.14 - 2020-07-14
89658   - Fix compilation errors on Android.
89659   - Fix compilation errors with -march=armv6.
89660   - Updates to the documentation.
89661
89662 v0.10.13 - 2020-07-11
89663   - Fix some potential buffer overflow errors with channel maps when channel counts are greater than MA_MAX_CHANNELS.
89664   - Fix compilation error on Emscripten.
89665   - Silence some unused function warnings.
89666   - Increase the default buffer size on the Web Audio backend. This fixes glitching issues on some browsers.
89667   - Bring FLAC decoder up-to-date with dr_flac.
89668   - Bring MP3 decoder up-to-date with dr_mp3.
89669
89670 v0.10.12 - 2020-07-04
89671   - Fix compilation errors on the iOS build.
89672
89673 v0.10.11 - 2020-06-28
89674   - Fix some bugs with device tracking on Core Audio.
89675   - Updates to documentation.
89676
89677 v0.10.10 - 2020-06-26
89678   - Add include guard for the implementation section.
89679   - Mark ma_device_sink_info_callback() as static.
89680   - Fix compilation errors with MA_NO_DECODING and MA_NO_ENCODING.
89681   - Fix compilation errors with MA_NO_DEVICE_IO
89682
89683 v0.10.9 - 2020-06-24
89684   - Amalgamation of dr_wav, dr_flac and dr_mp3. With this change, including the header section of these libraries before the implementation of miniaudio is no
89685     longer required. Decoding of WAV, FLAC and MP3 should be supported seamlessly without any additional libraries. Decoders can be excluded from the build
89686     with the following options:
89687     - MA_NO_WAV
89688     - MA_NO_FLAC
89689     - MA_NO_MP3
89690     If you get errors about multiple definitions you need to either enable the options above, move the implementation of dr_wav, dr_flac and/or dr_mp3 to before
89691     the implementation of miniaudio, or update dr_wav, dr_flac and/or dr_mp3.
89692   - Changes to the internal atomics library. This has been replaced with c89atomic.h which is embedded within this file.
89693   - Fix a bug when a decoding backend reports configurations outside the limits of miniaudio's decoder abstraction.
89694   - Fix the UWP build.
89695   - Fix the Core Audio build.
89696   - Fix the -std=c89 build on GCC.
89697
89698 v0.10.8 - 2020-06-22
89699   - Remove dependency on ma_context from mutexes.
89700   - Change ma_data_source_read_pcm_frames() to return a result code and output the frames read as an output parameter.
89701   - Change ma_data_source_seek_pcm_frames() to return a result code and output the frames seeked as an output parameter.
89702   - Change ma_audio_buffer_unmap() to return MA_AT_END when the end has been reached. This should be considered successful.
89703   - Change playback.pDeviceID and capture.pDeviceID to constant pointers in ma_device_config.
89704   - Add support for initializing decoders from a virtual file system object. This is achieved via the ma_vfs API and allows the application to customize file
89705     IO for the loading and reading of raw audio data. Passing in NULL for the VFS will use defaults. New APIs:
89706     - ma_decoder_init_vfs()
89707     - ma_decoder_init_vfs_wav()
89708     - ma_decoder_init_vfs_flac()
89709     - ma_decoder_init_vfs_mp3()
89710     - ma_decoder_init_vfs_vorbis()
89711     - ma_decoder_init_vfs_w()
89712     - ma_decoder_init_vfs_wav_w()
89713     - ma_decoder_init_vfs_flac_w()
89714     - ma_decoder_init_vfs_mp3_w()
89715     - ma_decoder_init_vfs_vorbis_w()
89716   - Add support for memory mapping to ma_data_source.
89717     - ma_data_source_map()
89718     - ma_data_source_unmap()
89719   - Add ma_offset_pcm_frames_ptr() and ma_offset_pcm_frames_const_ptr() which can be used for offsetting a pointer by a specified number of PCM frames.
89720   - Add initial implementation of ma_yield() which is useful for spin locks which will be used in some upcoming work.
89721   - Add documentation for log levels.
89722   - The ma_event API has been made public in preparation for some uncoming work.
89723   - Fix a bug in ma_decoder_seek_to_pcm_frame() where the internal sample rate is not being taken into account for determining the seek location.
89724   - Fix some bugs with the linear resampler when dynamically changing the sample rate.
89725   - Fix compilation errors with MA_NO_DEVICE_IO.
89726   - Fix some warnings with GCC and -std=c89.
89727   - Fix some formatting warnings with GCC and -Wall and -Wpedantic.
89728   - Fix some warnings with VC6.
89729   - Minor optimization to ma_copy_pcm_frames(). This is now a no-op when the input and output buffers are the same.
89730
89731 v0.10.7 - 2020-05-25
89732   - Fix a compilation error in the C++ build.
89733   - Silence a warning.
89734
89735 v0.10.6 - 2020-05-24
89736   - Change ma_clip_samples_f32() and ma_clip_pcm_frames_f32() to take a 64-bit sample/frame count.
89737   - Change ma_zero_pcm_frames() to clear to 128 for ma_format_u8.
89738   - Add ma_silence_pcm_frames() which replaces ma_zero_pcm_frames(). ma_zero_pcm_frames() will be removed in version 0.11.
89739   - Add support for u8, s24 and s32 formats to ma_channel_converter.
89740   - Add compile-time and run-time version querying.
89741     - MA_VERSION_MINOR
89742     - MA_VERSION_MAJOR
89743     - MA_VERSION_REVISION
89744     - MA_VERSION_STRING
89745     - ma_version()
89746     - ma_version_string()
89747   - Add ma_audio_buffer for reading raw audio data directly from memory.
89748   - Fix a bug in shuffle mode in ma_channel_converter.
89749   - Fix compilation errors in certain configurations for ALSA and PulseAudio.
89750   - The data callback now initializes the output buffer to 128 when the playback sample format is ma_format_u8.
89751
89752 v0.10.5 - 2020-05-05
89753   - Change ma_zero_pcm_frames() to take a 64-bit frame count.
89754   - Add ma_copy_pcm_frames().
89755   - Add MA_NO_GENERATION build option to exclude the `ma_waveform` and `ma_noise` APIs from the build.
89756   - Add support for formatted logging to the VC6 build.
89757   - Fix a crash in the linear resampler when LPF order is 0.
89758   - Fix compilation errors and warnings with older versions of Visual Studio.
89759   - Minor documentation updates.
89760
89761 v0.10.4 - 2020-04-12
89762   - Fix a data conversion bug when converting from the client format to the native device format.
89763
89764 v0.10.3 - 2020-04-07
89765   - Bring up to date with breaking changes to dr_mp3.
89766   - Remove MA_NO_STDIO. This was causing compilation errors and the maintenance cost versus practical benefit is no longer worthwhile.
89767   - Fix a bug with data conversion where it was unnecessarily converting to s16 or f32 and then straight back to the original format.
89768   - Fix compilation errors and warnings with Visual Studio 2005.
89769   - ALSA: Disable ALSA's automatic data conversion by default and add configuration options to the device config:
89770     - alsa.noAutoFormat
89771     - alsa.noAutoChannels
89772     - alsa.noAutoResample
89773   - WASAPI: Add some overrun recovery for ma_device_type_capture devices.
89774
89775 v0.10.2 - 2020-03-22
89776   - Decorate some APIs with MA_API which were missed in the previous version.
89777   - Fix a bug in ma_linear_resampler_set_rate() and ma_linear_resampler_set_rate_ratio().
89778
89779 v0.10.1 - 2020-03-17
89780   - Add MA_API decoration. This can be customized by defining it before including miniaudio.h.
89781   - Fix a bug where opening a file would return a success code when in fact it failed.
89782   - Fix compilation errors with Visual Studio 6 and 2003.
89783   - Fix warnings on macOS.
89784
89785 v0.10.0 - 2020-03-07
89786   - API CHANGE: Refactor data conversion APIs
89787     - ma_format_converter has been removed. Use ma_convert_pcm_frames_format() instead.
89788     - ma_channel_router has been replaced with ma_channel_converter.
89789     - ma_src has been replaced with ma_resampler
89790     - ma_pcm_converter has been replaced with ma_data_converter
89791   - API CHANGE: Add support for custom memory allocation callbacks. The following APIs have been updated to take an extra parameter for the allocation
89792     callbacks:
89793     - ma_malloc()
89794     - ma_realloc()
89795     - ma_free()
89796     - ma_aligned_malloc()
89797     - ma_aligned_free()
89798     - ma_rb_init() / ma_rb_init_ex()
89799     - ma_pcm_rb_init() / ma_pcm_rb_init_ex()
89800   - API CHANGE: Simplify latency specification in device configurations. The bufferSizeInFrames and bufferSizeInMilliseconds parameters have been replaced with
89801     periodSizeInFrames and periodSizeInMilliseconds respectively. The previous variables defined the size of the entire buffer, whereas the new ones define the
89802     size of a period. The following APIs have been removed since they are no longer relevant:
89803     - ma_get_default_buffer_size_in_milliseconds()
89804     - ma_get_default_buffer_size_in_frames()
89805   - 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
89806     callback.
89807   - API CHANGE: The ma_sine_wave API has been replaced with ma_waveform. The following APIs have been removed:
89808     - ma_sine_wave_init()
89809     - ma_sine_wave_read_f32()
89810     - ma_sine_wave_read_f32_ex()
89811   - 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
89812     reordered.
89813   - 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
89814     convert between.
89815   - API CHANGE: ma_calculate_frame_count_after_src() has been renamed to ma_calculate_frame_count_after_resampling().
89816   - Add support for the following filters:
89817     - Biquad (ma_biquad)
89818     - First order low-pass (ma_lpf1)
89819     - Second order low-pass (ma_lpf2)
89820     - Low-pass with configurable order (ma_lpf)
89821     - First order high-pass (ma_hpf1)
89822     - Second order high-pass (ma_hpf2)
89823     - High-pass with configurable order (ma_hpf)
89824     - Second order band-pass (ma_bpf2)
89825     - Band-pass with configurable order (ma_bpf)
89826     - Second order peaking EQ (ma_peak2)
89827     - Second order notching (ma_notch2)
89828     - Second order low shelf (ma_loshelf2)
89829     - Second order high shelf (ma_hishelf2)
89830   - Add waveform generation API (ma_waveform) with support for the following:
89831     - Sine
89832     - Square
89833     - Triangle
89834     - Sawtooth
89835   - Add noise generation API (ma_noise) with support for the following:
89836     - White
89837     - Pink
89838     - Brownian
89839   - Add encoding API (ma_encoder). This only supports outputting to WAV files via dr_wav.
89840   - Add ma_result_description() which is used to retrieve a human readable description of a given result code.
89841   - Result codes have been changed. Binding maintainers will need to update their result code constants.
89842   - More meaningful result codes are now returned when a file fails to open.
89843   - Internal functions have all been made static where possible.
89844   - Fix potential crash when ma_device object's are not aligned to MA_SIMD_ALIGNMENT.
89845   - 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.
89846   - Fix bugs in some backends where the device is not drained properly in ma_device_stop().
89847   - Improvements to documentation.
89848
89849 v0.9.10 - 2020-01-15
89850   - Fix compilation errors due to #if/#endif mismatches.
89851   - WASAPI: Fix a bug where automatic stream routing is being performed for devices that are initialized with an explicit device ID.
89852   - iOS: Fix a crash on device uninitialization.
89853
89854 v0.9.9 - 2020-01-09
89855   - Fix compilation errors with MinGW.
89856   - Fix compilation errors when compiling on Apple platforms.
89857   - WASAPI: Add support for disabling hardware offloading.
89858   - WASAPI: Add support for disabling automatic stream routing.
89859   - Core Audio: Fix bugs in the case where the internal device uses deinterleaved buffers.
89860   - Core Audio: Add support for controlling the session category (AVAudioSessionCategory) and options (AVAudioSessionCategoryOptions).
89861   - JACK: Fix bug where incorrect ports are connected.
89862
89863 v0.9.8 - 2019-10-07
89864   - WASAPI: Fix a potential deadlock when starting a full-duplex device.
89865   - WASAPI: Enable automatic resampling by default. Disable with config.wasapi.noAutoConvertSRC.
89866   - Core Audio: Fix bugs with automatic stream routing.
89867   - Add support for controlling whether or not the content of the output buffer passed in to the data callback is pre-initialized
89868     to zero. By default it will be initialized to zero, but this can be changed by setting noPreZeroedOutputBuffer in the device
89869     config. Setting noPreZeroedOutputBuffer to true will leave the contents undefined.
89870   - Add support for clipping samples after the data callback has returned. This only applies when the playback sample format is
89871     configured as ma_format_f32. If you are doing clipping yourself, you can disable this overhead by setting noClip to true in
89872     the device config.
89873   - Add support for master volume control for devices.
89874     - 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.
89875     - Use ma_device_set_master_volume_db() to set the volume in decibels where 0 is full volume and < 0 reduces the volume.
89876   - Fix warnings emitted by GCC when `__inline__` is undefined or defined as nothing.
89877
89878 v0.9.7 - 2019-08-28
89879   - Add support for loopback mode (WASAPI only).
89880     - To use this, set the device type to ma_device_type_loopback, and then fill out the capture section of the device config.
89881     - If you need to capture from a specific output device, set the capture device ID to that of a playback device.
89882   - Fix a crash when an error is posted in ma_device_init().
89883   - Fix a compilation error when compiling for ARM architectures.
89884   - Fix a bug with the audio(4) backend where the device is incorrectly being opened in non-blocking mode.
89885   - Fix memory leaks in the Core Audio backend.
89886   - Minor refactoring to the WinMM, ALSA, PulseAudio, OSS, audio(4), sndio and null backends.
89887
89888 v0.9.6 - 2019-08-04
89889   - Add support for loading decoders using a wchar_t string for file paths.
89890   - Don't trigger an assert when ma_device_start() is called on a device that is already started. This will now log a warning
89891     and return MA_INVALID_OPERATION. The same applies for ma_device_stop().
89892   - Try fixing an issue with PulseAudio taking a long time to start playback.
89893   - Fix a bug in ma_convert_frames() and ma_convert_frames_ex().
89894   - Fix memory leaks in the WASAPI backend.
89895   - Fix a compilation error with Visual Studio 2010.
89896
89897 v0.9.5 - 2019-05-21
89898   - Add logging to ma_dlopen() and ma_dlsym().
89899   - Add ma_decoder_get_length_in_pcm_frames().
89900   - Fix a bug with capture on the OpenSL|ES backend.
89901   - Fix a bug with the ALSA backend where a device would not restart after being stopped.
89902
89903 v0.9.4 - 2019-05-06
89904   - Add support for C89. With this change, miniaudio should compile clean with GCC/Clang with "-std=c89 -ansi -pedantic" and
89905     Microsoft compilers back to VC6. Other compilers should also work, but have not been tested.
89906
89907 v0.9.3 - 2019-04-19
89908   - Fix compiler errors on GCC when compiling with -std=c99.
89909
89910 v0.9.2 - 2019-04-08
89911   - Add support for per-context user data.
89912   - Fix a potential bug with context configs.
89913   - Fix some bugs with PulseAudio.
89914
89915 v0.9.1 - 2019-03-17
89916   - Fix a bug where the output buffer is not getting zeroed out before calling the data callback. This happens when
89917     the device is running in passthrough mode (not doing any data conversion).
89918   - Fix an issue where the data callback is getting called too frequently on the WASAPI and DirectSound backends.
89919   - Fix error on the UWP build.
89920   - Fix a build error on Apple platforms.
89921
89922 v0.9 - 2019-03-06
89923   - Rebranded to "miniaudio". All namespaces have been renamed from "mal" to "ma".
89924   - API CHANGE: ma_device_init() and ma_device_config_init() have changed significantly:
89925     - The device type, device ID and user data pointer have moved from ma_device_init() to the config.
89926     - All variations of ma_device_config_init_*() have been removed in favor of just ma_device_config_init().
89927     - ma_device_config_init() now takes only one parameter which is the device type. All other properties need
89928       to be set on the returned object directly.
89929     - The onDataCallback and onStopCallback members of ma_device_config have been renamed to "dataCallback"
89930       and "stopCallback".
89931     - The ID of the physical device is now split into two: one for the playback device and the other for the
89932       capture device. This is required for full-duplex. These are named "pPlaybackDeviceID" and "pCaptureDeviceID".
89933   - API CHANGE: The data callback has changed. It now uses a unified callback for all device types rather than
89934     being separate for each. It now takes two pointers - one containing input data and the other output data. This
89935     design in required for full-duplex. The return value is now void instead of the number of frames written. The
89936     new callback looks like the following:
89937         void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
89938   - API CHANGE: Remove the log callback parameter from ma_context_config_init(). With this change,
89939     ma_context_config_init() now takes no parameters and the log callback is set via the structure directly. The
89940     new policy for config initialization is that only mandatory settings are passed in to *_config_init(). The
89941     "onLog" member of ma_context_config has been renamed to "logCallback".
89942   - API CHANGE: Remove ma_device_get_buffer_size_in_bytes().
89943   - API CHANGE: Rename decoding APIs to "pcm_frames" convention.
89944     - mal_decoder_read()          -> ma_decoder_read_pcm_frames()
89945     - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame()
89946   - API CHANGE: Rename sine wave reading APIs to f32 convention.
89947     - mal_sine_wave_read()    -> ma_sine_wave_read_f32()
89948     - mal_sine_wave_read_ex() -> ma_sine_wave_read_f32_ex()
89949   - API CHANGE: Remove some deprecated APIs
89950     - mal_device_set_recv_callback()
89951     - mal_device_set_send_callback()
89952     - mal_src_set_input_sample_rate()
89953     - mal_src_set_output_sample_rate()
89954   - API CHANGE: Add log level to the log callback. New signature:
89955     - void on_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
89956   - API CHANGE: Changes to result codes. Constants have changed and unused codes have been removed. If you're
89957     a binding mainainer you will need to update your result code constants.
89958   - API CHANGE: Change the order of the ma_backend enums to priority order. If you are a binding maintainer, you
89959     will need to update.
89960   - API CHANGE: Rename mal_dsp to ma_pcm_converter. All functions have been renamed from mal_dsp_*() to
89961     ma_pcm_converter_*(). All structures have been renamed from mal_dsp* to ma_pcm_converter*.
89962   - API CHANGE: Reorder parameters of ma_decoder_read_pcm_frames() to be consistent with the new parameter order scheme.
89963   - The resampling algorithm has been changed from sinc to linear. The rationale for this is that the sinc implementation
89964     is too inefficient right now. This will hopefully be improved at a later date.
89965   - Device initialization will no longer fall back to shared mode if exclusive mode is requested but is unusable.
89966     With this change, if you request an device in exclusive mode, but exclusive mode is not supported, it will not
89967     automatically fall back to shared mode. The client will need to reinitialize the device in shared mode if that's
89968     what they want.
89969   - Add ring buffer API. This is ma_rb and ma_pcm_rb, the difference being that ma_rb operates on bytes and
89970     ma_pcm_rb operates on PCM frames.
89971   - Add Web Audio backend. This is used when compiling with Emscripten. The SDL backend, which was previously
89972     used for web support, will be removed in a future version.
89973   - Add AAudio backend (Android Audio). This is the new priority backend for Android. Support for AAudio starts
89974     with Android 8. OpenSL|ES is used as a fallback for older versions of Android.
89975   - Remove OpenAL and SDL backends.
89976   - Fix a possible deadlock when rapidly stopping the device after it has started.
89977   - Update documentation.
89978   - Change licensing to a choice of public domain _or_ MIT-0 (No Attribution).
89979
89980 v0.8.14 - 2018-12-16
89981   - Core Audio: Fix a bug where the device state is not set correctly after stopping.
89982   - Add support for custom weights to the channel router.
89983   - Update decoders to use updated APIs in dr_flac, dr_mp3 and dr_wav.
89984
89985 v0.8.13 - 2018-12-04
89986   - Core Audio: Fix a bug with channel mapping.
89987   - Fix a bug with channel routing where the back/left and back/right channels have the wrong weight.
89988
89989 v0.8.12 - 2018-11-27
89990   - Drop support for SDL 1.2. The Emscripten build now requires "-s USE_SDL=2".
89991   - Fix a linking error with ALSA.
89992   - Fix a bug on iOS where the device name is not set correctly.
89993
89994 v0.8.11 - 2018-11-21
89995   - iOS bug fixes.
89996   - Minor tweaks to PulseAudio.
89997
89998 v0.8.10 - 2018-10-21
89999   - Core Audio: Fix a hang when uninitializing a device.
90000   - Fix a bug where an incorrect value is returned from mal_device_stop().
90001
90002 v0.8.9 - 2018-09-28
90003   - Fix a bug with the SDL backend where device initialization fails.
90004
90005 v0.8.8 - 2018-09-14
90006   - Fix Linux build with the ALSA backend.
90007   - Minor documentation fix.
90008
90009 v0.8.7 - 2018-09-12
90010   - Fix a bug with UWP detection.
90011
90012 v0.8.6 - 2018-08-26
90013   - Automatically switch the internal device when the default device is unplugged. Note that this is still in the
90014     early stages and not all backends handle this the same way. As of this version, this will not detect a default
90015     device switch when changed from the operating system's audio preferences (unless the backend itself handles
90016     this automatically). This is not supported in exclusive mode.
90017   - WASAPI and Core Audio: Add support for stream routing. When the application is using a default device and the
90018     user switches the default device via the operating system's audio preferences, miniaudio will automatically switch
90019     the internal device to the new default. This is not supported in exclusive mode.
90020   - WASAPI: Add support for hardware offloading via IAudioClient2. Only supported on Windows 8 and newer.
90021   - WASAPI: Add support for low-latency shared mode via IAudioClient3. Only supported on Windows 10 and newer.
90022   - Add support for compiling the UWP build as C.
90023   - mal_device_set_recv_callback() and mal_device_set_send_callback() have been deprecated. You must now set this
90024     when the device is initialized with mal_device_init*(). These will be removed in version 0.9.0.
90025
90026 v0.8.5 - 2018-08-12
90027   - Add support for specifying the size of a device's buffer in milliseconds. You can still set the buffer size in
90028     frames if that suits you. When bufferSizeInFrames is 0, bufferSizeInMilliseconds will be used. If both are non-0
90029     then bufferSizeInFrames will take priority. If both are set to 0 the default buffer size is used.
90030   - Add support for the audio(4) backend to OpenBSD.
90031   - Fix a bug with the ALSA backend that was causing problems on Raspberry Pi. This significantly improves the
90032     Raspberry Pi experience.
90033   - Fix a bug where an incorrect number of samples is returned from sinc resampling.
90034   - Add support for setting the value to be passed to internal calls to CoInitializeEx().
90035   - WASAPI and WinMM: Stop the device when it is unplugged.
90036
90037 v0.8.4 - 2018-08-06
90038   - Add sndio backend for OpenBSD.
90039   - Add audio(4) backend for NetBSD.
90040   - Drop support for the OSS backend on everything except FreeBSD and DragonFly BSD.
90041   - Formats are now native-endian (were previously little-endian).
90042   - Mark some APIs as deprecated:
90043     - mal_src_set_input_sample_rate() and mal_src_set_output_sample_rate() are replaced with mal_src_set_sample_rate().
90044     - mal_dsp_set_input_sample_rate() and mal_dsp_set_output_sample_rate() are replaced with mal_dsp_set_sample_rate().
90045   - Fix a bug when capturing using the WASAPI backend.
90046   - Fix some aliasing issues with resampling, specifically when increasing the sample rate.
90047   - Fix warnings.
90048
90049 v0.8.3 - 2018-07-15
90050   - Fix a crackling bug when resampling in capture mode.
90051   - Core Audio: Fix a bug where capture does not work.
90052   - ALSA: Fix a bug where the worker thread can get stuck in an infinite loop.
90053   - PulseAudio: Fix a bug where mal_context_init() succeeds when PulseAudio is unusable.
90054   - JACK: Fix a bug where mal_context_init() succeeds when JACK is unusable.
90055
90056 v0.8.2 - 2018-07-07
90057   - Fix a bug on macOS with Core Audio where the internal callback is not called.
90058
90059 v0.8.1 - 2018-07-06
90060   - Fix compilation errors and warnings.
90061
90062 v0.8 - 2018-07-05
90063   - Changed MAL_IMPLEMENTATION to MINI_AL_IMPLEMENTATION for consistency with other libraries. The old
90064     way is still supported for now, but you should update as it may be removed in the future.
90065   - API CHANGE: Replace device enumeration APIs. mal_enumerate_devices() has been replaced with
90066     mal_context_get_devices(). An additional low-level device enumration API has been introduced called
90067     mal_context_enumerate_devices() which uses a callback to report devices.
90068   - API CHANGE: Rename mal_get_sample_size_in_bytes() to mal_get_bytes_per_sample() and add
90069     mal_get_bytes_per_frame().
90070   - API CHANGE: Replace mal_device_config.preferExclusiveMode with mal_device_config.shareMode.
90071     - This new config can be set to mal_share_mode_shared (default) or mal_share_mode_exclusive.
90072   - API CHANGE: Remove excludeNullDevice from mal_context_config.alsa.
90073   - API CHANGE: Rename MAL_MAX_SAMPLE_SIZE_IN_BYTES to MAL_MAX_PCM_SAMPLE_SIZE_IN_BYTES.
90074   - API CHANGE: Change the default channel mapping to the standard Microsoft mapping.
90075   - API CHANGE: Remove backend-specific result codes.
90076   - API CHANGE: Changes to the format conversion APIs (mal_pcm_f32_to_s16(), etc.)
90077   - Add support for Core Audio (Apple).
90078   - Add support for PulseAudio.
90079     - This is the highest priority backend on Linux (higher priority than ALSA) since it is commonly
90080       installed by default on many of the popular distros and offer's more seamless integration on
90081       platforms where PulseAudio is used. In addition, if PulseAudio is installed and running (which
90082       is extremely common), it's better to just use PulseAudio directly rather than going through the
90083       "pulse" ALSA plugin (which is what the "default" ALSA device is likely set to).
90084   - Add support for JACK.
90085   - Remove dependency on asound.h for the ALSA backend. This means the ALSA development packages are no
90086     longer required to build miniaudio.
90087   - Remove dependency on dsound.h for the DirectSound backend. This fixes build issues with some
90088     distributions of MinGW.
90089   - Remove dependency on audioclient.h for the WASAPI backend. This fixes build issues with some
90090     distributions of MinGW.
90091   - Add support for dithering to format conversion.
90092   - Add support for configuring the priority of the worker thread.
90093   - Add a sine wave generator.
90094   - Improve efficiency of sample rate conversion.
90095   - Introduce the notion of standard channel maps. Use mal_get_standard_channel_map().
90096   - Introduce the notion of default device configurations. A default config uses the same configuration
90097     as the backend's internal device, and as such results in a pass-through data transmission pipeline.
90098   - Add support for passing in NULL for the device config in mal_device_init(), which uses a default
90099     config. This requires manually calling mal_device_set_send/recv_callback().
90100   - Add support for decoding from raw PCM data (mal_decoder_init_raw(), etc.)
90101   - Make mal_device_init_ex() more robust.
90102   - Make some APIs more const-correct.
90103   - Fix errors with SDL detection on Apple platforms.
90104   - Fix errors with OpenAL detection.
90105   - Fix some memory leaks.
90106   - Fix a bug with opening decoders from memory.
90107   - Early work on SSE2, AVX2 and NEON optimizations.
90108   - Miscellaneous bug fixes.
90109   - Documentation updates.
90110
90111 v0.7 - 2018-02-25
90112   - API CHANGE: Change mal_src_read_frames() and mal_dsp_read_frames() to use 64-bit sample counts.
90113   - Add decoder APIs for loading WAV, FLAC, Vorbis and MP3 files.
90114   - Allow opening of devices without a context.
90115     - In this case the context is created and managed internally by the device.
90116   - Change the default channel mapping to the same as that used by FLAC.
90117   - Fix build errors with macOS.
90118
90119 v0.6c - 2018-02-12
90120   - Fix build errors with BSD/OSS.
90121
90122 v0.6b - 2018-02-03
90123   - Fix some warnings when compiling with Visual C++.
90124
90125 v0.6a - 2018-01-26
90126   - Fix errors with channel mixing when increasing the channel count.
90127   - Improvements to the build system for the OpenAL backend.
90128   - Documentation fixes.
90129
90130 v0.6 - 2017-12-08
90131   - API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll
90132     need to update.
90133   - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively.
90134   - API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent.
90135   - Add support for SDL and Emscripten.
90136   - Simplify the build system further for when development packages for various backends are not installed.
90137     With this change, when the compiler supports __has_include, backends without the relevant development
90138     packages installed will be ignored. This fixes the build for old versions of MinGW.
90139   - Fixes to the Android build.
90140   - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of
90141     audio data to a different format.
90142   - Improvements to f32 -> u8/s16/s24/s32 conversion routines.
90143   - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL backend.
90144   - Fixes and improvements for Raspberry Pi.
90145   - Warning fixes.
90146
90147 v0.5 - 2017-11-11
90148   - API CHANGE: The mal_context_init() function now takes a pointer to a mal_context_config object for
90149     configuring the context. The works in the same kind of way as the device config. The rationale for this
90150     change is to give applications better control over context-level properties, add support for backend-
90151     specific configurations, and support extensibility without breaking the API.
90152   - API CHANGE: The alsa.preferPlugHW device config variable has been removed since it's not really useful for
90153     anything anymore.
90154   - ALSA: By default, device enumeration will now only enumerate over unique card/device pairs. Applications
90155     can enable verbose device enumeration by setting the alsa.useVerboseDeviceEnumeration context config
90156     variable.
90157   - ALSA: When opening a device in shared mode (the default), the dmix/dsnoop plugin will be prioritized. If
90158     this fails it will fall back to the hw plugin. With this change the preferExclusiveMode config is now
90159     honored. Note that this does not happen when alsa.useVerboseDeviceEnumeration is set to true (see above)
90160     which is by design.
90161   - ALSA: Add support for excluding the "null" device using the alsa.excludeNullDevice context config variable.
90162   - ALSA: Fix a bug with channel mapping which causes an assertion to fail.
90163   - Fix errors with enumeration when pInfo is set to NULL.
90164   - OSS: Fix a bug when starting a device when the client sends 0 samples for the initial buffer fill.
90165
90166 v0.4 - 2017-11-05
90167   - API CHANGE: The log callback is now per-context rather than per-device and as is thus now passed to
90168     mal_context_init(). The rationale for this change is that it allows applications to capture diagnostic
90169     messages at the context level. Previously this was only available at the device level.
90170   - API CHANGE: The device config passed to mal_device_init() is now const.
90171   - Added support for OSS which enables support on BSD platforms.
90172   - Added support for WinMM (waveOut/waveIn).
90173   - Added support for UWP (Universal Windows Platform) applications. Currently C++ only.
90174   - Added support for exclusive mode for selected backends. Currently supported on WASAPI.
90175   - POSIX builds no longer require explicit linking to libpthread (-lpthread).
90176   - ALSA: Explicit linking to libasound (-lasound) is no longer required.
90177   - ALSA: Latency improvements.
90178   - ALSA: Use MMAP mode where available. This can be disabled with the alsa.noMMap config.
90179   - ALSA: Use "hw" devices instead of "plughw" devices by default. This can be disabled with the
90180     alsa.preferPlugHW config.
90181   - WASAPI is now the highest priority backend on Windows platforms.
90182   - Fixed an error with sample rate conversion which was causing crackling when capturing.
90183   - Improved error handling.
90184   - Improved compiler support.
90185   - Miscellaneous bug fixes.
90186
90187 v0.3 - 2017-06-19
90188   - API CHANGE: Introduced the notion of a context. The context is the highest level object and is required for
90189     enumerating and creating devices. Now, applications must first create a context, and then use that to
90190     enumerate and create devices. The reason for this change is to ensure device enumeration and creation is
90191     tied to the same backend. In addition, some backends are better suited to this design.
90192   - API CHANGE: Removed the rewinding APIs because they're too inconsistent across the different backends, hard
90193     to test and maintain, and just generally unreliable.
90194   - Added helper APIs for initializing mal_device_config objects.
90195   - Null Backend: Fixed a crash when recording.
90196   - Fixed build for UWP.
90197   - Added support for f32 formats to the OpenSL|ES backend.
90198   - Added initial implementation of the WASAPI backend.
90199   - Added initial implementation of the OpenAL backend.
90200   - Added support for low quality linear sample rate conversion.
90201   - Added early support for basic channel mapping.
90202
90203 v0.2 - 2016-10-28
90204   - API CHANGE: Add user data pointer as the last parameter to mal_device_init(). The rationale for this
90205     change is to ensure the logging callback has access to the user data during initialization.
90206   - API CHANGE: Have device configuration properties be passed to mal_device_init() via a structure. Rationale:
90207     1) The number of parameters is just getting too much.
90208     2) It makes it a bit easier to add new configuration properties in the future. In particular, there's a
90209        chance there will be support added for backend-specific properties.
90210   - Dropped support for f64, A-law and Mu-law formats since they just aren't common enough to justify the
90211     added maintenance cost.
90212   - DirectSound: Increased the default buffer size for capture devices.
90213   - Added initial implementation of the OpenSL|ES backend.
90214
90215 v0.1 - 2016-10-21
90216   - Initial versioned release.
90217 */
90218
90219
90220 /*
90221 This software is available as a choice of the following licenses. Choose
90222 whichever you prefer.
90223
90224 ===============================================================================
90225 ALTERNATIVE 1 - Public Domain (www.unlicense.org)
90226 ===============================================================================
90227 This is free and unencumbered software released into the public domain.
90228
90229 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
90230 software, either in source code form or as a compiled binary, for any purpose,
90231 commercial or non-commercial, and by any means.
90232
90233 In jurisdictions that recognize copyright laws, the author or authors of this
90234 software dedicate any and all copyright interest in the software to the public
90235 domain. We make this dedication for the benefit of the public at large and to
90236 the detriment of our heirs and successors. We intend this dedication to be an
90237 overt act of relinquishment in perpetuity of all present and future rights to
90238 this software under copyright law.
90239
90240 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
90241 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
90242 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
90243 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
90244 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
90245 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
90246
90247 For more information, please refer to <http://unlicense.org/>
90248
90249 ===============================================================================
90250 ALTERNATIVE 2 - MIT No Attribution
90251 ===============================================================================
90252 Copyright 2020 David Reid
90253
90254 Permission is hereby granted, free of charge, to any person obtaining a copy of
90255 this software and associated documentation files (the "Software"), to deal in
90256 the Software without restriction, including without limitation the rights to
90257 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
90258 of the Software, and to permit persons to whom the Software is furnished to do
90259 so.
90260
90261 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
90262 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
90263 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
90264 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
90265 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
90266 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
90267 SOFTWARE.
90268 */